-
Notifications
You must be signed in to change notification settings - Fork 16
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
Add a more ergonomic API around path segment matching #114
Comments
@akheron I've put a lot of thought into this issue, I'm not quite convinced on the proposed solution and would love to get feedback/ideas, so if you have any to give, it would be much appreciated! |
I've used array pattern matching to accomplish good ergonomics, and I think it's the way to go. It solves matching the path and capturing parameters at the same time. Matching path only: router { path } =
case path of
["todos", id] -> readTodo id
["todos"] -> listTodos
[] -> frontPage
_ -> HTTPure.notFound Matching path and method: router { method, path } =
handle method path
where
handle HTTPure.Get ["todos", id] -> readTodo id
handle HTTPure.Put ["todos", id] -> updateTodo id
handle HTTPure.Get [] -> frontPage
handle _ [] -> HTTPure.methodNotAllowed
handle _ _ -> HTTPure.notFound |
That's what I was originally leaning towards, but I started thinking more along the lines of the express API, because working on array pattern matching is somewhat limited in a few ways. Specifically:
I'm not entirely convinced these 3 are significant problems--they all have workarounds, and it may be cleaner to defer to the workarounds than to move away from PS language features. For 1., the workaround is just to match on any shape and check the shape in the route handler. I just don't love that, because it means that some aspects of routing are moved out of the router, but it works. For 2, you just have to have two different matches, one for each case--not a huge deal. 3 is a gross API, but totally doable--and perhaps not something we should cater towards, since HTTPure I think should make everything possible, but should make good things easy, and I can't think of a case where complex regex path matching would ever be a good thing. So I guess the question is, at this time, do you feel that any of these 3 are significant enough limitations (or that the workarounds are gross enough) to be worth catering solutions? |
Oh, and one other problem with array pattern matching: you can't do case-insensitive matches. That isn't a big issue for something like a REST API, but it's a non-starter for something that serves, e.g., a UI, where addresses are entered by users into address bars in browsers. HTTPure should be able to cater to both use cases. I don't know of any good workaround here, other than making all routes use regexes, which gets back into the gross ergonomics situation. |
The thing I like most in HTTPure is that the serve takes a function that processes all requests. The user is free to implement routing, request handlers, middleware etc. in any way he sees fit. However, providing helpers for common use cases (e.g. routing) would be a big plus, so that each user doesn't have to reinvent the wheel. I suggest figuring out the best way to create composable routers, which could then be used for different purposes. If the user wants regex route matching, it could be used while also using plain array pattern matching or simple prefix matching for other purposes. In The only problem with those arrays of routes and making a router function using PS. Case-insitive matching could be accomplished by e.g. converting the path of some or all requests to lowercase in a middleware function. |
Hi, I'm not sure if I should add any comments as I'm not a contributor but barely a user (we have just started to build a service around httpure)... but anyway here are my two cents: I really like clean API which is provided by this framework and I think that advanced/opinionated routing options should be delegated to external libraries like: purescript-httpure-rest-router, purescript-routing, purescript-routing-duplex, purescript-boomboom, purescript-boomerang or some other (maybe "contrib") proposition. I think that your path representation as just an array of segments is nearly ideal as it is lightweight, covers really simple scenarios and can be base for integration with any other more advanced routing option... Thanks for your work on httpure! |
Folks, the feedback here is really helpful, thank you both for leaving those opinions @akheron and @paluh . You guys have convinced me, there are enough tools out there that can be used and the simplicity of HTTPure is valuable. I'll close this ticket as something that doesn't need to happen. I do think before we go to 1.0 it would be nice to do a better job documenting some common patterns around routing, such as the array pattern matching approach, and using tools like the ones you listed @paluh . I'll add a note in #106 to remember to do that. Thanks again all! |
The Problem
The current API for matching path segments is entirely built around the
Lookup
typeclass. This works, but it can get clunky for some common things. For example, you can do this:But that will send any request whose first segment is
"something"
tosomethingRoute
. Likely the intent is to only send the request tosomethingRoute
if it has exactly one segment, which is"something"
, and you'd have to do something like this:The API can become very painful as you have longer paths, e.g.:
And that doesn't even include doing things like enforcing specific requirements for certain pattern-based path segments, which requires significantly more complexity.
Proposed Solution
Introduce two new binary operators,
=~
and==~
. These operators take aPath
on the left side, and aString
on the right side. ThePath
will be matched against theString
using some set of rules heavily inspired by Express's routing engine.=~
will be used for case-insensitive routing, where==~
can be used for strict (case-sensitive) routing.The only real change I'm aware of over what express does is that we'll have to come up with a different API around route parameters. Of course, that could be as simple as replacing
:namedParameter:
with\w+
and usingLookup
to reference the parameters. If there were some way to even use the named parameters approach that Express uses, it would be awesome, but I don't see how that would be possible in a purely functional world (at least, without introducing a significantly more complex API, which isn't really worth it--it's a fairly small thing, and if it can't be done without an overly complex API, it's not worth changing to it).The text was updated successfully, but these errors were encountered: