{"id":29095419,"url":"https://github.com/whostolebenfrog/rest-cljer","last_synced_at":"2025-06-28T11:02:11.507Z","repository":{"id":4890464,"uuid":"6045970","full_name":"whostolebenfrog/rest-cljer","owner":"whostolebenfrog","description":"A clojure wrapper for the rest driver library","archived":false,"fork":false,"pushed_at":"2018-03-13T09:33:02.000Z","size":114,"stargazers_count":37,"open_issues_count":2,"forks_count":15,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-05-22T00:25:59.078Z","etag":null,"topics":["clojure","clojure-wrapper","mocking","rest-cljer","rest-driver","testing"],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/whostolebenfrog.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-10-02T14:21:14.000Z","updated_at":"2024-05-31T07:56:30.000Z","dependencies_parsed_at":"2022-08-18T00:11:03.510Z","dependency_job_id":null,"html_url":"https://github.com/whostolebenfrog/rest-cljer","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/whostolebenfrog/rest-cljer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whostolebenfrog%2Frest-cljer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whostolebenfrog%2Frest-cljer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whostolebenfrog%2Frest-cljer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whostolebenfrog%2Frest-cljer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/whostolebenfrog","download_url":"https://codeload.github.com/whostolebenfrog/rest-cljer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whostolebenfrog%2Frest-cljer/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262377446,"owners_count":23301449,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","clojure-wrapper","mocking","rest-cljer","rest-driver","testing"],"created_at":"2025-06-28T11:01:21.216Z","updated_at":"2025-06-28T11:02:11.457Z","avatar_url":"https://github.com/whostolebenfrog.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rest-cljer [![Build Status](https://travis-ci.org/whostolebenfrog/rest-cljer.svg?branch=master)](https://travis-ci.org/whostolebenfrog/rest-cljer)\n\nRest-cljer is a library that allows *real* mocking of http rest calls. It starts a server to listen for your requests and returns real http responses to those requests. It allows you to test your services in isolation from one another whilst actually exercising your service's code. As such it allows the service to be tested from a separate process.\n\nA typical test scenario would be to switch out your service's dependencies to point to `:restdriver-port` on localhost and then use rest-cljer to mock the responses. Rest-cljer can use [environ](https://github.com/weavejester/environ) to determine `:restdriver-port`, so you can set your chosen port via a system property or environment variable.\n\nRest-cljer is a Clojure wrapper for [rest-driver](https://github.com/rest-driver/rest-driver).\n\n## Usage\n\nImport from [clojars](https://clojars.org/rest-cljer) with:\n\n```clj\n[rest-cljer \"0.2.2\"]\n```\n\nthen\n\n```clj\n(:require [rest-cljer.core :refer [rest-driven]])\n```\n\nAn example of clojure test usage (using environ to set `:rest-driver-port` to 8081):\n\n```clj\n(deftest example-of-a-test\n  (rest-driven [{:method :GET :url \"/gety\"}\n                {:status 200}]\n    (is (= 200 (:status (http/get \"http://localhost:8081/gety\"))))))\n```\n\nAn example using a random port:\n\n```clj\n(deftest example-of-a-test\n  (rest-driven [{:method :GET :url \"/gety\"}\n                {:status 200}]\n    (is (= 200 (:status (http/get (str \"http://localhost:\" *rest-driver-port* \" /gety\")))))))\n```\n\nAn example of midje usage.\n\n```clj\n(fact \"Example of testing two\"\n      (rest-driven\n          [{:method :GET :url \"/gety\"}\n           {:type :JSON :status 200}\n\n           {:method :GET :url \"/something\"}\n           {:type :JSON :status 200}]\n\n          (client/get \"http://localhost:8081/gety\") =\u003e (contains {:status 200})\n          (client/get \"http://localhost:8081/something\") =\u003e (contains {:status 200})))\n```\n\nWrap your test with the `(rest-driven)` macro.\n\nThis expects params in the form of a vector of pairs of maps followed by a body form that is your test.\n\nThe two maps correspond to a request and response (in that order). The request tells us what request to expect and the response map describes the response.\n\nAnother example:\n\n```clj\n(fact \"User history is posted to scrobbling\"\n       (rest-driven\n           [{:method :POST :url \"/events\"\n             :body [(Pattern/compile \"\\\\{.*\\\"userid\\\":\\\"userid\\\".*\\\\}\")\n                    \"application/json\"]}\n            {:type :JSON :status 202}]\n\n           (let [response (client/post ...snip...)]\n\n             response =\u003e (contains {:status 202}))))\n```\n\nEach pair may be enclosed in a vector if you like:\n\n```clj\n(fact \"Expectations as nested vectors\"\n       (rest-driven\n           [[{:method :GET :url \"/events\"} {:type :JSON :status 200}]\n            [{:method :GET :url \"/events\"} {:type :JSON :status 201}]]\n\n             (client/get url) =\u003e (contains {:status 200})\n             (client/get url) =\u003e (contains {:status 201})))\n```\n\nYou can also specific a map as the body of the request, thereby asserting that the right content is sent:\n\n```clj\n(fact \"I want to know my code is sending out the right information\"\n       (rest-driven\n           [{:method :POST :url \"/downstream\"\n             :body {:information \"yes,please\"}\n            {:type :JSON :status 202}]\n\n           (let [response (client/post {:body (json-str {:infomation \"yes,please\"}) :content-type :json]\n\n             response =\u003e (contains {:status 202}))))\n```\n\nThe body can also be a regex or a string along with a content type, specified as a two-valued vector:\n\n```clj\n        :body [\"a string\" \"text/plain\"]\n        \n        :body [#\"a regex\" \"someothercontent/type\"]\n```\n\nThe body can also be a predicate, or a two-valued vector with predicate and content-type. If the content-type is not set or set to \"application/json\" the body will be coerced into clojure format and then applied to the predicate.\n\n```clj\n        :body [#(= \"a string\" %) \"text/plain\"]\n        \n        :body :foo\n```\n\nIf you need to inspect the details of a request you can create a string-capture and analyse the details later:\n\n```clj\n(fact \"I want to capture the body of a request for further inspection\"\n      (let [capturer (string-capture)]\n        (rest-driven [{:method :POST :url resource-path\n                       :body [\"somethingstrange\" \"text/plain\"]\n                       :capture capturer}\n                      {:status 204}]\n                     (post url {:content-type \"text/plain\"\n                                :body \"somethingstrange\"\n                                :throw-exceptions false}) =\u003e (contains {:status 204})\n                     (capturer) =\u003e \"somethingstrange\")))\n```\n\nThere is also some sweetening of response definitions, like so:\n\n```clj\n(rest-driven [{:method :GET :url resource-path}\n                      {:body {:inigo \"montoya\"}}]\n                     (let [resp (http/get url)]\n                       resp =\u003e (contains {:status 200})\n                       (:headers resp) =\u003e (contains {\"content-type\" \"application/json\"})\n                       (json/read-str (:body resp) :key-fn keyword) =\u003e {:inigo \"montoya\"}))\n```\n\n\nRequest map params:\n\n    :method  -\u003e :GET :POST :PUT :DELETE :TRACE :HEAD :OPTIONS or a more unusual method as a string,\n                for example \"PATCH\", \"PROPFIND\" (defaults to :GET if not supplied)\n    :params  -\u003e a map of expected request params in the form {\"name\" \"value\"} or {:name \"value\"}\n                that would match ?name=value\n                alternatively use :any to match any params\n    :body    -\u003e a map that should match the body of the request or a predicate or a vector containing \n                a string/predicate/regex plus the content type.\n    :url     -\u003e a string or regex that should match the url\n    :headers -\u003e a map of headers that are expected on the incoming request where\n                keys are header names and values are header values.\n    :capture -\u003e an instance created using the string-capture function which captures the body\n                of the request as a string for later inspection.\n    :and     -\u003e a function that will receive a ClientDriverRequest and can apply\n                additional rest-driver setup steps that aren't explicitly supported\n                by rest-cljer.\n    :not     -\u003e a map of request params that will NOT appear in the request. Currently\n                only :headers is supported (i.e. to match against a header NOT appearing in the request).\n                :headers should be specified as a vector of strings, although a deprecated approach is\n                to specify a map where keys are header names and values are header values (which can be \n                any value).\n\nResponse map params:\n\n    :type    -\u003e :JSON (application/json) :XML (text/xml) :PLAIN (text/plain) or any other\n                string representing a valid media type (e.g. text/html)\n    :status  -\u003e the response status as a number\n    :body    -\u003e the response body as string, byte array or input stream\n    :headers -\u003e a map of headers that will be added to the response (where key is\n                header name and value is header value).\n    :and     -\u003e a function that will receive a ClientDriverResponse and can apply\n                additional rest-driver setup steps that aren't explicitly supported\n                by rest-cljer.\n    :times   -\u003e for repeating responses, the number of times a matching request will\n                be given this response (use :times :any to use this response for an\n                unlimited number of matching requests).\n    :after   -\u003e return respone after a sepecified number of milliseconds \n                (e.g. :after 1000 will return call after 1 second).\n\n## License\n\nDistributed under the Eclipse Public License, the same as Clojure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwhostolebenfrog%2Frest-cljer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwhostolebenfrog%2Frest-cljer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwhostolebenfrog%2Frest-cljer/lists"}