diff options
Diffstat (limited to 'echo/controller/content_type_negotiator.go')
-rw-r--r-- | echo/controller/content_type_negotiator.go | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/echo/controller/content_type_negotiator.go b/echo/controller/content_type_negotiator.go new file mode 100644 index 0000000..273a118 --- /dev/null +++ b/echo/controller/content_type_negotiator.go | |||
@@ -0,0 +1,59 @@ | |||
1 | package controller | ||
2 | |||
3 | import ( | ||
4 | "errors" | ||
5 | "net/http" | ||
6 | "sync" | ||
7 | |||
8 | "github.com/elnormous/contenttype" | ||
9 | "github.com/labstack/echo/v4" | ||
10 | ) | ||
11 | |||
12 | type ContentTypeNegotiatingHandler struct { | ||
13 | Handlers map[string]echo.HandlerFunc | ||
14 | DefaultHandler echo.HandlerFunc | ||
15 | mediaTypes []contenttype.MediaType | ||
16 | once sync.Once | ||
17 | } | ||
18 | |||
19 | func errorIsNotAcceptable(err error) bool { | ||
20 | return errors.Is(err, contenttype.ErrNoAcceptableTypeFound) || | ||
21 | errors.Is(err, contenttype.ErrNoAvailableTypeGiven) | ||
22 | } | ||
23 | |||
24 | func errorIsBadRequest(err error) bool { | ||
25 | return errors.Is(err, contenttype.ErrInvalidMediaType) || | ||
26 | errors.Is(err, contenttype.ErrInvalidMediaRange) || | ||
27 | errors.Is(err, contenttype.ErrInvalidParameter) || | ||
28 | errors.Is(err, contenttype.ErrInvalidExtensionParameter) || | ||
29 | errors.Is(err, contenttype.ErrInvalidWeight) | ||
30 | } | ||
31 | |||
32 | func (h *ContentTypeNegotiatingHandler) Handle(c echo.Context) error { | ||
33 | h.once.Do(func() { | ||
34 | h.mediaTypes = []contenttype.MediaType{} | ||
35 | for k, _ := range h.Handlers { | ||
36 | h.mediaTypes = append(h.mediaTypes, contenttype.NewMediaType(k)) | ||
37 | } | ||
38 | }) | ||
39 | |||
40 | handler := h.DefaultHandler | ||
41 | ct, _, err := contenttype.GetAcceptableMediaType(c.Request(), h.mediaTypes) | ||
42 | if err == nil { | ||
43 | handler = h.Handlers[ct.String()] | ||
44 | } else if errorIsNotAcceptable(err) { | ||
45 | return echo.NewHTTPError(http.StatusNotAcceptable) | ||
46 | } else if errorIsBadRequest(err) { | ||
47 | return echo.NewHTTPError(http.StatusBadRequest) | ||
48 | } | ||
49 | |||
50 | // If negotiation failed but it wasn't an error and there is no default | ||
51 | // handler then the request is still not acceptable | ||
52 | if handler == nil { | ||
53 | return echo.NewHTTPError(http.StatusNotAcceptable) | ||
54 | } | ||
55 | |||
56 | // Don't force each handler to do this itself to eliminate redundant code | ||
57 | c.Response().Header().Set("Content-Type", ct.String()) | ||
58 | return handler(c) | ||
59 | } | ||