-
Notifications
You must be signed in to change notification settings - Fork 150
Endpoints
-
GET
,POST
,PUT
,HEAD
,PATCH
,DELETE
,OPTIONS
andANY
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"}}
-
routes
can be used to group routes together (match-first) -
context
allows 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