Skip to content
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

Routing all paths to one handler function #648

Closed
saltukalakus opened this issue Nov 4, 2015 · 18 comments · Fixed by #1945
Closed

Routing all paths to one handler function #648

saltukalakus opened this issue Nov 4, 2015 · 18 comments · Fixed by #1945

Comments

@saltukalakus
Copy link

Is it possible to route all paths that start with something like “/api” to same handler function?

Such as:

/api/foo
/api/bar
/api/foo/bar
/api/bar/baz/this/that 

All should be handled with one function and I should be able to get the full path after /api.

This feature is very handy and I used it often at Node.js Express framework. Now I am looking for ways to accomplish the same thing with Falcon.

More info can be found here; It defines the feature as "white-listed “global” functionality."
http://expressjs.com/api.html#app.all

@hpincket
Copy link
Contributor

hpincket commented Nov 4, 2015

You can always write your own routing function (though it will be slow in comparison).

You can get partially there by adding a parameter, but this won't include paths which have extra '/'.

app.add_route('/things/{rest_of_url}', things)

Someone else might know more.

@philiptzou
Copy link
Contributor

Unfortunately slash "/" is the delimiter used by the compiled routing code, thus it can not be contained by any URL parameter. @hpincket's example will not work, I guess.

@hpincket
Copy link
Contributor

hpincket commented Nov 4, 2015

Right, my example will only work if there are no slashes.

On Wed, Nov 4, 2015 at 2:02 PM, Philip Tzou notifications@github.com
wrote:

Unfortunately slash "/" is the delimiter used by the compiled routing code, it can not be contained by any URL parameter. @hpincket's example will not work, I guess.

Reply to this email directly or view it on GitHub:
#648 (comment)

@kgriffs
Copy link
Member

kgriffs commented Nov 5, 2015

Falcon has a few features that can help with this. Global logic (such as auth, rate limiting, etc.) can be implemented in Falcon via middleware components or hooks. Sinks can capture all requests with a specific prefix.

If none of these fit the bill, I'm sure we can work out a plan to get what you need into the framework.

@philiptzou
Copy link
Contributor

I suppose we can introduce some new syntax to URI templates. For example something like '{path|re:/.+/}', which can be interpreted to "(?P<path>.+)". This approach doesn't add new type of node, it compatible with the complex var node which has already been interpreted as regexp.

@philiptzou
Copy link
Contributor

Another approach (may be more efficient and non-break) is add a new parameter "match_type" to add_route. Which is default to "EXCEPT_SLASH" which is the current behaviour. But we can add other types like "ALL" to extend the behaviour. So the usage will basically like this:

app.add_route('/things/{rest_of_url}', things, match_type=ALL)  # match the remaining part include slashes
app.add_route('/things/{just_this}', things, match_type=EXCEPT_SLASH)  # match any chars except slash
app.add_route('/things2/{just_this}', things)  # match any chars except slash, the default behaviour

How do you think @kgriffs?

@kgriffs
Copy link
Member

kgriffs commented Mar 2, 2016

The regex approach may prove more flexible (afford more functionality). However, before moving forward I'd like to see some concrete examples of what types of use cases such a feature would serve, that isn't already covered by using a sink. Just to make sure we design this in the right way.

@kgriffs kgriffs added this to the On Deck milestone Mar 2, 2016
@dergigi
Copy link

dergigi commented Apr 28, 2016

I ran into this issue and what surprises me is that slashes pose problems in parameters even when URL encoded.

api.add_route('/v1/things/{param}', things)
GET /v1/things/forward-slash     # works
GET /v1/things/forward/slash     # does not work
GET /v1/things/forward%2Fslash   # does also not work

Is this expected behaviour?

@miso-belica
Copy link

miso-belica commented Dec 20, 2016

Hi, my use-case is to create microservice for CORS proxy like this GET /api/v1/proxy/http://example.com/some/path/to/file.jpeg?width=300&heigth=100. IMHO this is quite common case. Currently I am able to do this with sink.

EDIT: This was not good idea. Now we are using URL GET /api/v1/proxy?url=http%3A%2F%2Fexample.com%2Fsome%2Fpath%2Fto%2Ffile.jpeg%3Fwidth%3D300%26heigth%3D100 because if proxied URL has some encoded characters they are decoded in endpoint and the URL is broken. This way the URL is always correctly decoded in endpoint.

@winglq
Copy link

winglq commented Sep 26, 2017

same issue here. slash was url encoded

@Dotrox
Copy link

Dotrox commented Apr 17, 2018

I use a sink and then extract the rest part with the follow code:

parts = req.relative_uri.split('/my_sink_path/')
url = parts[1]

But this is ugly!

Also I need deal with a # symbol but this part is totally lost in the Request object.

@philiptzou
Copy link
Contributor

@Dotrox: There's no way you can capture the text after # symbol. It won't be submitted to the server by any browsers.

@geyang
Copy link

geyang commented Jul 10, 2018

Really need this feature.

@kgriffs kgriffs modified the milestones: Version 2.0, Version 2.2 Nov 8, 2018
@ashpekvs
Copy link

ashpekvs commented Aug 5, 2019

Voting for this feature as well

@rex-sang
Copy link

rex-sang commented Sep 5, 2019

Any updates? Really wanted this feature as well

@KixPanganiban
Copy link

Any updates to this?

@sonvt8
Copy link

sonvt8 commented Oct 27, 2019

I am looking for the best way to handle this case. Any updates here?

@vytas7
Copy link
Member

vytas7 commented Oct 27, 2019

Hi everyone,
as @kgriffs pointed out, Falcon now already has a few features (including the new ones in 2.0) which may or may not fit the bill in this case.
To reiterate, it would be good to understand where we stand right now, and what is not covered by Falcon 2.0 (or is covered but perceived too "ugly" / too much extra work to do).

Although probably not exactly what was requested in this issue, if the amount of routes is finite and known in advance, the route suffix feature may be helpful to route all these paths to the same resource with suffixed methods.

If we just need to handle all paths to one function as the issue is originally formulated, could a sink work? I was thinking along the lines:

import re

import falcon


def one_handler_function(req, resp, path):
    resp.media = {
        'message': 'Just demonstrating a possible approach to #648',
        'path': path,
    }


api = falcon.API()
api.add_sink(one_handler_function, re.compile(r'/api(?P<path>/.*)'))

That seems to do the job (but probably I'm missing important details):

GET /api/hello/world?q=1 HTTP/1.1

{
    "message": "Just demonstrating a possible approach to #648",
    "path": "/hello/world"
}

Sinks are somewhat unwieldy in the sense that one needs to handle req.method explicitly, but OTOH that perfectly fits the bill of one handler function.

FWIW, we have an issue to improve documentation for the sink feature: #1538 .
Regarding forward slashes in the path woes, there are admittedly some unresolved glitches on that front. See also related routing discussions here: #423

Furthermore, depending on what this one handler function does, simple cases may be handled by responding directly from middleware by signalling the Response.complete flag. While I would primarily recommend sinks for routing paths to one function, the Response.complete approach may prove advantageous if you also have some of these paths clashing with existing routes that you still may want to handle separately (and that would take precedence over sinks). The new feature itself is meant to cover cases like intelligent caching of responses etc.

Last but not the least, do not hesitate to share and discuss ideas on our Gitter channels.
Routing improvements is admittedly one of the areas we are getting many requests from the community.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.