I don't think you need a macro here.  In any case, I'd avoid using a macro
as late as possible.  See how far you get with just functions, and then
maybe at the end, add one macro if you absolutely need it to add just a
touch of syntactic sugar.

routes should clearly be some sort of data-structure, rather than
side-effect setter functions.  Maybe this:

(with-fake-routes!
  optional-server-instance
  route-map)


Where optional-server-instance, if it exists is, an object returned by (
fake-server/start!).  If optional-server-instance is not passed in,
then with-fake-routes!
creates it's own and is free to call (shutdown!) on it automatically. And
route-map is a Map of routes:

{
"/x"
  {:status 200 :content-type "application/json" :body (slurp (io/resource
"my.json"))}
{:path "/y" :query {:q "something")}}
  {:status 200 :content-type "application/json" :body (slurp (io/resource
"my2.json"))}
}


Also, at the risk of scope creep, I could foresee wanting the response to
be based on the input instead of just a static blob.  So maybe the value of
:body could be a string or a function of 1 arg, the route-- in your code
test with (fn?).

This gives you a single api, no macros, optional auto-server start/stop or
explicit server management.

marc


On Tue, Mar 8, 2016 at 3:10 AM, Johan Haleby <johan.hal...@gmail.com> wrote:

> Hi,
>
> I've just committed an embryo of an open source project
> <https://github.com/johanhaleby/fake-http> to fake http requests by
> starting an actual (programmable) HTTP server. Currently the API looks like
> this (which in my eyes doesn't look very Clojure idiomatic):
>
> (let [fake-server (fake-server/start!)
>         (fake-route! fake-server "/x" {:status 200 :content-type 
> "application/json" :body (slurp (io/resource "my.json"))})
>         (fake-route! fake-server {:path "/y" :query {:q "something")}} 
> {:status 200 :content-type "application/json" :body (slurp (io/resource 
> "my2.json"))})]
>         ; Do actual HTTP request
>          (shutdown! fake-server))
>
>
> fake-server/start! starts the HTTP server on a free port (and thus have
> side-effects) then you add routes to it by using fake-route!. The first
> route just returns an HTTP response with status code 200 and content-type
> "application/json" and the specified response body if a request is made
> with path "/x". The second line also matches that a query parameter called
> "q" must be equal to "something. In the end the server is stopped.
>
> I'm thinking of converting all of this into a macro that is used like this:
>
> (with-fake-routes!
> "/x" {:status 200 :content-type "application/json" :body (slurp
> (io/resource "my.json"))}
> {:path "/y" :query {:q "something")}} {:status 200 :content-type
> "application/json" :body (slurp (io/resource "my2.json"))})
>
> This looks better imho and it can automatically shutdown the webserver
> afterwards but there are some potential problems. First of all, since
> starting a webserver is (relatively) slow it you might want to do this once
> for a number of tests. I'm thinking that perhaps as an alternative (both
> options could be available) it could be possible to first start the
> fake-server and then supply it to with-fake-routes! as an additional
> parameter. Something like this:
>
> (with-fake-routes!
>         fake-server ; We pass the fake-server as the first argument in
> order to have multiple tests sharing the same fake-server
> "/x" {:status 200 :content-type "application/json" :body (slurp
> (io/resource "my.json"))}
>  {:path "/y" :query {:q "something")}} {:status 200 :content-type
> "application/json" :body (slurp (io/resource "my2.json"))})
>
> If so you would be responsible for shutting it down just as in the initial
> example.
>
> Another thing that concerns me a bit with the macro is that routes doesn't
> compose. For example you can't define the route outside of the 
> with-fake-routes!
> body and just supply it as an argument to the macro (or can you?). I.e. I
> think it would be quite nice to be able to do something like this:
>
> (let [routes [["/x" {:status 200 :content-type "application/json" :body
> (slurp (io/resource "my.json"))}]
>               [{:path "/y" :query {:q "something")}} {:status 200
> :content-type "application/json" :body (slurp (io/resource "my2.json"))}]]]
>      (with-fake-routes routes))
>
> Would this be a good idea? Would it make sense to have overloaded variants
> of the with-fake-routes! macro to accommodate this as well? Should it be
> a macro in the first place? What do you think?
>
> Regards,
> /Johan
>
> --
> 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.
>

-- 
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