summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Magnusson <mathias@magnusson.space>2026-01-24 01:57:33 +0100
committerMathias Magnusson <mathias@magnusson.space>2026-01-24 01:57:33 +0100
commit39c6170ccab2977bbbaecdde2fdff772f39e2415 (patch)
tree97d1d360e8ce62517a573380c0c03362915e55e8
parent1fe804770391a644e23eea7c22e0868e3dfb4d2e (diff)
downloadhh-main.tar.gz
allow returning values from handlersHEADmain
-rw-r--r--cmd/generate/main.go24
-rw-r--r--cmd/generate/templates.go.tmpl24
-rw-r--r--examples/basic.go25
-rw-r--r--hh.go17
4 files changed, 87 insertions, 3 deletions
diff --git a/cmd/generate/main.go b/cmd/generate/main.go
index eddd4cb..f846012 100644
--- a/cmd/generate/main.go
+++ b/cmd/generate/main.go
@@ -39,8 +39,10 @@ type Function struct {
Name string
Pattern string
RequestTypeDef string
- RequestTypeFields []RequestTypeField
DoParseForm bool
+ RequestTypeFields []RequestTypeField
+ ResponseHasError bool
+ ResponseHasMain bool
}
type RequestTypeField struct {
@@ -161,7 +163,7 @@ func run() error {
}
}
if winner == "" {
- panic("Counld not find import for " + parsedField.TypeDef)
+ panic("Could not find import for " + parsedField.TypeDef)
}
parsedPackage.Imports = append(
slices.DeleteFunc(parsedPackage.Imports, func(i string) bool { return i == winner }),
@@ -208,6 +210,24 @@ func run() error {
parsedFunction.RequestTypeFields = append(parsedFunction.RequestTypeFields, parsedField)
}
}
+ if f.Type.Results == nil {
+ //
+ } else if len(f.Type.Results.List) == 1 {
+ switch typ := f.Type.Results.List[0].Type.(type) {
+ case *ast.Ident:
+ if typ.Name == "error" {
+ parsedFunction.ResponseHasError = true
+ }
+ }
+ if !parsedFunction.ResponseHasError {
+ parsedFunction.ResponseHasMain = true
+ }
+ } else if len(f.Type.Results.List) == 2 {
+ parsedFunction.ResponseHasError = true
+ parsedFunction.ResponseHasMain = true
+ } else if len(f.Type.Results.List) > 2 {
+ return errors.New("Too many return values. Max two allowed")
+ }
parsedPackage.Functions = append(parsedPackage.Functions, parsedFunction)
}
}
diff --git a/cmd/generate/templates.go.tmpl b/cmd/generate/templates.go.tmpl
index 3533b2b..9ee259b 100644
--- a/cmd/generate/templates.go.tmpl
+++ b/cmd/generate/templates.go.tmpl
@@ -66,6 +66,28 @@ func hh_{{ $fn.Name }}(w http.ResponseWriter, r *http.Request) {
}
}
{{ end }}
- {{ $fn.Name }}(parsed)
+ {{ if $fn.ResponseHasMain -}}
+ res
+ {{- end -}}
+ {{- if and $fn.ResponseHasMain $fn.ResponseHasError -}}
+ ,
+ {{- end -}}
+ {{- if $fn.ResponseHasError -}}
+ err
+ {{- end -}}
+ {{- if or $fn.ResponseHasMain $fn.ResponseHasError -}}
+ :=
+ {{- end -}}
+ {{- $fn.Name }}(parsed)
+
+ {{ if $fn.ResponseHasError }}
+ if err != nil {
+ panic("todo: Internal server error in " + {{ $fn.Name | quote }} + ": " + err.Error())
+ // return
+ }
+ {{ end }}
+ {{ if $fn.ResponseHasMain -}}
+ res.Respond(w, r)
+ {{- end -}}
}
{{ end }}
diff --git a/examples/basic.go b/examples/basic.go
index d8ad6d7..5986e7e 100644
--- a/examples/basic.go
+++ b/examples/basic.go
@@ -1,9 +1,11 @@
package main
import (
+ "errors"
"log/slog"
"net/http"
+ "git.0m.nu/hh"
"github.com/google/uuid"
)
@@ -26,6 +28,29 @@ func adminUsersForm(r struct {
slog.Info("get admin users form", "search", r.search, "offset", r.offset, "next-url", r.nextURL)
}
+//hh:route GET /return-err
+func returnErr(r struct{ raw *http.Request }) error {
+ _ = r
+ return errors.New("whoops")
+}
+
+//hh:route GET /return-value
+func returnValue(r struct{ raw *http.Request }) hh.JSONValue {
+ _ = r
+ return hh.JSON(map[string]any{"key": []string{"value", "s"}})
+}
+
+//hh:route GET /return-both/{which}
+func returnBoth(r struct {
+ which string `hh:"path"`
+}) (hh.JSONValue, error) {
+ if r.which == "error" {
+ return hh.JSON(nil), errors.New("whoops")
+ } else {
+ return hh.JSON(map[string]any{"key": []string{"value", "s"}}), nil
+ }
+}
+
func main() {
hhMountRoutes(nil)
slog.Error("Error listening", "error", http.ListenAndServe(":http", nil))
diff --git a/hh.go b/hh.go
index 84df871..a8b7cd4 100644
--- a/hh.go
+++ b/hh.go
@@ -1,6 +1,7 @@
package hh
import (
+ "encoding/json"
"net/http"
"strconv"
@@ -42,3 +43,19 @@ func ConvertToString(value string) (string, error) {
func ConvertToUuidUUID(value string) (uuid.UUID, error) {
return uuid.Parse(value)
}
+
+type ToResponse interface {
+ Respond(w http.ResponseWriter, r *http.Request)
+}
+
+func JSON(a any) JSONValue {
+ return JSONValue{a}
+}
+
+type JSONValue struct{ any }
+
+func (j JSONValue) Respond(w http.ResponseWriter, r *http.Request) {
+ if err := json.NewEncoder(w).Encode(j); err != nil {
+ panic("todo: internal server error: " + err.Error())
+ }
+}