Clojure is a functional programming language that runs on the Java Virtual Machine (JVM). It’s known for its concise syntax, immutability, and powerful concurrency support. It’s a great choice for building web applications, and it’s often used to create RESTful APIs.
In this blog post, we’ll explore how to write a REST API in Clojure using the popular Ring and Compojure libraries.
Setting up the project
To get started, we need to set up a new project. We’ll use Leiningen, a popular build tool for Clojure projects.
1 | lein new app my-api |
This command will create a new directory called my-api
with a basic Clojure project structure.
Next, we need to add the dependencies for Ring and Compojure to our project. We’ll add these to the project.clj
file in the root of our project.
1 2 3 4 5 | (defproject my-api "0.1.0-SNAPSHOT" :dependencies [[org.clojure/clojure "1.10.3"] [compojure "1.6.2"] [ring/ring-core "1.10.3"] [ring/ring-jetty-adapter "1.10.3"]]) |
We also need to create a handler.clj
file in the src/my_api
directory. This file will contain the code for our API.
Creating routes
Now that we have our project set up, let’s create some routes for our API. We’ll use Compojure to define our routes.
1 2 3 4 5 | (ns my-api.handler (:require [compojure.core :refer :all] [ring.util.response :refer :all])) (defroutes app-routes (GET "/hello" [] "Hello, World!")) (def app (wrap-defaults app-routes site-defaults)) |
In this code, we’re defining a single route that responds with “Hello, World!” when we make a GET request to /hello
. We’re also wrapping our routes with some default middleware provided by Ring.
Starting the server
To start our API, we need to create a Jetty server and pass in our routes.
1 2 3 4 | (ns my-api.core (:require [my-api.handler :as handler] [ring.adapter.jetty :refer :all])) (defn -main [] (let [port (Integer. (get (System/getenv) "PORT" "3000"))] (run-jetty handler/app {:port port}))) |
In this code, we’re starting a Jetty server on port 3000 (or whatever port is provided by the PORT
environment variable). We’re passing in our app
function from the handler
namespace.
Testing our API
Now that we have our API set up and running, we can test it using a tool like cURL or HTTPie.
1 2 3 | $ http :3000/hello HTTP/1.1 200 OK Content-Length: 13 Content-Type: text/html;charset=utf-8 Date: Wed, 02 Mar 2022 22:04:23 GMT Server: Jetty(9.4.43.v20210629) Hello, World! |
1 | bashCopy code<code>$ http :3000/hello HTTP/1.1 200 OK Content-Length: 13 Content-Type: text/html;charset=utf-8 Date: Wed, 02 Mar 2022 22:04:23 GMT Server: Jetty(9.4.43.v20210629) Hello, World! |
And that’s it! We’ve successfully created a simple REST API using Clojure, Ring, and Compojure. From here, we can add more routes and functionality to our API as needed.