Regarding the previous conversations around not being able to state routing trees for "resources", the way we have always done it due to reitit's strict and 'not super user friendly as it wants to educate "good routing trees'" (Tommi's words), the example below is what I have settled on for now. I also had to turn conflicts back on, because although I had turned them off and thought this may allow me to do what I wanted, (specifically, state the same path twice, once with GET, another with POST, to allow the 'usual' layout), it turned out that turning conflicts off only prevented the compile error. With the app running, the routes as stated/intended didn't work; (a GET masked a later declared POST where I repeated the same URL, and the POST failed to match), so I don't understand at the moment what the purpose of turning conflicts off actually is; bit confused there. So my routing tree, to get routes working in 'traditional' way: (Which is also not good practice in reitit's view - reitit wishes to educate away from this as I understand) Original (as used by, e.g. php/laravel, ruby, node...), How we define a "resource", aka "crud" GET /threads/create :name :threads.create POST /threads :name :threads.store GET /threads/:slug/edit :name :threads.edit POST /threads/:slug/ :name :threads.update POST /threads/:slug :name :threads.delete GET /threads/:slug :name :threads.show GET /threads :name :threads.index The problem with the above in the reitit view are many. There are a lot of conflicts. Also, you are required to state the url first, and the http method second. You cannot state a url twice, which means the standard order above cannot be used unless the URLs are changed to make them all unique and conflict free. So - Reitit version - how to define a "resource" GET /threads/reitit/create ; will be visible in url POST /threads/reitit/store ; not seen since it's a POST GET /threads/:slug/edit POST /threads/:slug/update POST /threads/:slug/delete GET /threads/:slug ; used in url, webcrawlers, bookmarks, so i prioritised keeping this one clean / the same as usual. GET /threads No conflicts! 🙂 If the first two above were just /threads/create and /threads/store, they would conflict with /threads/:slug. Even though in less strict routing methods this is fine because if they are placed first they just take priority and 'mask' the latter. (If my understanding is correct - please correct me). Reitit does not permit this so we must use the above instead. Of course, you can change 'reitit' above to, 'no-conflict', or 'item' - what does everyone think? Comments please? Am I on the right track at all?
Can you use a HTTP DELETE?
What might help you is knowing that reitit works only on the path level. Only the paths affect matching. The GET/POST stuff is handled after reitit, by the reitit-ring adapter. So yeah, you need to specify all handlers for the same path in the same entry.
With conflicts enabled, you should be able to express your original routes, you just need to order them a bit differently:
/threads {:get ... :post ...}
/threads/create {:get ...}
/threads/:slug/edit {:get ...}
/threads/:slug/ {:get ...}
/threads/:slug {:get ... :post ...}
And of course you can't give different names to the same path, again, due to reitit working on the path level.the only conflict here (AFAICS) is the one between /threads/create and /threads/:slug, just as you saw earlier
If you want to use methods as part of routing, you might be better off with something that works closer to the ring level, perhaps Compojure. It just lets you define your handlers in sequence and the first one that returns a response, wins.
(of course you don't get all the coercion and parameter goodness that you get from reitit, but you might not need it if you're not creating a complex JSON API)
BTW, if you're interested in the implementation, here are the lines that show how reitit ring-handler first does matching by the request uri, and then uses the method to get the handler from the match: https://github.com/metosin/reitit/blob/86871a6a555c218b1e8b1e20646653f3ed18973f/modules/reitit-ring/src/reitit/ring.cljc#L360-L364
Since we can't use route naming effectively given the grouping requirement, is there a way to indicate the route name(s) without having to do so in a comment? I was thinking like a doc string or something. This is what held me back from putting threads.index and threads.store under the same 'name', as there seemed no semantic value in grouping them together.
just thought of :name :threads.store.threads.index
(munge them together)
post first then get
OpenAPI defines operationId for each method. Adding that to each method (under a path) gives a global lookup for routes. Code-generators use this info, e.g.
/threads {:get {:openapi/operationId ::get-threads}
:post {:openapi/operationId ::post-threads}
/threads/create {:get ...}
/threads/:slug/edit {:get ...}
/threads/:slug/ {:get ...}
/threads/:slug {:get ... :post ...}there is no utility function for doing reverse routing using the info in reitit, but all information is there, should be easy to do in user space too.
reordering routes like https://tonsky.me/blog/simple-router/, also should be easy to do on top of current reitit, just not done.
… and last, helper to allow separate routes like:
POST /threads/:slug :name :threads.delete
GET /threads/:slug :name :threads.show
to be merged into
"/threads/:slug" {:get ..., :post ...}
should be a simple helper on top of current core lib.should these be all in reitit by default? I think so. there is much room for improvement and I think all of those are valuable as optional helpers, or maybe even as default behavior. Just need someone with time to do them.
about the openapi operationId, see https://swagger.io/docs/specification/paths-and-operations/
libs like https://github.com/oliyh/martian use that.
I've been using this: GET /thread/new POST /thread/items GET /thread/items/:slug/edit PUT /thread/items/:slug DELETE /thread/items/:slug GET /thread/items/:slug GET /thread/items