On Wed, Mar 9, 2016 at 6:20 AM, Johan Haleby <johan.hal...@gmail.com> wrote:

> Thanks for your feedback, exactly what I wanted.
>
> On Tuesday, March 8, 2016 at 3:16:02 PM UTC+1, mlimotte wrote:
>>
>> 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)
>>
>>
Hmm now that I come to think of it I don't see how this would actually work
unless you also perform the HTTP request from inside the scope of
with-fake-routes!,
otherwise the server instance would be closed before you get the chance to
make the request. Since you make an actual HTTP request you need access to
the URI generated when starting the fake-server instance (at least if the
port is chosen randomly). So either I suppose you would have to do like
this (which requires a macro?):

(with-fake-routes!
  {"/x" {:status 200 :content-type "application/json" :body (slurp
(io/resource "my.json"))}}
  ; Actual HTTP request
  (http/get uri "/x"))

where "uri" is created by the  with-fake-routes! macro *or* we could return
the generated fake-server. But if so with-fake-routes! cannot automatically
close the fake-server instance since we need the instance to be alive when
we make the call to the generated uri. I suppose it would have to look
something like this:

(let [fake-server (with-fake-routes! {"/x" {:status 200 :content-type
"application/json" :body (slurp (io/resource "my.json"))}})]
(http/get (:uri fake-server) "/x")
(shutdown! fake-server))

If so I think that the second option is unnecessary since then you might
just go with:

(with-fake-routes!
  *required*-server-instance
  route-map)

instead of having two options. But then we loose the niceness of having the
server instance be automatically created and stopped for us?


>> 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"))}
>> }
>>
>>
> +1. I'm gonna go for this option.
>
>
>>
>> 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?).
>>
>
> That's a good idea indeed. I've already thought about this for matching
> the request. I'd like this to work:
>
> {
>  (fn [request] (= (:path request) "/x"))
>   {:status 200 :content-type "application/json" :body (slurp (io/resource
> "my.json"))}
> {:path "/y" :query {:q (fn [q] (clojure.string/starts-with? q "some"))}}
>   {:status 200 :content-type "application/json" :body (slurp (io/resource
> "my2.json"))}
> }
>
> Thanks a lot for your help and feedback!
>
>
>>
>> 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....@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 clo...@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+u...@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+u...@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 a topic in the
> Google Groups "Clojure" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/clojure/gieS5hQCUm4/unsubscribe.
> To unsubscribe from this group and all its topics, 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