Skip to content

Commit

Permalink
Implement RFC 9110, generate less server code (#34)
Browse files Browse the repository at this point in the history
* Prepare changes in generated code

* Remove one server method generated per each RPC method

* Implement RFC 9110: Respond with Allow header on HTTP 405

* Switch case on request path to choose the JSON handler
  • Loading branch information
VojtechVitek authored Aug 24, 2023
1 parent 55ba4f5 commit 45007cb
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 161 deletions.
107 changes: 19 additions & 88 deletions _examples/golang-basics/example.gen.go

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

70 changes: 16 additions & 54 deletions _examples/golang-imports/api.gen.go

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

36 changes: 17 additions & 19 deletions server.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -32,41 +32,39 @@ func (s *{{$serviceName}}) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx = context.WithValue(ctx, HTTPRequestCtxKey, r)
ctx = context.WithValue(ctx, ServiceNameCtxKey, "{{.Name}}")

if r.Method != "POST" {
err := ErrorWithCause(ErrWebrpcBadMethod, fmt.Errorf("unsupported method %q (only POST is allowed)", r.Method))
RespondWithError(w, err)
return
}

var handler func(ctx context.Context, w http.ResponseWriter, r *http.Request)
switch r.URL.Path {
{{- range .Methods}}
case "/rpc/{{$name}}/{{.Name}}":
s.serve{{.Name | firstLetterToUpper}}(ctx, w, r)
return
case "/rpc/{{$name}}/{{.Name}}": handler = s.serve{{.Name | firstLetterToUpper}}JSON
{{- end}}
default:
err := ErrorWithCause(ErrWebrpcBadRoute, fmt.Errorf("no handler for path %q", r.URL.Path))
RespondWithError(w, err)
return
}
}
{{range .Methods }}
func (s *{{$serviceName}}) serve{{.Name | firstLetterToUpper}}(ctx context.Context, w http.ResponseWriter, r *http.Request) {
header := r.Header.Get("Content-Type")
i := strings.Index(header, ";")
if i == -1 {
i = len(header)

if r.Method != "POST" {
w.Header().Add("Allow", "POST") // RFC 9110.
err := ErrorWithCause(ErrWebrpcBadMethod, fmt.Errorf("unsupported method %q (only POST is allowed)", r.Method))
RespondWithError(w, err)
return
}

switch strings.TrimSpace(strings.ToLower(header[:i])) {
contentType := r.Header.Get("Content-Type")
if i := strings.Index(contentType, ";"); i >= 0 {
contentType = contentType[:i]
}
contentType = strings.TrimSpace(strings.ToLower(contentType))

switch contentType {
case "application/json":
s.serve{{ .Name | firstLetterToUpper }}JSON(ctx, w, r)
handler(ctx, w, r)
default:
err := ErrorWithCause(ErrWebrpcBadRequest, fmt.Errorf("unexpected Content-Type: %q", r.Header.Get("Content-Type")))
RespondWithError(w, err)
}
}

{{range .Methods }}
func (s *{{$serviceName}}) serve{{ .Name | firstLetterToUpper }}JSON(ctx context.Context, w http.ResponseWriter, r *http.Request) {
var err error
ctx = context.WithValue(ctx, MethodNameCtxKey, "{{.Name}}")
Expand Down

0 comments on commit 45007cb

Please sign in to comment.