Go's net/http router is updated but it doesn't provide a way to easily manage 404 Not Found and 405 Method Not Allowed for JSON APIs. For instance, JSON response header and body. Here is an example how you can accomplish it yourself. What it does is simple. Custom middleware intercepts the response, overrides it and writes it. You can extend it as you wish.


package main

import (
"net/http"
)

func main() {
rtr := http.NewServeMux()
rtr.HandleFunc("GET /v1", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`GET /v1`)) })
rtr.HandleFunc("POST /v1", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`POST /v1`)) })
rtr.HandleFunc("GET /v1/users", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`GET /v1/users`)) })
rtr.HandleFunc("POST /v1/users", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`POST /v1/users`)) })
rtr.HandleFunc("POST /v1/{channel}/users", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`POST /v1/{channel}/users`)) })

http.ListenAndServe(":8888", InterceptResponse(rtr))
}

func InterceptResponse(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
h.ServeHTTP(&OverrideResponse{ResponseWriter: w}, r)
})
}

type OverrideResponse struct {
http.ResponseWriter

status int
override bool
}

func (o *OverrideResponse) WriteHeader(status int) {
if o.Header().Get("Content-Type") == "text/plain; charset=utf-8" {
o.Header().Set("Content-Type", "application/json; charset=utf-8")

o.override = true
}

o.status = status
o.ResponseWriter.WriteHeader(status)
}

func (o *OverrideResponse) Write(body []byte) (int, error) {
if o.override {
switch o.status {
case http.StatusNotFound:
body = []byte(`{"code": "route_not_found"}`)
case http.StatusMethodNotAllowed:
body = []byte(`{"code": "method_not_allowed"}`)
}
}

return o.ResponseWriter.Write(body)
}

Test


PUT http://localhost:8888/v1/users

HTTP/1.1 405 Method Not Allowed
Content-Type: application/json; charset=utf-8

{"code": "method_not_allowed"}

PUT http://localhost:8888/v1/posts

HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8

{"code": "route_not_found"}