Skip to content

Instantly share code, notes, and snippets.

@verma
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save verma/a15dea0689089e1287e3 to your computer and use it in GitHub Desktop.
Save verma/a15dea0689089e1287e3 to your computer and use it in GitHub Desktop.
Blog post

JSON Web Services with Clojure

Less reading more coding.

All code for this exercise is available here.

Setup a project

lein new compojure api-test

This sets up api-test with a basic compojure template.

Add some deps

 ;; project.clj
 ...
 :dependencies [[org.clojure/clojure "1.6.0"]
                [ring/ring-json "0.3.1"]
                [compojure "1.1.8"]]

Make sure stuffs there

 lein deps

or install deps and run server at the same time:

 lein ring server

Add JSON middleware

Change your app definition to include the required middleware (make sure you require the middleware as well):

(ns api-test.handler
  (:require [compojure.core :refer :all]
            [compojure.handler :as handler]
            [ring.middleware.json :as middleware]
            [compojure.route :as route]))

;; ...

(def app
  (-> (handler/site app-routes)
      (middleware/wrap-json-body {:keywords? true})
      middleware/wrap-json-response))

The {:keywords? true} above makes sure that when my body is parsed, I get my keys as keywords and not as strings.

Write a handler

You get two things out of doing all this so far:

  1. All json request bodies are parsed into nice looking maps for your convinience.
  2. Response bodies can now be maps as well, which will be converted into JSON before they're put on the wire.

Lets write the handler (just look at the POST "/" stuff):

(defroutes app-routes
  (POST "/" request
        (let [name (or (get-in request [:params :name])
                       (get-in request [:body :name])
                       "John Doe")]
          {:status 200
           :body {:name name
                  :desc (str "The name you sent to me was " name)}}))
  (route/resources "/")
  (route/not-found "Not Found"))

First it figures the name of the sender, it could be either in params, the body or defaults to "John Doe" (see how nicely you can query the body here for things).

;; ...
{:status 200
 :body {:name name
        :desc (str "The name you sent to me was " name)}}

This is how you generate your body now, just a simple clojure map.

Test it

Lets check it out in console:

$ curl -X POST http://localhost:3000/ \
--data '{"name":"verma"}' --header "Content-type:application/json"
{"name":"verma","desc":"The name you sent to me was verma"}

$ curl -X POST --data 'name=verma' http://localhost:3000/
{"name":"verma","desc":"The name you sent to me was verma"}

$ curl -X POST  http://localhost:3000/
{"name":"John Doe","desc":"The name you sent to me was John Doe"}

Until next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment