-
Notifications
You must be signed in to change notification settings - Fork 146
Endpoints
-
GET,POST,PUT,HEAD,PATCH,DELETE,OPTIONSandANY
Compojure-api has it's own versions of Compojure http endpoint macros in compojure.api.core (and also in compojure.api.sweet). They can be used just like the originals, but they also support the compojure-api restructuring syntax.
(require '[compojure.api.sweet :refer :all])
(require '[ring.util.http-response :refer :all])
;; vanilla compojure app
(def app
(GET "/ping" []
(ok {:ping "pong"})))
(app {:request-method :get, :uri "/ping"})
; => {:status 200, :headers {}, :body {:ping "pong"}}-
routescan be used to group routes together (match-first) -
contextallows routes to be grouped under a common path prefix
(def app
(routes
(GET "/ping" []
(ok {:ping "pong"}))
(context "/api" []
(GET "/kikka" []
(ok {:kikka true}))
(POST "/kukka" []
(ok {:kukka true})))))
(app {:request-method :get, :uri "/ping"})
; {:status 200, :headers {}, :body {:ping "pong"}}
(app {:request-method :get, :uri "/api/kikka"})
; {:status 200, :headers {}, :body {:kikka true}}
(app {:request-method :post, :uri "/api/kukka"})
; {:status 200, :headers {}, :body {:kukka true}}Both context and all endpoint macros can have a extra restructuring map (or pairs of keyword key + value) after the 3 compojure-params before the actual body of a handler function. Restructuring is applied at macro-expansion time, enabling new code to be emitted into the handler. A multimethod compojure.api.meta/restructure-param is used as restructuring key dispatch. Compojure-api ships with a set of predefined resturcture dispatch keys, for things like validation, api-docs and more.
;; keys & vals
(GET "/ping" []
:summary "this is a ping endpoint"
(ok {:ping "pong"}))
;; as map
(GET "/ping" []
{:summary "this is a ping endpoint"}
(ok {:ping "pong"}))A more useful example, with typed & automatically coerced query-parameters and response, producing also relevand swagger-docs.
(GET "/plus" []
:query-params [x :- Long, y :- Long]
:return {:result Long}
(ok {:result (+ x y)}))TODO Rewrite this with code-samples
;;
;; Pass-through swagger metadata
;;
(defmethod restructure-param :summary [k v acc]
(update-in acc [:swagger] assoc k v))
(defmethod restructure-param :description [k v acc]
(update-in acc [:swagger] assoc k v))
(defmethod restructure-param :operationId [k v acc]
(update-in acc [:swagger] assoc k v))
(defmethod restructure-param :consumes [k v acc]
(update-in acc [:swagger] assoc k v))
(defmethod restructure-param :produces [k v acc]
(update-in acc [:swagger] assoc k v))
;;
;; Smart restructurings
;;
; Boolean to discard the route out from api documentation
; Example:
; :no-doc true
(defmethod restructure-param :no-doc [_ v acc]
(update-in acc [:swagger] assoc :x-no-doc v))
; publishes the data as swagger-parameters without any side-effects / coercion.
; Examples:
; :swagger {:responses {200 {:schema User}
; 404 {:schema Error
; :description "Not Found"} }
; :paramerers {:query {:q s/Str}
; :body NewUser}}}
(defmethod restructure-param :swagger [_ swagger acc]
(assoc-in acc [:swagger :swagger] swagger))
; Route name, used with path-for
; Example:
; :name :user-route
(defmethod restructure-param :name [_ v acc]
(update-in acc [:swagger] assoc :x-name v))
; Tags for api categorization. Ignores duplicates.
; Examples:
; :tags [:admin]
(defmethod restructure-param :tags [_ tags acc]
(update-in acc [:swagger :tags] (comp set into) tags))
; Defines a return type and coerces the return value of a body against it.
; Examples:
; :return MySchema
; :return {:value String}
; :return #{{:key (s/maybe Long)}}
(defmethod restructure-param :return [_ schema acc]
(let [response (convert-return schema)]
(-> acc
(update-in [:swagger :responses] (fnil conj []) response)
(update-in [:responses] (fnil conj []) response))))
; value is a map of http-response-code -> Schema. Translates to both swagger
; parameters and return schema coercion. Schemas can be decorated with meta-data.
; Examples:
; :responses {403 nil}
; :responses {403 {:schema ErrorEnvelope}}
; :responses {403 {:schema ErrorEnvelope, :description \"Underflow\"}}
(defmethod restructure-param :responses [_ responses acc]
(-> acc
(update-in [:swagger :responses] (fnil conj []) responses)
(update-in [:responses] (fnil conj []) responses)))
; reads body-params into a enhanced let. First parameter is the let symbol,
; second is the Schema to be coerced! against.
; Examples:
; :body [user User]
(defmethod restructure-param :body [_ [value schema] acc]
(-> acc
(update-in [:lets] into [value (src-coerce! schema :body-params :body)])
(assoc-in [:swagger :parameters :body] schema)))
; reads query-params into a enhanced let. First parameter is the let symbol,
; second is the Schema to be coerced! against.
; Examples:
; :query [user User]
(defmethod restructure-param :query [_ [value schema] acc]
(-> acc
(update-in [:lets] into [value (src-coerce! schema :query-params :string)])
(assoc-in [:swagger :parameters :query] schema)))
; reads header-params into a enhanced let. First parameter is the let symbol,
; second is the Schema to be coerced! against.
; Examples:
; :headers [headers Headers]
(defmethod restructure-param :headers [_ [value schema] acc]
(-> acc
(update-in [:lets] into [value (src-coerce! schema :headers :string)])
(assoc-in [:swagger :parameters :header] schema)))
; restructures body-params with plumbing letk notation. Example:
; :body-params [id :- Long name :- String]
(defmethod restructure-param :body-params [_ body-params acc]
(let [schema (strict (fnk-schema body-params))]
(-> acc
(update-in [:letks] into [body-params (src-coerce! schema :body-params :body)])
(assoc-in [:swagger :parameters :body] schema))))
; restructures form-params with plumbing letk notation. Example:
; :form-params [id :- Long name :- String]
(defmethod restructure-param :form-params [_ form-params acc]
(let [schema (strict (fnk-schema form-params))]
(-> acc
(update-in [:letks] into [form-params (src-coerce! schema :form-params :string)])
(update-in [:swagger :parameters :formData] st/merge schema)
(assoc-in [:swagger :consumes] ["application/x-www-form-urlencoded"]))))
; restructures multipart-params with plumbing letk notation and consumes "multipart/form-data"
; :multipart-params [file :- compojure.api.upload/TempFileUpload]
(defmethod restructure-param :multipart-params [_ params acc]
(let [schema (strict (fnk-schema params))]
(-> acc
(update-in [:letks] into [params (src-coerce! schema :multipart-params :string)])
(update-in [:swagger :parameters :formData] st/merge schema)
(assoc-in [:swagger :consumes] ["multipart/form-data"]))))
; restructures header-params with plumbing letk notation. Example:
; :header-params [id :- Long name :- String]
(defmethod restructure-param :header-params [_ header-params acc]
(let [schema (fnk-schema header-params)]
(-> acc
(update-in [:letks] into [header-params (src-coerce! schema :headers :string)])
(assoc-in [:swagger :parameters :header] schema))))
; restructures query-params with plumbing letk notation. Example:
; :query-params [id :- Long name :- String]
(defmethod restructure-param :query-params [_ query-params acc]
(let [schema (fnk-schema query-params)]
(-> acc
(update-in [:letks] into [query-params (src-coerce! schema :query-params :string)])
(assoc-in [:swagger :parameters :query] schema))))
; restructures path-params by plumbing letk notation. Example:
; :path-params [id :- Long name :- String]
(defmethod restructure-param :path-params [_ path-params acc]
(let [schema (fnk-schema path-params)]
(-> acc
(update-in [:letks] into [path-params (src-coerce! schema :route-params :string)])
(assoc-in [:swagger :parameters :path] schema))))
; Applies the given vector of middlewares to the route
(defmethod restructure-param :middleware [_ middleware acc]
(update-in acc [:middleware] into middleware))
; Bind to stuff in request components using letk syntax
(defmethod restructure-param :components [_ components acc]
(update-in acc [:letks] into [components `(mw/get-components ~+compojure-api-request+)]))
; route-specific override for coercers
(defmethod restructure-param :coercion [_ coercion acc]
(update-in acc [:middleware] conj [mw/wrap-coercion coercion]))See https://github.com/metosin/compojure-api/wiki/Creating-your-own-metadata-handlers