-
Notifications
You must be signed in to change notification settings - Fork 67
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
[WIP] New router #215
base: master
Are you sure you want to change the base?
[WIP] New router #215
Conversation
d93dda1
to
265d215
Compare
Okay, I think this is ready for some preliminary review. |
Regarding API for site composition, I implemented a very simple router API like this for Sihl: let all =
[
router ~scope:"" ~middlewares:Middleware.site_middlewares public;
router ~scope:"/applicants"
~middlewares:Middleware.logged_in_site_middlewares applicant;
router ~scope:"/applications"
~middlewares:Middleware.applications_site_middlewares application;
router ~scope:"/admin" ~middlewares:Middleware.admin_middlewares admin;
router ~scope:"/api" ~middlewares:[] api;
] But it became apparent that we need an API that allows nesting routers. F#'s Giraffe has these combinators. let notLoggedIn =
RequestErrors.UNAUTHORIZED
"Basic"
"Some Realm"
"You must be logged in."
let mustBeLoggedIn = requiresAuthentication notLoggedIn
let webApp =
choose [
route "/" >=> text "Hello World"
route "/user" >=>
mustBeLoggedIn >=>
choose [
GET >=> readUserHandler
POST >=> submitUserHandler
]
] |
b02ee31
to
5717062
Compare
That looks interesting. What I had in mind with composition was the ability to "mount" 3rd party web apps under a URL. Using something like: val mount : Router.t -> string -> Rock.App.t -> Router.t For example: let router = mount router "/metrics" metrics in The idea is that all the routers inside metrics will now be relative to What your snippet shows is more of an API that allows for hierarchical construction of the router. What I mean by that is that parameters are transparent to the subroutes. E.g.: let webApp =
choose [
route "/user/:id" >=>
mustBeLoggedIn >=>
choose [
GET >=> readUserHandler
POST >=> submitUserHandler
]
]
|
5717062
to
ec8fe13
Compare
@@ -1,3 +1,9 @@ | |||
module Private : sig | |||
module Router : module type of struct |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious, module type of Router
wouldn't be the same thing? Or is this to allow adding other elements to the signature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recall that the simplest form omitted some type equalities for types inside Router.t
. So if one used Router
from outside this alias, the type Router.t
wouldn't be equal. But I think this bug was fixed not too long ago. I'll see if the simpler form works as well.
val m : Rock.Handler.t t -> Rock.Middleware.t | ||
val empty : 'action t | ||
val add : 'a t -> route:Route.t -> meth:Method.t -> action:'a -> 'a t | ||
val m : t -> Rock.Middleware.t |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have any guidelines on naming conventions for similar functions in Opium? I assume m
is "middleware", but would be good to know if this should be used more generally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's my original naming convention for a module that provides a middleware. It seemed a little long to name things like Middleware_foo.middleware
. Not so sure if this convention is still beneficial.
Haven't looked in detail into this, but one thing that I believe is important is to expose the ability to iterate and inspect routes after they have been added. The use case that I have in mind is generating OpenAPI/Swagger specifications for the API. |
This will be covered. Though I think we'll need a handler type that allows for more introspection. |
a31396c
to
6a8aff7
Compare
I'm now wondering how to treat trailing slashes and parameter capture. Should |
I would say no, IMO
Again, I would say no, but it's a bit more opinionated. I remember some websites where the former redirected to the latter for instance. FWIW, I just tried on Github and it does not make a distinction. That's sensible behavior IMO, and the end-users are always free to implement their own Router, so it's ok to be opinionated I think. |
I think it makes sense to remove empty segments (save for Line 48 in 6a8aff7
I don't know what the behavior is with this implementation, but with the current implementation I am using full splat for serving files from an archive file: |
That makes it impossible to have something like
That reminds me that EDIT: In particular, if we treat
As you prefer. |
In my (limited) experience it most often doesn't matter if you add empty segments, e.g.: https://github.com/rgrinberg//opium///pull/215
Yes, I like this. |
One expectation I have in the handler is that the parameter is present, so for this example, I would not expect the route to be matched if one of the parameters is absent. I'm looking at Rails documentation, for which the router DSL is similar to Opium's and they have two kinds of parameters:
We could do something similar? Now considering the limitation you mention: if the parameter is optional, I would expect
That seems fine to me. |
8fe0930
to
3d90072
Compare
Signed-off-by: Rudi Grinberg <[email protected]>
Signed-off-by: Rudi Grinberg <[email protected]>
Signed-off-by: Rudi Grinberg <[email protected]>
Signed-off-by: Rudi Grinberg <[email protected]>
Signed-off-by: Rudi Grinberg <[email protected]>
Signed-off-by: Rudi Grinberg <[email protected]>
Signed-off-by: Rudi Grinberg <[email protected]>
Signed-off-by: Rudi Grinberg <[email protected]>
Signed-off-by: Rudi Grinberg <[email protected]>
e2ff83e
to
1bef65d
Compare
TODO
**
tail recursive addition of routes.let's skip this for now, I doubt this will be useful for realistic routesDiscussion
Do we need optional parameters? E.g.
:foo?
I still haven't created an api for site composition. Still thinking of what is
that going to look like