github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/web/middlewares/json_headers.go (about) 1 package middlewares 2 3 import ( 4 "net/http" 5 "strings" 6 7 "github.com/cozy/cozy-stack/pkg/jsonapi" 8 "github.com/labstack/echo/v4" 9 10 "github.com/golang/gddo/httputil" 11 ) 12 13 const ( 14 defaultContentTypeOffer = jsonapi.ContentType 15 acceptContentTypeKey = "offer-content-type" 16 ) 17 18 var contentTypeOffers = []string{ 19 jsonapi.ContentType, 20 echo.MIMEApplicationJSON, 21 echo.MIMETextHTML, 22 echo.MIMETextPlain, 23 } 24 25 // AcceptOptions can be used to parameterize the the Accept middleware: the 26 // default content-type in case no offer is accepted, and the list of offers to 27 // select from. 28 type AcceptOptions struct { 29 DefaultContentTypeOffer string 30 Offers []string 31 } 32 33 // AcceptJSON is an echo middleware that checks that the HTTP Accept header 34 // is compatible with application/json 35 func AcceptJSON(next echo.HandlerFunc) echo.HandlerFunc { 36 return func(c echo.Context) error { 37 accept := c.Request().Header.Get(echo.HeaderAccept) 38 if accept == "*/*" || strings.Contains(accept, echo.MIMEApplicationJSON) { 39 return next(c) 40 } 41 return c.JSON(http.StatusBadRequest, echo.Map{ 42 "error": "bad_accept_header", 43 }) 44 } 45 } 46 47 // ContentTypeJSON is an echo middleware that checks that the HTTP Content-Type 48 // header is compatible with application/json 49 func ContentTypeJSON(next echo.HandlerFunc) echo.HandlerFunc { 50 return func(c echo.Context) error { 51 contentType := c.Request().Header.Get(echo.HeaderContentType) 52 if strings.HasPrefix(contentType, echo.MIMEApplicationJSON) { 53 return next(c) 54 } 55 return c.JSON(http.StatusBadRequest, echo.Map{ 56 "error": "bad_content_type", 57 }) 58 } 59 } 60 61 // Accept is a middleware resolving the better content-type offering for the 62 // HTTP request, given the `Accept` header and the middleware options. 63 func Accept(args ...AcceptOptions) echo.MiddlewareFunc { 64 var opts AcceptOptions 65 if len(args) > 0 { 66 opts = args[0] 67 } 68 if opts.DefaultContentTypeOffer == "" { 69 opts.DefaultContentTypeOffer = defaultContentTypeOffer 70 } 71 if opts.Offers == nil { 72 opts.Offers = contentTypeOffers 73 } 74 return func(next echo.HandlerFunc) echo.HandlerFunc { 75 return func(c echo.Context) error { 76 contentTypeOffer := httputil.NegotiateContentType(c.Request(), opts.Offers, opts.DefaultContentTypeOffer) 77 c.Set(acceptContentTypeKey, contentTypeOffer) 78 return next(c) 79 } 80 } 81 } 82 83 // AcceptedContentType returns the accepted content-type store from the Accept 84 // middleware. 85 func AcceptedContentType(c echo.Context) string { 86 return c.Get(acceptContentTypeKey).(string) 87 }