CARVIEW |
Select Language
HTTP/2 200
date: Thu, 24 Jul 2025 00:25:32 GMT
content-type: text/html; charset=utf-8
vary: X-PJAX, X-PJAX-Container, Turbo-Visit, Turbo-Frame, X-Requested-With,Accept-Encoding, Accept, X-Requested-With
x-robots-tag: none
etag: W/"209f12640212d96ff479f005b880cc98"
cache-control: max-age=0, private, must-revalidate
strict-transport-security: max-age=31536000; includeSubdomains; preload
x-frame-options: deny
x-content-type-options: nosniff
x-xss-protection: 0
referrer-policy: no-referrer-when-downgrade
content-security-policy: default-src 'none'; base-uri 'self'; child-src github.githubassets.com github.com/assets-cdn/worker/ github.com/assets/ gist.github.com/assets-cdn/worker/; connect-src 'self' uploads.github.com www.githubstatus.com collector.github.com raw.githubusercontent.com api.github.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com *.rel.tunnels.api.visualstudio.com wss://*.rel.tunnels.api.visualstudio.com objects-origin.githubusercontent.com copilot-proxy.githubusercontent.com proxy.individual.githubcopilot.com proxy.business.githubcopilot.com proxy.enterprise.githubcopilot.com *.actions.githubusercontent.com wss://*.actions.githubusercontent.com productionresultssa0.blob.core.windows.net/ productionresultssa1.blob.core.windows.net/ productionresultssa2.blob.core.windows.net/ productionresultssa3.blob.core.windows.net/ productionresultssa4.blob.core.windows.net/ productionresultssa5.blob.core.windows.net/ productionresultssa6.blob.core.windows.net/ productionresultssa7.blob.core.windows.net/ productionresultssa8.blob.core.windows.net/ productionresultssa9.blob.core.windows.net/ productionresultssa10.blob.core.windows.net/ productionresultssa11.blob.core.windows.net/ productionresultssa12.blob.core.windows.net/ productionresultssa13.blob.core.windows.net/ productionresultssa14.blob.core.windows.net/ productionresultssa15.blob.core.windows.net/ productionresultssa16.blob.core.windows.net/ productionresultssa17.blob.core.windows.net/ productionresultssa18.blob.core.windows.net/ productionresultssa19.blob.core.windows.net/ github-production-repository-image-32fea6.s3.amazonaws.com github-production-release-asset-2e65be.s3.amazonaws.com insights.github.com wss://alive.github.com api.githubcopilot.com api.individual.githubcopilot.com api.business.githubcopilot.com api.enterprise.githubcopilot.com; font-src github.githubassets.com; form-action 'self' github.com gist.github.com copilot-workspace.githubnext.com objects-origin.githubusercontent.com; frame-ancestors 'none'; frame-src viewscreen.githubusercontent.com notebooks.githubusercontent.com; img-src 'self' data: blob: github.githubassets.com media.githubusercontent.com camo.githubusercontent.com identicons.github.com avatars.githubusercontent.com private-avatars.githubusercontent.com github-cloud.s3.amazonaws.com objects.githubusercontent.com release-assets.githubusercontent.com secured-user-images.githubusercontent.com/ user-images.githubusercontent.com/ private-user-images.githubusercontent.com opengraph.githubassets.com copilotprodattachments.blob.core.windows.net/github-production-copilot-attachments/ github-production-user-asset-6210df.s3.amazonaws.com customer-stories-feed.github.com spotlights-feed.github.com objects-origin.githubusercontent.com *.githubusercontent.com; manifest-src 'self'; media-src github.com user-images.githubusercontent.com/ secured-user-images.githubusercontent.com/ private-user-images.githubusercontent.com github-production-user-asset-6210df.s3.amazonaws.com gist.github.com; script-src github.githubassets.com; style-src 'unsafe-inline' github.githubassets.com; upgrade-insecure-requests; worker-src github.githubassets.com github.com/assets-cdn/worker/ github.com/assets/ gist.github.com/assets-cdn/worker/
server: github.com
content-encoding: gzip
accept-ranges: bytes
set-cookie: _gh_sess=%2FxRT6Ese9PJ%2FdrNMKoViQxR2h%2FEL8IPZElUhAdNlV1Ch5jtMYfjPkcHOR%2B8skr9aagNNsZZUgD6rDMXi4UqDHlAdG6%2F2hRSKWbLmNqSVSWrqrfUpWXxJPg0kORgwgpEfbedUK2QGpX1dmcLLO2RQ9qnMij3rxWi46CEPmCVMdeBSCH10Z8JCebN6fTu%2BbP3jq7wjxUs880Lf8MAji0tWZJPSElbvgsMWwpMSgSuqxm84sxWAymmU01RIkvhrNBM0ITxIXwe9H%2FFBvf%2FASz3aZA%3D%3D--bFd8P03%2BaSMwHQnG--Cka4PTYoXQdor27K0tJtag%3D%3D; Path=/; HttpOnly; Secure; SameSite=Lax
set-cookie: _octo=GH1.1.361236837.1753316731; Path=/; Domain=github.com; Expires=Fri, 24 Jul 2026 00:25:31 GMT; Secure; SameSite=Lax
set-cookie: logged_in=no; Path=/; Domain=github.com; Expires=Fri, 24 Jul 2026 00:25:31 GMT; HttpOnly; Secure; SameSite=Lax
x-github-request-id: B5E8:221257:1C390A:27A909:68817D7B
Resources and Liberator · metosin/compojure-api Wiki · GitHub
Skip to content
Navigation Menu
{{ message }}
-
Notifications
You must be signed in to change notification settings - Fork 150
Resources and Liberator
Marcin Kulik edited this page Jan 8, 2017
·
4 revisions
Compojure-api also allows http-endpoints to be modeled as data-driven resources, using enhanced Ring-Swagger resource definitions. Resources might be good in the following cases:
- Wanting to add swagger-docs and/or schema-based coercion to your existing resource-based apis, like the Liberator.
- Generate endpoints based on external data, e.g.
- generate REST or CRUD-apis from (database) entity definitions
- generate RPC-apis from function/data definitions
Resources are created with function compojure.api.resource/resource
, which is also imported in the compojure.api.sweet
namespace. Both request & response coercion can be disabled for resources, so that they can be used just to generate swagger-docs on top of existing/legacy apis.
Resources are routed with context
.
(context "/hello" []
:middleware [[require-role :admin]]
(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)}))}}))
(defn resource
"Creates a nested compojure-api Route from enhanced 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.
Enhancements 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.
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))))
(resource
{:handler (constantly (ok "hello world"))})
(resource
{:description "shared description, can be overridden"
:parameters {:path-params {:id Long}}
:get {:description "get user"
:summary "get-user ftw!"
:handler get-user}
:put {:parameters {:body-params User}
:responses {200 {:schema User}}
:handler modify-user}
:delete {:description "delete's a user"
:handler delete-user}
:handler (constantly
(internal-server-error
{:reason "other methods not implemented"}))})
Inlined (as a closure):
(context "/plus" []
:middleware [require-admin]
(resource
{:get {:parameters {:query-params {:x Long, :y Long}}
:responses {200 {:schema {:total Long}}}
:handler my-plus-request-handler-with-coerced-inputs-and-outputs}}))
Predefined (bit faster):
(def plus-resource
(resource
{:get {:parameters {:query-params {:x Long, :y Long}}
:responses {200 {:schema {:total Long}}}
:handler my-plus-request-handler-with-coerced-inputs-and-outputs}}))
(context "/plus" []
:middleware [require-admin]
plus-resource)
- https://github.com/metosin/compojure-api/tree/master/examples/resources
- https://github.com/metosin/compojure-api/tree/master/examples/reusable-resources
- set the Liberator resource as top-level handler
- return raw responses to enable response coercion via
:as-response
orring-response
, see the guide - read the coerced parameters from the liberator context:
(get-in ctx [:request :body-parameters])
- optionally disable coercion on resource just to get just swagger-docs
(def user-resource
(resource
{:parameters {:path-params {:id Long}}
:get {:parameters {:query-params {(s/optional-key :fields) [String]}}
:responses {200 {:schema User}}
:summary "returns a User (or fields of it)"}
:put {:parameters {:body-params User}
:responses {200 {:schema User}}
:summary "Updates a user"}
:delete {:summary "Deletes a user"}
:handler my-liberator-resource}
;; add this if you just want the swagger-docs
{:coercion (constantly nil)}))
(context "/user" []
user-resource)
Feel free to update this guide. Initial discussion here.
You can’t perform that action at this time.