:coercion
applies for context
parameters too (not just childs)
updated deps:
[metosin/muuntaja "0.3.3"] is available but we use "0.3.2"
dynamic-context
is removed in favor of :dynamic true
meta-data for contexts:(require '[compojure.api.help :as help])
(help/help :meta :dynamic)
; :dynamic
;
; If set to to `true`, makes a `context` dynamic,
; e.g. body is evaluated on each request. NOTE:
; Vanilla Compojure has this enabled by default
; while compojure-api default to `false`, being
; much faster. For details, see:
;
; https://github.com/weavejester/compojure/issues/148
;
; (context "/static" []
; (if (= 0 (random-int 2))
; ;; mounting decided once
; (GET "/ping" [] (ok "pong")))
;
; (context "/dynamic" []
; :dynamic true
; (if (= 0 (random-int 2))
; ;; mounted for 50% of requests
; (GET "/ping" [] (ok "pong")))
routes
and context
:(context "/api" []
(for [path ["/ping" "/pong"]]
(GET path [] (ok {:path path}))))
[metosin/ring-swagger "0.24.3"] is available but we use "0.24.2"
ANY
produces swagger-docs for all methods, thanks to Anthony
Updated deps:
[metosin/spec-tools "0.5.0"] is available but we use "0.4.0"
:pred
under Spec :problems
, fixes #345:spec
coercion is tried without required dependenciesAligned with the latest spec-tools: [metosin/spec-tools "0.4.0"]
To use Clojure 1.9 & Spec with Swagger, these need to be imported:
[org.clojure/clojure "1.9.0-beta2"]
[metosin/spec-tools "0.4.0"]
ring.middleware.http-response
exception handling directly:(require '[compojure.api.sweet :refer :all])
(require '[ring.util.http-response :as http])
(api
{:exceptions {:handlers {::http/response handle-thrown-http-exceptions-here}}
(GET "/throws" []
(http/bad-request! {:message "thrown response"})))
api
instance (if not undefined, e.g. nil
) is injected into :compojure.api.request/muuntaja
for endpoints to use.
path-for
and path-for*
now use this to encode path-parameters.(require '[compojure.api.sweet :refer :all])
(require '[compojure.api.request :as request])
(require '[muuntaja.core :as m])
(api
(GET "/ping" {:keys [::request/muuntaja]}
(ok {:json-string (slurp (m/encode muuntaja "application/json" [:this "is" 'JSON]))})))
Muuntaja
-instance optins are merged correctly.(require '[compojure.api.sweet :refer :all])
(require '[ring.util.http-response :refer [ok]])
(require '[metosin.transit.dates :as transit-dates])
(require '[muuntaja.core :as m])
(def muuntaja
(m/create
(-> muuntaja/default-options
(update-in
[:formats "application/transit+json"]
merge
{:decoder-opts {:handlers transit-dates/readers}
:encoder-opts {:handlers transit-dates/writers}}))))
(api
{:formats muuntaja}
(GET "/pizza" []
(ok {:now (org.joda.time.DateTime/now)})))
[cheshire "5.7.1"]
[org.tobereplaced/lettercase "1.0.0"]
[potemkin "0.4.4"] is available but we use "0.4.3"
[metosin/ring-swagger "0.24.2"] is available but we use "0.24.1"
[metosin/spec-tools "0.4.0"] is available but we use "0.3.2"
application/yaml
& application/msgpack
. If you want to add them back, you need to manually add the dependencies below and configure Muuntaja to handle those:(require '[muuntaja.core :as muuntaja])
(require '[muuntaja.format.yaml :as yaml-format])
(require '[muuntaja.format.msgpack :as msgpack-format])
(api
{:formats (-> muuntaja/default-options)
(yaml-format/with-yaml-format)
(msgpack-format/with-msgpack-format))}
...)
[circleci/clj-yaml "0.5.6"]
[clojure-msgpack "1.2.0"]
spec coericon also calls s/unform
after s/conform
, e.g. specs like (s/or :int spec/int? :keyword spec/keyword?)
work now too.
updated dependencies:
[circleci/clj-yaml "0.5.6"] is available but we use "0.5.5"
[metosin/muuntaja "0.3.2"] is available but we use "0.3.1"
[ring/ring-core "1.6.2"] is available but we use "1.6.1"
[metosin/ring-swagger "0.24.1"] is available but we use "0.24.0"
updated deps for the 1.*
BREAKING: in compojure.api.swagger
, the swagger-ui
and swagger-docs
now take options map with path
key instead of separate optional path & vararg opts.
swagger-routes
and thus be unaffected of this.updated dependencies:
[prismatic/plumbing "0.5.4"] is available but we use "0.5.3"
[compojure "1.6.0"] is available but we use "1.5.2"
[prismatic/schema "1.1.6"] is available but we use "1.1.3"
[ring-middleware-format "0.7.2"] is available but we use "0.7.0"
[metosin/ring-http-response "0.9.0"] is available but we use "0.8.1"
[metosin/ring-swagger "0.24.1"] is available but we use "0.22.14"
Spec coercion endpoints produce now Swagger2 data
To use Clojure 1.9 & Spec with Swagger, these need to be imported:
[org.clojure/clojure "1.9.0-alpha17"]
[metosin/spec-tools "0.3.0"]
[org.clojure/clojure "1.8.0"]
[metosin/spec-tools "0.3.0" :exclusions [org.clojure/spec.alpha]]
[clojure-future-spec "1.9.0-alpha17"]
INFO :spec swagger generation enabled in compojure.api
[metosin/spec-tools "0.3.0"] is available but we use "0.2.2"
pr-str
value.resource
body-params are associated over existing instead of merged. e.g. extra params are really stripped off.Update to latest Muuntaja.
updated deps:
[metosin/muuntaja "0.3.1"] is available but we use "0.2.2"
compojure.api.request
back to src
.:compojure.api.request/coercion
compojure.api.coercion
, replacing compojure.api.coerce
.:coercion
can be set to api
, context
, endpoint macros or a resource
. It can be either:
compojure.api.coercion.core/Coercion
Coercion
via compojure.api.coercion.core/named-coercion
multimethod.coercion
is stored in Route :info
Coercion
:(defprotocol Coercion
(get-name [this])
(get-apidocs [this spec data])
(encode-error [this error])
(coerce-request [this model value type format request])
(coerce-response [this model value type format request]))
:schema
(default) resolves to compojure.api.coercion.schema/SchemaCoercion
:spec
resolves to compojure.api.coercion.spec/SpecCoercion
nil
removes the coercion (was: nil
or (constantly nil)
).(require '[compojure.api.sweet :refer :all])
(require '[clojure.spec.alpha :as s])
(require '[spec-tools.spec :as spec])
(s/def ::id spec/int?)
(s/def ::name spec/string?)
(s/def ::description spec/string?)
(s/def ::type spec/keyword?)
(s/def ::new-pizza (s/keys :req-un [::name ::type] :opt-un [::description]))
(s/def ::pizza (s/keys :req-un [::id ::name ::type] :opt-un [::description]))
(resource
{:coercion :spec
:summary "a spec resource, no swagger yet"
:post {:parameters {:body-params ::new-pizza}
:responses {200 {:schema ::pizza}}
:handler (fn [{new-pizza :body-params}]
(ok (assoc new-pizza :id 1)))}})
(require '[spec-tools.data-spec :as ds])
(s/def ::id spec/int?)
(context "/spec" []
:coercion :spec
(POST "/pizza" []
:summary "a spec endpoint"
:return ::pizza
:body [new-pizza ::new-pizza]
(ok (assoc new-pizza :id 1)))
(POST "/math/:x" []
:summary "a spec endpoint"
:return {:total int?}
:path-params [x :- spec/int?]
:query-params [y :- spec/int?,
{z :- spec/int? 0}]
(ok {:total (+ x y z)})))
[org.clojure/clojure "1.9.0-alpha17"]
[metosin/spec-tools "0.2.2"]
[org.clojure/clojure "1.8.0"]
[metosin/spec-tools "0.2.2" :exclusions [org.clojure/spec.alpha]]
[clojure-future-spec "1.9.0-alpha17"]
BREAKING: Clojure 1.7.0 is no longer supported (no back-port for clojure.spec
).
use ClassLoader -scoped Schema memoization instead of api-scoped - same for anonymous map specs
:body-params
is available for exception handlers, fixes #306 & #313
BREAKING: Restructuring internal key changes in compojure.api.meta
:
:swagger
is removed in favor of :info
.[:info :public]
instead of [:swagger]
:info
can contain:
:static-context?
-> true
if the context
is internally optimized as static:name
, route name:coercion
, the defined coercion(let [app (GET "/" []
:return {:x String}
(ok {:kikka 2}))]
(try
(app {:request-method :get, :uri "/"})
(catch Exception e
(ex-data e))))
; {:type :compojure.api.exception/response-validation,
; :validation :schema,
; :in [:response :body],
; :schema {:x java.lang.String},
; :errors {:x missing-required-key,
; :kikka disallowed-key},
; :response {:status 200,
; :headers {},
; :body {:kikka 2}}}
(let [app (GET "/" []
:query-params [x :- String]
(ok))]
(try
(app {:request-method :get, :uri "/" :query-params {:x 1}})
(catch Exception e
(ex-data e))))
; {:type :compojure.api.exception/request-validation,
; :validation :schema,
; :value {:x 1},
; :in [:request :query-params],
; :schema {Keyword Any, :x java.lang.String},
; :errors {:x (not (instance? java.lang.String 1))},
; :request {:request-method :get,
; :uri "/",
; :query-params {:x 1},
; :route-params {},
; :params {},
; :compojure/route [:get "/"]}}
Introduce dynamic-context
that works like context
before the fast context optimization (#253).
context
, they will not work as intended. If you need this, replace context
with dynamic-context
.For example:
;; compojure-api 1.1
(context "/static" []
(if (its-noon?)
(GET "/noon-route" [] (ok "it's noon")))
;; compojure-api 1.2:
(dynamic-context "/static" []
(if (its-noon?)
(GET "/noon-route" [] (ok "it's noon")))
1.0.0
(for :parameters
and :middlewares
)BREAKING: resource
function is always 1-arity, options and info are merged.
resource
can have :middleware
on both top-level & method-level.
(def mw [handler value]
(fn [request]
(println value)
(handler request)))
(resource
{:middleware [[mw :top1] [mw :top2]]
:get {:middleware [[mw :get1] [mw :get2]]}
:post {:middleware [[mw :post1] [mw :post2]]}
:handler (constantly (ok))})
[prismatic/schema "1.1.6"] is available but we use "1.1.5"
resource
separates 1-arity :handler
and 3-arity :async-handler
. Rules:
:handler
is used, sent via compojure.response/render
:async-handler
is used, with fallback to :handler
.
compojure.response/send
so manifold Deferred
and core.async ManyToManyChannel
can be returned.(require '[compojure.api.sweet :refer :all])
(require '[clojure.core.async :as a])
(require '[manifold.deferred :as d])
(resource
{:summary "async resource"
:get {:summary "normal ring async"
:async-handler (fn [request respond raise]
(future
(Thread/sleep 100)
(respond (ok {:hello "world"})))
nil)}
:put {:summary "core.async"
:handler (fn [request]
(a/go
(a/<! (a/timeout 100))
(ok {:hello "world"})))}
:post {:summary "manifold"
:handler (fn [request]
(d/future
(Thread/sleep 100)
(ok {:hello "world"})))}})
[ring/ring-core "1.6.1"] is available but we use "1.6.0"
[ring/ring-core "1.6.0"]
compojure.api.core
depends on compojure.api.async
Deferred
and core.async ManyToManyChannel
can be returned from endpoints.resource
now supports async (3-arity) handlers as well.(resource
{:parameters {:query-params {:x Long}}
:handler (fn [request respond raise]
(future
(res (ok {:total (-> request :query-params :x)})))
nil)})
[ring/ring-core "1.6.0"]
[cheshire "5.7.1"] is available but we use "5.7.0"
[compojure "1.6.0"] is available but we use "1.5.2"
[prismatic/schema "1.1.5"] is available but we use "1.1.4"
[prismatic/plumbing "0.5.4"] is available but we use "0.5.3"
[metosin/ring-http-response "0.9.0"] is available but we use "0.8.2"
[metosin/ring-swagger "0.24.0"] is available but we use "0.23.0"
[compojure "1.6.0"] is available but we use "1.6.0-beta3"
[org.clojure/clojure "1.9.0-alpha15"]
(requires Midje 1.9.0-alpha6
)[metosin/muuntaja "0.2.1"] is available but we use "0.2.0-20170323.064148-15"
Initial support for Async Ring, using CPS, manifold or core.async
compojure.api.core/ring-handler
to turn a compojure-api route into a 1-arity function
Fn
:params
are populated correctly from :body-params
Allow nil
paths in routing, allows easy (static) conditional routing like:
(defn app [dev-mode?]
(api
(GET "ping" [] (ok "pong"))
(if dev-mode?
(GET "/drop-the-db" [] (ok "dropped")))))
java.io.File
as response type, mapping to file downloads
(GET "/file" []
:summary "a file download"
:return java.io.File
:produces #{"image/png"}
(-> (io/resource "screenshot.png")
(io/input-stream)
(ok)
(header "Content-Type" "image/png"))))
Fix help-for for some restructure methods #275 by Nicolás Berger
BREAKING: in compojure.api.swagger
, the swagger-ui
and swagger-docs
now take options map with path
key instead of separate optional path & vararg opts.
swagger-routes
and thus be unaffected of this.BREAKING: middleware
is removed because it dangerously applied the
middleware even to requests that didn't match the contained routes. New route-middleware
only applies middlewares when the request is matched against contained routes.
route-middleware
is not exposed in sweet
namespace but is available at compojure.api.core
Updated deps:
[metosin/muuntaja "0.2.0-20170323.064148-15"] is available but we use "0.2.0-20170122.164054-8"
[prismatic/schema "1.1.4"] is available but we use "1.1.3"
[metosin/ring-swagger-ui "2.2.10"] is available but we use "2.2.8"
[metosin/ring-swagger "0.23.0"] is available but we use "0.22.14"
[metosin/ring-http-response "0.8.2"] is available but we use "0.8.1"
[:exceptions :handlers]
options also allows exception classes as keys.
:type
-lookup, then by Exception class and it's superclasses.(api
{:exceptions
{:handlers
{::ex/default handle-defaults
java.sql.SQLException handle-all-sql-exceptions}}}
...)
compojure.api.help/help
.(require '[compojure.api.help :refer [help]])
(help)
; ------------------------------------------------------------
; Usage:
;
; (help)
; (help topic)
; (help topic subject)
;
; Topics:
;
; :meta
;
; Topics & subjects:
;
; :meta :body
; :meta :body-params
; :meta :coercion
; :meta :components
; :meta :consumes
; :meta :description
; :meta :form-params
; :meta :header-params
; :meta :middleware
; :meta :multipart-params
; :meta :name
; :meta :no-doc
; :meta :operationId
; :meta :path-params
; :meta :produces
; :meta :responses
; :meta :return
; :meta :summary
; :meta :swagger
; :meta :tags
(help/help :meta :middleware)
; ------------------------------------------------------------
;
; :middleware
;
; Applies the given vector of middleware to the route.
; Middleware is presented as data in a Duct-style form:
;
; 1) ring mw-function (handler->request->response)
;
; 2) mw-function and it's arguments separately - mw is
; created by applying function with handler and args
;
; (defn require-role [handler role]
; (fn [request]
; (if (has-role? request role)
; (handler request)
; (unauthorized))))
;
; (def require-admin (partial require-role :admin))
;
; (GET "/admin" []
; :middleware [require-admin]
; (ok))
;
; (GET "/admin" []
; :middleware [[require-role :admin]]
; (ok))
;
; (GET "/admin" []
; :middleware [#(require-admin % :admin)]
; (ok))
;
(defmethod help/help-for [:restructuring :query-params] [_ _]
(help/text
"Restructures query-params with plumbing letk notation.\n"
"Example: read x and optionally y (defaulting to 1)"
"from query parameters. Body of the endpoint sees the"
"coerced values.\n"
(help/code
"(GET \"/ping\""
" :query-params [x :- Long, {y :- Long 1}]"
" (ok (+ x y)))")))
[metosin/muuntaja "0.2.0-20170130.142747-9"] is available but we use "0.2.0-20170122.164054-8"
this is an alpha release, feedback welcome
:body
does not keywordize all keys,
true
).resource
under context
requires exact routing match, fixes #269compojure.api.routes/Routes
, returned routes don't commit to swagger-docs - as they can be generated at runtimecompojure.api.middleware
, the default-coercion-matchers
is removed in favour of create-coercion
& default-coercion-options
coercion
should work as before, as the contract has not changedjson-coercion-matcher
Format | Request | Response |
---|---|---|
application/edn | validate | validate |
application/transit+json | validate | validate |
application/transit+msgpack | validate | validate |
application/json | json-coercion-matcher | validate |
application/msgpack | json-coercion-matcher | validate |
application/x-yaml | json-coercion-matcher | validate |
defaults as code:
(def default-coercion-options
{:body {:default (constantly nil)
:formats {"application/json" json-coercion-matcher
"application/msgpack" json-coercion-matcher
"application/x-yaml" json-coercion-matcher}}
:string string-coercion-matcher
:response {:default (constantly nil)
:formats {}}})
to create a valid coercion
(for api or to routes):
;; create (with defaults)
(mw/create-coercion)
(mw/create-coercion mw/default-coercion-options)
;; no response coercion
(mw/create-coercion (dissoc mw/default-coercion-options :response)
;; disable all coercion
nil
(mw/create-coercion nil)
(context "/api" []
(GET "/ping" [] (ok))
(POST "/echo" []
:body [data {:name s/Str}]
:return {:name s/Str}
(ok data))
(context "/resource" []
(resource
{:get {:handler (constantly (ok))}})))
; #Route {:path "/api",
; :childs [#Route {:path "/ping"
; :method :get}
; #Route {:path "/echo",
; :method :post,
; :info {:parameters {:body {:name Str}},
; :responses {200 {:schema {:name Str}
; :description ""}}}}
; #Route {:path "/resource"
; :childs [#Route{:childs [#Route{:path "/"
; :method :get}]}]}]}
[cheshire "5.7.0"] is available but we use "5.6.3"
[metosin/muuntaja "0.2.0-20170122.164054-8"] is available but we use "0.2.0-20161031.085120-3"
[metosin/ring-http-response "0.8.1"] is available but we use "0.8.0"
[metosin/ring-swagger "0.22.14"] is available but we use "0.22.12"
[metosin/ring-swagger-ui "2.2.8"] is available but we use "2.2.5-0"
:format
has been deprecated (fails at api creation time), use :formats
instead. It consumes either a
Muuntaja instance, Muuntaja options map or nil
(unmounts it). See how to configure Muuntaja how to use.context
s, #253 - use static routes if a context
doesn't do any lexical bindings
context
routing.:middleware
for api
& api-middleware
, run last just before the actual routes. Uses same syntax as with the routing macros.(api
{:middleware [no-cache [wrap-require-role :user]]}
...)
[metosin/muuntaja "0.2.0-SNAPSHOT"]
[metosin/ring-swagger "0.22.12"] is available but we use "0.22.11"
[ring-middleware-format "0.7.0"]
[compojure "1.5.2"] is available but we use "1.5.1"
[metosin/ring-http-response "0.8.1"] is available but we use "0.8.0"
[metosin/ring-swagger "0.22.14"] is available but we use "0.22.11"
[metosin/ring-swagger-ui "2.2.8"] is available but we use "2.2.5-0"
:header-params
with resources, #254[frankiesardo/linked "1.2.9"] is available but we use "1.2.7"
[metosin/ring-swagger "0.22.11"] is available but we use "0.22.10"
[metosin/ring-swagger-ui "2.2.5-0"] is available but we use "2.2.2-0"
Lot's of new swagger-bindings from Ring-swagger:
schema.core.defrecord
org.joda.time.LocalTime
s/Any
in body generates empty object instead of nilBundled with latest swagger-ui 2.2.2-0
Updated deps:
[metosin/ring-swagger "0.22.10"] is available but we use "0.22.9"
[metosin/ring-swagger-ui "2.2.2-0"] is available but we use "2.2.1-0"
Bundled with the latest Swagger-ui (2.2.1-0)
Updated deps:
[metosin/ring-swagger-ui "2.2.1-0"] is available but we use "2.1.4-0"
:content-type
of user-defined formats are pushed into Swagger :produces
and :consumes
, thanks to Waldemar.(def custom-json-format
(ring.middleware.format-response/make-encoder cheshire.core/generate-string "application/vnd.vendor.v1+json"))
(api
{:format {:formats [custom-json-format :json :edn]}}
...)
[:api :disable-api-middleware?]
to disable the api-middleware completely. With this set, api
only produces the (reverse) route-tree + set's swagger stuff and sets schema coercions for the api.
(api
{:api {:disable-api-middleware? true}
;; Still available
:swagger {:ui "/api-docs"
:spec "/swagger.json"
:data {:info {:title "api"}}}}
...)
:data
in swagger-routes
can be overridden even if run outside of api
:(def app
(routes
(swagger-routes
{:ui "/api-docs"
:spec "/swagger.json"
:data {:info {:title "Kikka"}
:paths {"/ping" {:get {:summary "ping get"}}}}})
(GET "/ping" [] "pong"))))
:format
option in api-middleware
causes all format-middlewares not to mount:exceptions
option in api-middleware
causes the exception handling to be disabled:coercion
translates to same as setting it to (constantly nil)
(api
{:exceptions nil ;; disable exception handling
:format nil ;; disable ring-middleware-format
:coercion nil} ;; disable all schema-coercion
;; this will be really thrown
(GET "/throw" []
(throw (new RuntimeException))))
[prismatic/schema "1.1.3"] is available but we use "1.1.2"
[frankiesardo/linked "1.2.7"] is available but we use "1.2.6"
fix reflection warning with logging, thanks to Matt K.
Empty contexts (/
) don't accumulate to the path, see https://github.com/weavejester/compojure/issues/125
NOTE: update of ring-http-response
had a breaking change:
updated dependencies:
[compojure "1.5.1"] is available but we use "1.5.0"
[metosin/ring-http-response "0.8.0"] is available but we use "0.7.0"
[cheshire "5.6.3"] is available but we use "5.6.1"
[prismatic/schema "1.1.2"] is available but we use "1.1.1"
[metosin/ring-http-response "0.7.0"] is available but we use "0.6.5"
[metosin/ring-swagger "0.22.9"] is available but we use "0.22.8"
[reloaded.repl "0.2.2"] is available but we use "0.2.1"
[peridot "0.4.4"] is available but we use "0.4.3"
[reloaded.repl "0.2.2"] is available but we use "0.2.1"
Response headers are mapped correctly, fixes #232
updated dependencies:
[metosin/ring-swagger "0.22.8"] is available but we use "0.22.7"
:swagger
.(let [runtime-data {:x-name :boolean
:operationId "echoBoolean"
:description "Ehcoes a boolean"
:parameters {:query {:q s/Bool}}}]
(api
(GET "/route" []
:swagger runtime-data
(ok {:it "works"}))))
:route-params
into :path-params
with resources
(resource
{:parameters {:path-params {:id s/Int}}
:responses {200 {:schema s/Int}}
:handler (fnk [[:path-params id]]
(ok (inc id)))})
[prismatic/schema "1.1.1"] is available but we use "1.1.0"
compojure.api.swgger/validate
to compojure.api.validator/validate
.resource
doesn't define a handler for a given request-method
or for top-level, nil is returned (instead of throwing exeption)context
. Trying to return a compojure.api.routing/Route
from an endpoint like ANY
will throw descriptive (runtime-)exception.(context "/hello" []
(resource
{:description "hello-resource"
:responses {200 {:schema {:message s/Str}}}
:post {:summary "post-hello"
:parameters {:body-params {:name s/Str}}
:handler (fnk [[:body-params name]]
(ok {:message (format "hello, %s!" name)}))}
:get {:summary "get-hello"
:parameters {:query-params {:name s/Str}}
:handler (fnk [[:query-params name]]
(ok {:message (format "hello, %s!" name)}))}}))
{:ui nil, :spec nil}
. Setting up just the spec or ui, doesn't automatically setup the other (like previously):middleware
, fixes #228describe
works with anonymous body-schemas (via ring-swagger 0.22.7
), Fixes #168[metosin/compojure-api "1.1.0" :exclusions [[metosin/scjsv]]]
[metosin/ring-swagger "0.22.7"] is available but we use "0.22.6"
[prismatic/plumbing "0.5.3"] is available but we use "0.5.2"
[cheshire "5.6.1"] is available but we use "5.5.0"
compojure.api.meta
to compojure.api.coerce
.compojure.api.resource/resource
(also in compojure.api.sweet
) for building resource-oriented services
(defn resource
"Creates a nested compojure-api Route from enchanced ring-swagger operations map and options.
By default, applies both request- and response-coercion based on those definitions.
Options:
- **:coercion** A function from request->type->coercion-matcher, used
in resource coercion for :body, :string and :response.
Setting value to `(constantly nil)` disables both request- &
response coercion. See tests and wiki for details.
Enchancements to ring-swagger operations map:
1) :parameters use ring request keys (query-params, path-params, ...) instead of
swagger-params (query, path, ...). This keeps things simple as ring keys are used in
the handler when destructuring the request.
2) at resource root, one can add any ring-swagger operation definitions, which will be
available for all operations, using the following rules:
2.1) :parameters are deep-merged into operation :parameters
2.2) :responses are merged into operation :responses (operation can fully override them)
2.3) all others (:produces, :consumes, :summary,...) are deep-merged by compojure-api
3) special key `:handler` either under operations or at top-level. Value should be a
ring-handler function, responsible for the actual request processing. Handler lookup
order is the following: operations-level, top-level, exception.
4) request-coercion is applied once, using deep-merged parameters for a given
operation or resource-level if only resource-level handler is defined.
5) response-coercion is applied once, using merged responses for a given
operation or resource-level if only resource-level handler is defined.
Note: Swagger operations are generated only from declared operations (:get, :post, ..),
despite the top-level handler could process more operations.
Example:
(resource
{:parameters {:query-params {:x Long}}
:responses {500 {:schema {:reason s/Str}}}
:get {:parameters {:query-params {:y Long}}
:responses {200 {:schema {:total Long}}}
:handler (fn [request]
(ok {:total (+ (-> request :query-params :x)
(-> request :query-params :y))}))}
:post {}
:handler (constantly
(internal-server-error {:reason \"not implemented\"}))})"
([info]
(resource info {}))
([info options]
(let [info (merge-parameters-and-responses info)
root-info (swaggerize (root-info info))
childs (create-childs info)
handler (create-handler info options)]
(routes/create nil nil root-info childs handler))))
[compojure "1.5.0"] is available but we use "1.4.0"
[prismatic/schema "1.1.0"] is available but we use "1.0.5"
[metosin/ring-swagger "0.22.6"] is available but we use "0.22.4"
ex-data
under :response
.
This can be used in logging, "what did the route try to return". Thanks to Tim Gilbert.:default
code if available and response code doesn't match(GET "/" []
:responses {200 {:schema {:ping s/Str}}
:default {:schema {:error s/int}}}
...)
[prismatic/schema "1.0.5"] is available but we use "1.0.4"
:basePath
with swagger-routes
, thanks to Hoxu.[metosin/ring-swagger "0.22.4"] is available but we use "0.22.3"
(defn more-routes [db version]
(routes
(GET "/version" []
(ok {:version version}))
(POST "/thingie" []
(ok (thingie/create db)))))
(defn app [db]
(api
(context "/api/:version" []
:path-params [version :- s/Str]
(more-routes db version)
(GET "/kikka" []
(ok "kukka")))))
BREAKING Vanilla Compojure routes will not produce any swagger-docs (as they do not satisfy the
Routing
protocol. They can still be used for handling request, just without docs.
[:api :invalid-routes-fn]
to declare how to handle routes not satisfying
the Routing
protocol. Default implementation logs invalid routes as WARNINGs.BREAKING compojure.core imports are removed from compojure.api.sweet
:
let-request
, routing
, wrap-routes
BREAKING Asterix (*
) is removed from route macro & function names, as there is no reason to mix compojure-api & compojure route macros.
GET*
=> GET
ANY*
=> ANY
HEAD*
=> HEAD
PATCH*
=> PATCH
DELETE*
=> DELETE
OPTIONS*
=> OPTIONS
POST*
=> PUT
context*
=> context
defroutes*
=> defroutes
BREAKING swagger-docs
and swagger-ui
are no longer in compojure.api.sweet
:swagger
(has no defaults)swagger-routes
function, mounting both the swagger-ui
and swagger-docs
and wiring them together
/
and the swagger-spec to /swagger.json
swagger-ui
& swagger-docs
(need to be separately imported from compojure.api.swagger
).(defapi app
(swagger-routes)
(GET "/ping" []
(ok {:message "pong"})))
(defapi app
{:swagger {:ui "/", :spec "/swagger.json"}}
(GET "/ping" []
(ok {:message "pong"})))
BREAKING: api-level coercion option is now a function of request => type => matcher
as it is documented.
Previously required a type => matcher
map. Options are checked against type => matcher
coercion input, and a
descriptive error is thrown when api is created with the old options format.
BREAKING: Renamed middlewares
to middleware
and :middlewares
key (restructuring) to :middleware
BREAKING: Middleware must be defined as data: both middleware macro and :middleware restructuring take a vector of middleware containing either
[function args]
[[wrap-foo {:opts :bar}]]
[#(wrap-foo % {:opts :bar})]
[(fn [handler] (wrap-foo handler {:opts :bar}))]
BREAKING: (Custom restructuring handlers only) :parameters
key used by restructure-param
has been renamed to :swagger
.
BREAKING public-resource-routes
& public-resources
are removed from compojure.api.middleware
.
BREAKING: compojure.api.legacy
namespace has been removed.
https://github.com/metosin/compojure-api/wiki/Migration-Guide-to-1.0.0
Additional route functions/macros in compojure.api.core
:
routes
& letroutes
, just like in the Compojure, but supporting Routing
undocumented
- works just like routes
but without any route definitions. Can be used to wrap legacy routes which setting the api option to fail on missing docs.top-level api
is now just function, not a macro. It takes an optional options maps and a top-level route function.
Coercer cache is now at api-level with 10000 entries.
Code generated from restructured route macros is much cleaner now
Coercion is on by default for standalone (apiless) endpoints.
(fact "coercion is on for apiless routes"
(let [route (GET "/x" []
:query-params [x :- Long]
(ok))]
(route {:request-method :get :uri "/x" :query-params {}}) => throws))
[backtick "0.3.3"]
Fixed path parameter handling in cases where path parameter is followed by an extension (#196, metosin/ring-swagger#82)
Added compojure.api.exception/with-logging
helper to add logging to exception handlers.
Updated deps:
[metosin/ring-swagger "0.22.3"] is available
[metosin/ring-swagger "0.22.2"] is available
[metosin/ring-swagger-ui "2.1.4-0"] is available
[potemkin "0.4.3"] is available
coercer-cache is now per Route instead beeing global and based on a FIFO size 100 cache. Avoids potential memory leaks when using anonymous coercion matchers (which never hit the cache).
Updated deps:
[prismatic/schema "1.0.4"] is available but we use "1.0.3"
schema
& matcher
-input) for better performance.
api
and reading json-string out.[potemkin "0.4.2"] is available but we use "0.4.1"
[Ring-Swagger "0.22.1"]
clojure.tools.logging
is used with default uncaugt exception handling if it's found
on the classpath. Fixes #172.api
and defapi
produce identical swagger-docs. Fixes #159[metosin/ring-swagger "0.22.1"] is available but we use "0.22.0"
[metosin/ring-swagger-ui "2.1.3-4"] is available but we use "2.1.3-2"
[prismatic/plumbing "0.5.2] is available but we use "0.5.1"
ring-middleware-format
accepts transit options in a new format:;; pre 0.24.0:
(api
{:format {:response-opts {:transit-json {:handlers transit/writers}}
:params-opts {:transit-json {:options {:handlers transit/readers}}}}}
...)
;; 0.24.0 +
(api
{:format {:response-opts {:transit-json {:handlers transit/writers}}
:params-opts {:transit-json {:handlers transit/readers}}}}
...)
swagger-ui
now supports passing arbitrary options to SwaggerUI
(metosin/ring-swagger#67).[prismatic/schema "1.0.3"] is available but we use "0.4.4"
[prismatic/plumbing "0.5.1] is available but we use "0.4.4"
[metosin/schema-tools "0.7.0"] is available but we use "0.5.2"
[metosin/ring-swagger "0.22.0"] is available but we use "0.21.0"
[metosin/ring-swagger-ui "2.1.3-2"] is available but we use "2.1.2"
:query-params [x :- [Long]]
& url ?x=1&x=2&x=3
should result in x
being [1 2 3]
.:validation-errors :error-handler
, :validation-errors :catch-core-errors?
and :exceptions :exception-handler
options have been removed.
:exceptions :handlers
options.context
from compojure.api.sweet
to compojure.api.legacy
. Use context*
instead.[metosin/ring-swagger "0.21.0-SNAPSHOT"] is available but we use "0.20.4"
[compojure "1.4.0"] is available but we use "1.3.4"
[prismatic/schema "0.4.4"] is available but we use "0.4.3"
[metosin/ring-http-response "0.6.5"] is available but we use "0.6.3"
[metosin/schema-tools "0.5.2"] is available but we use "0.5.1"
[metosin/ring-swagger-ui "2.1.2"] is available but we use "2.1.5-M2"
[peridot "0.4.1"] is available but we use "0.4.0"
[metosin/ring-http-response "0.6.3"] is available but we use "0.6.2"
[midje "1.7.0"] is available but we use "1.7.0-SNAPSHOT"
Optional integration with Component.
Use either :components
-option of api-middleware
or wrap-components
-middleware
to associate the components with your API. Then you can use :components
-restructuring
to destructure your components using letk syntax.
fix for #123
support for pluggable coercion, at both api-level & endpoint-level with option :coercion
. See thethe tests.
ring-request->coercion-type->coercion-matcher
allowing protocol-based coercion in the future
** BREAKING**: if you have created custom restructurings using src-coerce
, they will break (nicely at compile-time)new restucturing :swagger
just for swagger-docs. Does not do any coercion.
(GET* "/documented" []
:swagger {:responses {200 {:schema User}
404 {:schema Error
:description "Not Found"} }
:paramerers {:query {:q s/Str}
:body NewUser}}}
...)
[cheshire "5.5.0"] is available but we use "5.4.0"
[backtick "0.3.3"] is available but we use "0.3.2"
[lein-ring "0.9.6"] is available but we use "0.9.4"
:multipart-params
now sets :consumes ["multipart/form-data"]
and :form-params
sets
:consumes ["application/x-www-form-urlencoded"]
compojure.api.upload
namespace.(POST* "/upload" []
:multipart-params [file :- TempFileUpload]
:middlewares [wrap-multipart-params]
(ok (dissoc file :tempfile))))
:responses
. A helpful IllegalArgumentException
will be thrown at compile-time with old models.:responses {400 {:schema ErrorSchema}}
:responses {400 {:schema ErrorSchema, :description "Eror"}}
api-middleware
options with key :ring-swagger
:(defapi app
{:ring-swagger {:ignore-missing-mappings? true}})
(swagger-docs)
(swagger-ui)
...)
path-for
:(fact "bidirectional routing"
(let [app (api
(GET* "/api/pong" []
:name :pong
(ok {:pong "pong"}))
(GET* "/api/ping" []
(moved-permanently (path-for :pong))))]
(fact "path-for resolution"
(let [[status body] (get* app "/api/ping" {})]
status => 200
body => {:pong "pong"}))))
(require '[compojure.api.sweet :refer :all])
(require '[compojure.api.swagger :refer [validate])
(defrecord NonSwaggerRecord [data])
(def app
(validate
(api
(swagger-docs)
(GET* "/ping" []
:return NonSwaggerRecord
(ok (->NonSwaggerRecord "ping"))))))
; clojure.lang.Compiler$CompilerException: java.lang.IllegalArgumentException:
; don't know how to create json-type of: class compojure.api.integration_test.NonSwaggerRecord
[metosin/ring-swagger "0.20.4"] is available but we use "0.20.3"
[metosin/ring-http-response "0.6.2"] is available but we use "0.6.1"
[metosin/ring-swagger-ui "2.1.5-M2"]
[prismatic/plumbing "0.4.4"] is available but we use "0.4.3"
[prismatic/schema "0.4.3"] is available but we use "0.4.2"
with-meta
), fixes #96
(context* "/responses" []
:tags ["responses"]
(GET* "/" []
:query-params [return :- (s/enum :200 :403 :404)]
:responses {403 ^{:message "spiders?"} {:code s/Str} ; old
404 (with-meta {:reason s/Str} {:message "lost?"})} ; new
:return Total
:summary "multiple returns models"
(case return
:200 (ok {:total 42})
:403 (forbidden {:code "forest"})
:404 (not-found {:reason "lost"}))))
compojure.api.core/api
, the work-horse behind compojure.api.core/defapi
.api
, pushed to request via ring-swagger middlewares.
+compojure-api-routes+
littering the handler namespaces.[metosin/ring-swagger "0.20.3"] is available but we use "0.20.2"
[prismatic/plumbing "0.4.3"] is available but we use "0.4.2"
[peridot "0.4.0"] is available but we use "0.3.1"
[compojure "1.3.4"] is available but we use "1.3.3"
[lein-ring "0.9.4"] is available but we use "0.9.3"
[metosin/ring-swagger "0.20.2"] is available but we use "0.20.0"
[prismatic/schema "0.4.2"] is available but we use "0.4.1"
New restructuring for :no-doc
(a boolean) - endpoints with this don't get api documentation.
Fixed #42 - defroutes*
now does namespace resolution for the source
used for route peeling and source linking (the macro magic)
Fixed #91 - defroutes*
are now automatically accessed over a Var for better development flow.
Fixed #89.
Fixed #82.
Fixed #71, ring-swagger-ui is now a dependency.
breaking ring.swagger.json-schema/describe
is now imported into compojure.api.sweet
for easy use. If your code
refers to it directly, you need remove the direct reference.
defapi
or compojure.api.routes/api-root
within that)compojure.api.routes/with-routes
is now compojure.api.routes/api-root
[metosin/ring-swagger-ui "2.1.1-M2"]
to get things pre-configured2.1.1-M2
yourself from the source.:nickname
is now :operationId
:notes
is now :description
swagger-docs
now takes any valid Swagger Spec data in. Using old format gives a warning is to STDOUT.(swagger-docs
{:info {:version "1.0.0"
:title "Sausages"
:description "Sausage description"
:termsOfService "http://helloreverb.com/terms/"
:contact {:name "My API Team"
:email "foo@example.com"
:url "http://www.metosin.fi"}
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}}
:tags [{:name "kikka", :description "kukka"}]})
/api/api-docs
to /swagger.json
.compojure.api.swagger/swaggered
is deprecated - not relevant with 2.0. Works, but prints out a warning to STDOUT
** in 2.0, apis are categorized by Tags, one can set them either to endpoints or to paths:(GET* "/api/pets/" []
:tags ["pet"]
(ok ...))
(context* "/api/pets" []
:tags ["pet"]
(GET* "/" []
:summary "get all pets"
(ok ...)))
[metosin/ring-swagger "0.20.0"] is available but we use "0.19.4"
[prismatic/schema "0.4.1"] is available but we use "0.4.0"
[prismatic/plumbing "0.4.2"] is available but we use "0.4.1"
[prismatic/schema "0.4.1"] is available but we use "0.4.0"
[potemkin "0.3.13"] is available but we use "0.3.12"
[compojure "1.3.3"] is available but we use "1.3.2"
[metosin/ring-swagger "0.19.4"] is available but we use "0.19.3"
2.1.0-M2
- [metosin/ring-swagger-ui "2.1.0-M2-2]
[metosin/ring-swagger "0.19.3"] is available but we use "0.19.2"
:return (s/maybe User)
:responses {200 (s/maybe User)
400 (s/either Cat Dog)}
[metosin/ring-swagger "0.19.2"] is available but we use "0.19.1"
:headers
, thanks to tchagnon!:path-param
allows any keywords, needed for the partial parameter matching with context*
compojure.api.meta/restructure-param
dispatch functions - for the swagger documentation part. See https://github.com/metosin/ring-swagger/blob/master/test/ring/swagger/swagger2_test.clj & https://github.com/metosin/compojure-api/blob/master/src/compojure/api/meta.clj for examples of the new schemas.context*
to allow setting meta-data to mid-routes. Mid-route meta-data are deep-merged into endpoint swagger-definitions at compile-time. At runtime, code is executed in place.(context* "/api/:kikka" []
:summary "summary inherited from context"
:path-params [kikka :- s/Str] ; enforced here at runtime
:query-params [kukka :- s/Str] ; enforced here at runtime
(GET* "/:kakka" []
:path-params [kakka :- s/Str] ; enforced here at runtime
(ok {:kikka kikka
:kukka kukka
:kakka kakka})))
[prismatic/plumbing "0.4.1"] is available but we use "0.3.7"
[potemkin "0.3.12"] is available but we use "0.3.11"
[prismatic/schema "0.4.0"] is available but we use "0.3.7"
[metosin/ring-http-response "0.6.1"] is available but we use "0.6.0"
[metosin/ring-swagger "0.19.0"] is available but we use "0.18.1"
[lein-ring "0.9.3"] is available but we use "0.9.2"
(defapi app
{:format {:formats [:json-kw :yaml-kw :edn :transit-json :transit-msgpack]
:params-opts {}
:response-opts {}}
:validation-errors {:error-handler nil
:catch-core-errors? nil}
:exceptions {:exception-handler default-exception-handler}}
...)
compojure.core/wrap-routes
into compojure.api.sweet
compojure.api.middleware
, ex-info-support
is now parameterizable wrap-exception
[prismatic/plumbing "0.3.7"] is available but we use "0.3.5"
[compojure "1.3.2"] is available but we use "1.3.1"
[prismatic/schema "0.3.7"] is available but we use "0.3.3"
[metosin/ring-swagger "0.18.0"] is available but we use "0.15.0"
[metosin/ring-http-response "0.6.0"] is available but we use "0.5.2"
[metosin/ring-middleware-format "0.6.0"] is available but we use "0.5.0"
ring-middleware-format
[cheshire "5.4.0"] is available but we use "5.3.1"
[metosin/ring-swagger-ui "2.0.24"] is available but we use "2.0.17"
[lein-ring "0.9.0"] is available but we use "0.8.13"
[compojure "1.3.1"] is available but we use "1.2.1"
[metosin/ring-swagger "0.15.0"] is available but we use "0.14.1"
[peridot "0.3.1"] is available but we use "0.3.0"
[prismatic/schema "0.3.3"] is available but we use "0.3.2"
[metosin/ring-http-response "0.5.2"] is available but we use "0.5.1"
[org.tobereplaced/lettercase "1.0.0"]
for camel-casing (see https://github.com/metosin/compojure-api-examples/issues/1#issuecomment-62580504)[metosin/ring-swagger "0.14.1"] is available but we use "0.14.0"
:form-parameters
, thanks to Thomas Whitcomb[prismatic/plumbing "0.3.5"] is available but we use "0.3.3"
[potemkin "0.3.11"] is available but we use "0.3.8"
[compojure "1.2.1"] is available but we use "1.1.9"
[prismatic/schema "0.3.2"] is available but we use "0.2.6"
[metosin/ring-http-response "0.5.1"] is available but we use "0.5.0"
[metosin/ring-swagger "0.14.0"] is available but we use "0.13.0"
[lein-ring "0.8.13"] is available but we use "0.8.11"
:middlewares
broke route parameters:yaml-in-html
and :clojure
from default response formatsclojure.walk
ring-swagger
ring-swagger
hash-map
loses the order if it has enough properties(s/defschema Thingie (ordered-map :a String ...))
~~ring-swagger
:body
and others no langer take description as third param, instead use :body [body (describe Schema "The description")]
describe
works also for Java classes :query-params [x :- (describe Long "first-param")]
(s/defschema Schema {:sub (describe [{:x Long :y String}] "Array of stuff")})
500
instead of 400
, thanks to @phadej!(GET* "/plus" []
:return Long
:query-params [x :- Long {y :- Long 1}]
:summary "x+y with query-parameters. y defaults to 1."
(ok (+ x y)))
:responses
restructuring to (error) return codes and models, thanks to @phadej!(POST* "/number" []
:return Total
:query-params [x :- Long y :- Long]
:responses {403 ^{:message "Underflow"} ErrorEnvelope}
:summary "x-y with body-parameters."
(let [total (- x y)]
(if (>= total 0)
(ok {:total (- x y)})
(forbidden {:message "difference is negative"}))))
s/Uuid
via latest ring-swagger
.compojure.api.meta/restructure-param
:header-params
(fixes #31)[metosin/ring-swagger 0.10.2]
)
String
is supported as Ring doesn't support others
swagger
atom, there is one defined +routes+
var per namespace
compojure.api.core/with-routes
on api root to generate and hold the +routes+
(automatically bundled with defapi
)0.10.1
to get support for s/Keyword
as a nested schema key.middlewares
macro and :middlewares
restructuring now use thread-first to apply middlewares0.9.1
with support for vanilla schema.core/defschema
schemas
defroutes
to compojure.api.legacy
compojure.api.common
: ->Long
, fn->
, fn->>
compojure.api.meta/restructure
(doesn't generate empty lets
& letks
)compojure.api.legacy
ns to have the old Compojure HTTP-method macros (GET
, POST
,...)[prismatic/plumbing "0.3.1"] is available but we use "0.2.2"
[compojure "1.1.8"] is available but we use "1.1.7"
[prismatic/schema "0.2.3"] is available but we use "0.2.2"
[metosin/ring-swagger "0.8.8"] is available but we use "0.8.7"
[peridot "0.3.0"] is available but we use "0.2.2"
[metosin/ring-swagger "0.8.7"]
[metosin/ring-swagger-ui "2.6.16-2"]
updated dependencies:
[compojure "1.1.7"]
[prismatic/schema "0.2.2"]
[metosin/ring-swagger "0.8.5"]
consumes
and produces
are now feed to ring-swagger
based on the installed middlewares.
restructure-param
to receive key, value and the accumulator. Remove the key from accumulator parameters by default. No more alpha.meta
:middlewares
restructuring to support adding middlewares to routes: (DELETE* "/user/:id" []
:middlewares [audit-support (for-roles :admin)]
(ok {:name "Pertti"})))
with-middleware
is renamed to middlewares
& it applies middlewares in reverse orderclojure.walk16
internallyclojure.walk
to clojure.walk16
swagger
atom happens now at runtime, not compile-time. Works with AOT.compojure.api.core
restructuring are now using restructure-param
multimethod to allow external extensions. ALPHA.swaggered
resources are now collected in order+compojure-api-request+
when having both Compojure destructuring & Compojure-api destructuring in place:body-params
(with strict schema):(POST* "/minus" []
:body-params [x :- Long y :- Long]
:summary "x-y with body-parameters"
(ok {:total (- x y)}))
ring-swagger
to 0.8.4
to get better basepath-resolution (with reverse-proxies):path-parameters
and query-parameters
:(GET* "/sum" []
:query-params [x :- Long y :- Long]
:summary "sums x & y query-parameters"
(ok {:total (+ x y)}))
(GET* "/times/:x/:y" []
:path-params [x :- Long y :- Long]
:summary "multiplies x & y path-parameters"
(ok {:total (* x y)}))
swagger-ui
index-redirect work also under a context when running in an legacy app-server. Thanks to Juha Syrjälä for the PR.instanceof?
to match records instead of =
with class. Apps can now be uberwarred with lein ring uberwar
.ring-swagger
to 0.8.3
, generate path-parameters on client sidering-swagger
to 0.8.1
, all JSON-schema generation now done there.ring-http-response
to 0.4.0
compojure.api.core-integration-test
using peridot.core
(context "/api" []
(GET* ["/item/:name" :name #"[a-z/]+"] [name] identity))
GET*
and POST*
. Addeds tests to verify.ring-swagger
to 0.7.3
(GET* "/echo" []
:return Thingie
:query [thingie Thingie]
(ok thingie)) ;; here be coerced thingie
compojure.api.routes/defroutes
is now compojure.api.core/defroutes*
to avoid namespace clashes & promote it's different.compojure.api.core
web methods"compojure.api.core
.Ring-Swagger
to 0.7.2
json-response-support
, thanks to Dmitry BalakhonskiyRing-Swagger
to 0.7.1
giving support for nested Maps: (defmodel Customer {:id String
:address {:street String
:zip Long
:country {:code Long
:name String}}})
compojure.api.core
web methods does now automatic coercion for the bodycompojure.api.core
web methods (POST* "/customer"
:return Customer
:body [customer Customer]
(ok customer))) ;; we have a coerced customer here
ring-swagger
to 0.7.0
schema/maybe
and schema/both
Date
& DateTime
both with and without milliseconds: "2014-02-18T18:25:37.456Z"
& "2014-02-18T18:25:37Z"
swaggered
is stripped out of spaces.ring-swagger
to 0.6.0
swaggered
doesn't have to contain container-element (context
etc.) within, endpoints are ok: (swaggered "ping"
:description "Ping api"
(GET* "/ping" [] (ok {:ping "pong"})))
POST*
and PUT*
now allows model sequences: (POST* "/pizzas" []
:body [pizzas [NewPizza] {:description "new pizzas"}]
(ok (add! pizzas)))
ring-swagger
to 0.5.0
to get support for Data & DateTime.swaggered
can now follow symbols pointing to a compojure.api.routes/defroutes
route definition to allow better route composition.compojure.api.sweet
now uses compojure.api.routes/defroutes
instead of compojure.core/defroutes
Can you improve this documentation? These fine people already did:
Tommi Reiman, Juho Teperi, Miikka Koskinen & Daniel KwiecinskiEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close