Yes, I was assuming the HTTP calls happen inside the with-fake-routes! block.

I missed the part about the random port.  I se 3 options for that:

*Assign a port, rather than random*

(with-fake-routes! 9999 ...)


But then, of course, you have to worry about port already in use.

*An atom*

(def the-uri (atom nil))
(with-fake-routes! the-uri
  ...
  (http/get @the-uri "/x"))

*A macro*

A common convention in Clojure would be to pass it a symbol (e.g. `uri`
that is bound by the macro), rather implicitly creating `uri`.

(with-fake-routes! [uri option-server-instance]

    route-map

    (http/get uri "/x"))


or, with a pre-defined server

(def fake-server ...)
(with-fake-routes!

    route-map

    (http/get (:uri fake-server) "/x"))


marc



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

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

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