A Clojure library designed to stub HTTP responses regardless of which client library that is used to make the actual HTTP requests.
There are several client specific "http mocking/stubbing/faking" libraries out there such as clj-http-fake and ring-mock but they work on the level of the library and not the HTTP level. I couldn't find a client agnostic library for stubbing HTTP endpoints so I sat out to write one myself based on nanohttpd. This is useful if you want to test your app against a real HTTP server with actual HTTP requests. And even if you don't want to this it may be your only option if you're (for example) using a Java library that makes HTTP requests and you want to stub/fake its responses.
The latest release version of stub-http is hosted on Clojars:
(ns x.y
(:require [stub-http.core :refer :all]))
(with-routes!
{"/something" {:status 200 :content-type "application/json" :body (json/generate-string {:hello "world"}) :delay 1000 :counter (atom 0)}
{:path "/y" :query-params {:q "something"}} {:status 200 :content-type "application/json" :body (json/generate-string {:hello "brave new world"})}}
; Do actual HTTP request
)
Example demonstrating integration with clojure test and clj-http-lite. This example matches path "/something" and returns the json document
{ "hello" : "world" }
as response:
(ns stub-http.example1
(:require [clojure.test :refer :all]
[stub-http.core :refer :all]
[cheshire.core :as json]
[clj-http.lite.client :as client]))
(deftest Example1
(with-routes!
{"/something" {:status 200 :content-type "application/json"
:body (json/generate-string {:hello "world"})}}
(let [response (client/get (str uri "/something"))
json-response (json/parse-string (:body response) true)]
(is (= "world" (:hello json-response))))))
This example matches only a GET request with a query param "name" equal "value" using the start!
function:
(ns stub-http.example2
(:require [clojure.test :refer :all]
[stub-http.core :refer :all]
[cheshire.core :as json]
[clj-http.lite.client :as client]))
(declare ^:dynamic *stub-server*)
(defn start-and-stop-stub-server [f]
(binding [*stub-server* (start! {{:method :get :path "/something" :query-params {:name "value"}}
{:status 200 :content-type "application/json" :body (json/generate-string {:hello "world"})}})]
(try
(f)
(finally
(.close *stub-server*)))))
(use-fixtures :each start-and-stop-stub-server)
(deftest Example2
(let [response (client/get (str (:uri *stub-server*) "/something"))
json-response (json/parse-string (:body response) true)]
(is (= "world" (:hello json-response)))))
The start!
function return a Clojure record that implements Closeable.
This means that you can use it with the with-open macro:
(ns stub-http.example3
(:require [clojure.test :refer :all]
[stub-http.core :refer :all]
[cheshire.core :as json]
[clj-http.lite.client :as client]))
(deftest Example3
(with-open [server (start! {"/something" {:status 200 :content-type "application/json"
:body (json/generate-string {:hello "world"})}})]
(let [response (client/get (str (:uri server) "/something"))
json-response (json/parse-string (:body response) true)]
(is (= "world" (:hello json-response)))))
The project is in an early phase and some changes are to be expected.
Copyright (c) 2022 Johan Haleby
Released under the MIT License.