This is a set of middlewares that can be used to deserialize parameters sent in the :body of requests and serialize a Clojure data structure in the :body of a response to some string representation. It natively handles JSON, YAML, and Clojure but it can easily be extended to other custom formats. It is intended for the creation of RESTful APIs that do the right thing by default but are flexible enough to handle most special cases.
To get automatic deserialization and serialization for all supported formats with sane defaults regarding headers and charsets, just do this:
(ns my.app
(:use [ring.middleware.format-params :only [wrap-restful-params]]
[ring.middleware.format-response :only [wrap-restful-response]])
(:require [compojure.handler :as handler]))
(defroutes main-routes
...)
(def app
(-> (handler/api main-routes)
(wrap-restful-params)
(wrap-restful-response)))
Your routes should return raw clojure data structures where everything inside can be handled by the default encoders (no Java objects or fns mostly). If a route returns a String, File or InputStream, nothing will be done. If no format can be deduced from the Accept header, JSON will be sent back by default. However, if the formats specified by the request Accept header are unknown, the middleware will respond with a 406
status instead.
These middlewares are mostly lifted from https://github.com/mmcgrana/ring-json-params but generalized for arbitrary decoders. The wrap-json-params is drop-in replacement for ring-json-params. They will decode the params in the request body, put them in a :body-params key and merge them in the :params key. There are three default wrappers:
- wrap-json-params
- wrap-yaml-params
- wrap-clojure-params
There is also a generic wrap-format-params on which the others depend. Each of these wrappers take 3 optional args: :decoder, :predicate and :charset. See wrap-format-params doc for further details.
These middlewares will take a raw data structure returned by a route and serialize it in various formats.
There are four default wrappers:
- wrap-json-response
- wrap-yaml-response
- wrap-yaml-in-html-response (responds to text/html MIME type and useful to test an API in the browser)
- wrap-clojure-response
There is also a generic wrap-format-response on which the others depend. Each of these wrappers take 3 optional args: :encoders, :predicate, and :charset. See wrap-format-response doc for further details.
You can implement custom formats in two ways:
- If you want to slightly modify an existing wrapper you can juste pass it an argument to overload the default. For exemple, this will cause all json formatted responses to be encoded in iso-latin-1:
(-> handler
(wrap-json-response :charset "ISO-8859-1"))
- You can implement the wrapper from scratch by using both wrap-format-params and wrap-format-response. For now, see the docs of each and how the others format were implemented for help doing this.
This module aims to be both easy to use and easy to extend to new formats. However, it does not try to help with every apect of building a RESTful API, like proper error handling and method dispatching. If that is what you are looking for, you could check the modules which function more like frameworks:
- https://github.com/malcolmsparks/plugboard
- https://github.com/banjiewen/Clothesline
- https://github.com/myfreeweb/ringfinger
- Some form of extensible error handling
Copyright (C) 2011 Nils Grunwald
Distributed under the Eclipse Public License, the same as Clojure.