Hi everyone,

 

I'm very excited to introduce *Martian*, a Clojure/script HTTP client 
wrapper which simplifies HTTP calls without surrendering control to an 
opaque library.

Find it on Github and Clojars now: https://github.com/oliyh/martian

 

It uses Swagger descriptions to name operations, map parameters to form the 
request map and serialise it as efficiently as possible, and is built using 
pedestal's interceptor concept making it composable and extensible.

 

You can use your favourite HTTP client, with implementations provided for 
httpkit, clj-http and cljs-http and extend behaviour any way you wish by 
providing your own interceptors to the chain. The following example shows 
how simple it can be to make HTTP calls to a Swagger API:

 

(require '[martian.core :as martian]

         '[martian.clj-http :as martian-http])

 

(let [m (martian-http/bootstrap-swagger 
"https://pedestal-api.herokuapp.com/swagger.json";)]

  (martian/response-for m :create-pet {:name "Doggy McDogFace" :type "Dog" :age 
3})

  ;; => {:status 201 :body {:id 123}}

 

  (martian/response-for m :get-pet {:id 123}))

  ;; => {:status 200 :body {:name "Doggy McDogFace" :type "Dog" :age 3}}

 

Martian offers a pure client with no server code or dependency, no compile 
time dependencies on the API, is cross platform, allows you full access to 
the request and response data and your own choice of HTTP library.

 

Using Swagger descriptions allows Martian to apply runtime schema checks to 
the parameters you send in requests and even provide dummy implementations 
that return generated responses instead of calling a real server. This 
opens up areas of code that would previously be difficult to test and makes 
them fully transparent.

 

As well as performing requests and returning the response, Martian lets you 
explore APIs, build URLs and request maps without executing them. 

 

(require '[martian.core :as martian]

         '[martian.clj-http :as martian-http])

 

;; bootstrap the martian instance by simply providing the url serving the 
swagger description

(let [m (martian-http/bootstrap-swagger 
"https://pedestal-api.herokuapp.com/swagger.json";)]

 

  ;; explore the endpoints

  (martian/explore m)

  ;; => [[:get-pet "Loads a pet by id"]

  ;;     [:create-pet "Creates a pet"]]

 

  ;; explore the :get-pet endpoint

  (martian/explore m :get-pet)

  ;; => {:summary "Loads a pet by id"

  ;;     :parameters {:id s/Int}}

 

  ;; build the url for a request

  (martian/url-for m :get-pet {:id 123})

  ;; => https://pedestal-api.herokuapp.com/pets/123

 

  ;; build the request map for a request

  (martian/request-for m :get-pet {:id 123})

  ;; => {:method :get

  ;;     :url "https://pedestal-api.herokuapp.com/pets/123";

  ;;     :headers {"Accept" "application/transit+msgpack"

  ;;     :as :byte-array}

 

If you need to add your own behaviour it's easy - the interceptor pattern 
lets you add your own interceptors to decorate requests before they are 
sent and process the responses when they come back, as shown in this 
example:

 

(require '[martian.core :as martian]

         '[martian.clj-http :as martian-http])

 

(def add-authentication-header

  {:name ::add-authentication-header

   :enter (fn [ctx]

            (assoc-in ctx [:request :headers "Authorization"] "Token: 
12456abc"))})

 

(def request-timer

  {:name ::request-timer

   :enter (fn [ctx]

            (assoc ctx ::start-time (System/currentTimeMillis)))

   :leave (fn [ctx]

            (->> ctx ::start-time

                 (- (System/currentTimeMillis))

                 (format "Request to %s took %sms" (get-in ctx [:handler 
:route-name]))

                 (println))

            ctx)})

 

(let [m (martian-http/bootstrap-swagger

               "https://pedestal-api.herokuapp.com/swagger.json";

               {:interceptors (concat martian/default-interceptors

                                      [add-authentication-header

                                       martian-http/encode-body

                                       (martian-http/coerce-response)

                                       request-timer

                                       martian-http/perform-request])})]

 

        (martian/response-for m :all-pets {:id 123}))

        ;; Request to :all-pets took 38ms

        ;; => {:status 200 :body {:pets []}}

 

Martian can even be used for endpoints that don't have Swagger definitions 
if you describe them yourself in the Swagger format. There'll be more on 
this in future updates.

 

There are more examples and use cases on the Github README 
https://github.com/oliyh/martian

The project is new so any feedback is very welcome, including pull requests 
and issues on Github.

 

I hope you find it useful!

Oliy

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to