-
Notifications
You must be signed in to change notification settings - Fork 256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve documentation to include more complex examples #192
Comments
That's not a bad idea. There isn't much documentation for I'm a little confused at why you think 1 is a problem, though, as there's quite a few examples and explanations on how to combine routes with |
I know there is an example (at least one) on how to combine routes. But I'm talking about combining route definitions like the following: (defroutes finance-routes
(context "/finance"
(GET "/accounts" [] ...)
(POST "/record" [] ...)))
(defroutes billing-routes
(context "/billing"
(POST "/invoice" [] ...)
(GET "/invoice/:invoice-id/lines/" [] ...)))
(defroutes api-routes
...) From experimenting I found that I can combine these with (routes
(GET "/health" [] {:status 200})
finance-routes
billing-routes
api-routes) But for me it wasn't intuitive that I can treat a list of routes (what I've called a "route definition" above) the same as a single route (i.e. the health route). But to be honest I think my biggest issue here is that I don't have a clear picture of how I should structure everything ( About |
Routes are just Ring handler functions that may return The (defroutes finance-routes
(context "/finance"
(GET "/accounts" [] ...)
(POST "/record" [] ...))) Is the same as: (def finance-routes
(routes
(context "/finance"
(GET "/accounts" [] ...)
(POST "/record" [] ...)))) And because there's only one argument to (def finance-routes
(context "/finance"
(GET "/accounts" [] ...)
(POST "/record" [] ...)))) If you want to apply middleware to a route, you can sometimes just apply it directly: (def finance-routes
(context "/finance"
(-> (GET "/accounts" [] ...)
(wrap-some-middleware {:some-option 123}))
(POST "/record" [] ...)))) Remember that a route is just a Ring handler function that may return However, it's usually safer to use (def finance-routes
(context "/finance"
(-> (GET "/accounts" [] ...)
(wrap-routes wrap-some-middleware {:some-option 123}))
(POST "/record" [] ...)))) And of course you can also apply middleware to groups of routes: (def finance-routes
(-> (context "/finance"
(GET "/accounts" [] ...)
(POST "/record" [] ...))
(wrap-routes wrap-some-middleware {:some-option 123}))) The (def handler
(routes
(GET "/" [] "<h1>Hello World</h1>")
(route/not-found "<h1>Page not found</h1>"))) Because this is a valid handler, and will never return (def handler
(-> (routes
(GET "/" [] "<h1>Hello World</h1>")
(route/not-found "<h1>Page not found</h1>"))
(wrap-some-middleware {:some-option 123}))) Does that make things clearer? |
Yes mostly... what if I want to add multiple middlewares, would it then look like so? (def finance-routes
(context "/finance"
(-> (GET "/accounts" [] ...)
(wrap-routes wrap-some-middleware {:some-option 123}))
(wrap-routes wrap-some-other-middleware))
(POST "/record" [] ...)))) |
Exactly. Though I should mention it's slightly more efficient to combine the middleware before passing it to (def finance-routes
(context "/finance"
(-> (GET "/accounts" [] ...)
(wrap-routes
#(-> %
(wrap-some-middleware {:some-option 123})
(wrap-some-other-middleware)))
(POST "/record" [] ...)))) But in practice it shouldn't make much difference, and using |
Alternatively to About this:
I've slightly modified your example: (def finance-routes
(context "/finance"
(GET "/accounts/:id" [id] ...)
(-> (GET "/accounts" [] ...)
(wrap-some-middleware {:some-option 123}))
(POST "/record" [] ...)))) Is it correctly understood that |
The middleware is triggered when the route is reached, whether or not it matches. If the middleware has no side-effects this can be fine. So for example: (defn wrap-some-middleware [handler options]
(fn [request]
(handler (assoc request ::foo 1)))) This would be fine, because the middleware function doesn't care about the output of the handler and has no side effects. In this case there's no real difference between this and using The |
Would you be interested in me writing a small wiki page about Middleware? |
I want it to highlight the following:
|
I think that would be a good idea, and much appreciated. |
This is my initial take and should give you an idea of what I had in mind: I thought it would fit in the list on the index page between I'm going to read through it again tomorrow for those obvious mistakes that usually hides in the first round. I looked for an opening to insert a link to https://github.com/ring-clojure/ring/wiki/Concepts#middleware somewhere but I couldn't find a god place (and sentence) for it. Also you mentioned something about valid handlers never returning Feel free to modify. 😁 |
Thanks 😃 . I updated the page and updated the explanations to be more accurate and examples to be a little more concrete. |
Look good thanks 👍 😄 |
Just a note. You wrote:
I gives me the feeling that these are the only two valid reasons to use My use cases where:
My reasoning might be stupid but I'm just trying to give context on why it confuses me that the reasoning in the Wiki seems specific and technical. Couldn't business requirements also warrant use of specific middleware on specific routes and other technical reasons? I guess my real question underneath it all is: Should I solve my above use cases in a different way? |
In both those cases you're likely dealing with side-effects. Parsing multipart parameters involves consuming the body input stream, which is side-effectful, and while enforcing a bearer token isn't necessarily side-effectful, it likely involves choosing whether to execute a side-effectful route. However, I admit it could definitely be clearer! I'll consider how to reword it to make the use of |
Maybe just replace Also consider this. When I read the following sentence I understood the word
Now in your above comment you write:
Does that mean |
This issue helped me a lot in understanding and working with |
It appears to me that When (defn- wrap-compojure-route
[handler]
(compojure/wrap-routes handler (fn [route-handler]
(fn [request]
(log/infof "ROUTE: %s" (-> request :compojure/route second))
(route-handler request)))))
(defn resource-handler [request]
(log/infof "REQUEST: %s" request)
{:status 200})
(def route-handler
(wrap-compojure-route
(compojure/routes
(compojure/context "/api" []
(compojure/GET "/resource" [] #'resource-handler)))))
(defn start-server []
(jetty/run-jetty route-handler {:port 5010 :join? false})) It logs |
|
Thanks! This works: (defn- wrap-compojure-route
[handler]
(compojure/wrap-routes handler (fn [route-handler]
(fn [request]
(let [{:compojure/keys [route route-context]} request]
(log/infof "ROUTE: %s" (str route-context (second route))))
(route-handler request)))))
(defn resource-handler [request]
(log/infof "REQUEST: %s" request)
{:status 200})
(def route-handler
(wrap-compojure-route
(compojure/routes
(compojure/context "/api" []
(compojure/GET "/resource" [] #'resource-handler)))))
(defn start-server []
(jetty/run-jetty #'route-handler {:port 5010 :join? false})) |
I don't use Compojure on a regular basis (sometimes with years in between), so I always hit the wiki to find out how it is used. The basics are really intuitive and easy to get up and running. But I always struggle to figure out how the more complex stuff works. Specifically I have two reoccurring issues that I get stuck with every time, where I have to turn to web searches (usually ending up on StackOverflow) to figure it out.
I would love to have the Wiki to be one-stop for documentation... am I the only one?
The text was updated successfully, but these errors were encountered: