Skip to content

Commit

Permalink
feat: support decoding query parameters into pointers
Browse files Browse the repository at this point in the history
Also fix incorrect error message and bad reference to "matches".
  • Loading branch information
alecthomas committed Feb 6, 2023
1 parent e4c5608 commit 1da7200
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 17 deletions.
29 changes: 18 additions & 11 deletions cmd/happy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,24 +351,31 @@ func genQueryDecoderFunc(gctx *genContext, paramType types.Type) (name string, e
w = w.Push()
for i := 0; i < strct.NumFields(); i++ {
field := strct.Field(i)
fieldName := lcFirst(strings.ReplaceAll(field.Name(), ".", ""))
fieldName := lcFirst(field.Name())
w.L("if q, ok := p[%q]; ok {", fieldName)
w = w.Push()
switch field.Type().String() {
fieldType := field.Type()
strctRef := "out"
if _, ptr := fieldType.(*types.Pointer); ptr {
fieldType = fieldType.(*types.Pointer).Elem()
w.L("out.%s = new(%s)", field.Name(), fieldType)
strctRef = "*" + strctRef
}
switch fieldType.String() {
case "bool":
gctx.Import("strconv")
w.L("if out.%s, err = strconv.ParseBool(q[len(q)-1]); err != nil {", field.Name())
w.L(` return fmt.Errorf("failed to decode query parameter \"%s\" as %s: %%w", err)`, fieldName, field.Type())
w.L("if %s.%s, err = strconv.ParseBool(q[len(q)-1]); err != nil {", strctRef, field.Name())
w.L(` return fmt.Errorf("failed to decode query parameter \"%s\" as %s: %%w", err)`, fieldName, fieldType)
w.L("}")
case "int":
gctx.Import("strconv")
w.L("if out.%s, err = strconv.Atoi(q[len(q)-1]); err != nil {", field.Name())
w.L(` return fmt.Errorf("failed to decode query parameter \"%s\" as %s: %%w", err)`, fieldName, field.Type())
w.L("if %s.%s, err = strconv.Atoi(q[len(q)-1]); err != nil {", strctRef, field.Name())
w.L(` return fmt.Errorf("failed to decode query parameter \"%s\" as %s: %%w", err)`, fieldName, fieldType)
w.L("}")
case "string":
w.L("out.%s = q[len(q)-1]", field.Name())
w.L("%s.%s = q[len(q)-1]", strctRef, field.Name())
default:
return "", fmt.Errorf("can't decode query parameter into field %s.%s of type %s", paramType, field.Name(), field.Type())
return "", fmt.Errorf("can't decode query parameter into field %s.%s of type %s, only int, string and bool are supported", paramType, field.Name(), field.Type())
}
w = w.Pop()
w.L("}")
Expand Down Expand Up @@ -465,9 +472,9 @@ func genEndpoint(gctx *genContext, w *codewriter.Writer, ep endpoint) error {

case bt == "string":
if bt != ref {
args = append(args, fmt.Sprintf("%s(matches[%d])", ref, index))
args = append(args, fmt.Sprintf("%s(params[%d])", ref, index))
} else {
args = append(args, fmt.Sprintf("matches[%d]", index))
args = append(args, fmt.Sprintf("params[%d]", index))
}

case bt == "int":
Expand Down Expand Up @@ -505,7 +512,7 @@ func genEndpoint(gctx *genContext, w *codewriter.Writer, ep endpoint) error {
return fmt.Errorf("%s: %w", pos, err)
}
w.L("if err := %s(r.URL.Query(), &param%d); err != nil {", decoderFn, i)
w.L(` http.Error(w, fmt.Sprintf("Failed to decode query parameters: %s", err), http.StatusBadRequest)`)
w.L(` http.Error(w, fmt.Sprintf("Failed to decode query parameters: %%s", err), http.StatusBadRequest)`)
w.L(" return")
w.L("}")
} else {
Expand Down
2 changes: 1 addition & 1 deletion testdata/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func (s *Service) CreateUser(r *http.Request, user User) error {
type Paginate struct {
Page int
Size int
Sparse bool
Sparse *bool
}

//happy:api GET /users
Expand Down
11 changes: 6 additions & 5 deletions testdata/main_api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 1da7200

Please sign in to comment.