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.