I might be approaching this the wrong way so I am open to alternatives.
I would simply like to match the following sample urls using a single route:
/
/welcome
/en/welcome
/fr/welcome
/my/arbitrarily/deep/path
/en/my/arbitrarily/deep/path
/fr/my/arbitrarily/deep/path
etc
Here is what I have so far:
$app->get('/{_locale}{path}', function (Request $request) use ($app) {
$path = $request->attributes->get('path');
// do stuff with path here
})
->value('_locale', 'en')
->assert('_locale','^(en|fr)?$')
->value('path', 'index')
->assert('path', '.*')
->bind('*');
Now this seems to work as expected, but when I try to use the twig path() or url() it fails to build the correct url, for example:#
on /foo (no locale specified on the url so defaults to en):
{{ path('*', {path:'foo/bar'}) }}
will result correctly in
foo/bar
on /fr/foo, the same call:
{{ path('*', {path:'foo/bar'}) }}
results in
frfoo/bar
This is because of the missing / between {_locale} and {path}, but by changing the route to:
/{_locale}/{path}
It stops matching /foo and only matches either /en/foo, /fr/foo or //foo.
I'm not sure where to go from here :s
I didn't want to use multiple routes (maybe one with and without a {_locale}) because I'm not sure how that works with the path() function, I basically want the result of path() to include the current locale in the url if it's not 'en' (I think is what I'm getting at).
Can anyone help me with this?
Cheers
Toby
Declare a route for /{_locale}/{path} and /{path}.
As for path() , since you defined a default _locale value for the first route , there should not be any issues in your views.
Related
Is there a flask function that returns request url without the variables ?
#app.route('/index/<int:id1>/<int:id2>')
#app.route('/index1/<int:id1>/<int:id2>')
For a request /index/2/1 I expect /index in result
For a request /index1/2/1 I expect /index1 in result
I asked a function like described here https://stackoverflow.com/a/15975041/4772933
thanks
Not sure if this is what you want, but you can add more #app.routes to match your conditions, like:
#app.route('/index/<int:id1>/<int:id2>')
#app.route('/index')
def .....
This way the request /index/2/1 and /index will be maped to the same function
Edit
I think the answer is no. But you can use request.url_rule inside the function to get the pattern matched for url, then should be easy to rip off the variables parts. On your case you will get the string '/index//' as an answer.
I'm trying to create an endpoint that contains an actual path that I extract and use as a parameter. For instance, in the following path:
/myapi/function/this/is/the/path
I want to match "/myapi/function/" to my function, and pass the parameter "this/is/the/path" as the parameter to that function.
If I try this it obviously doesn't work because it only matches the first element of the path:
app.get("/myapi/function/:mypath")
If I try this it works, but it doesn't show up in req.params, I instead have to parse req.path which is messy because the logic has to know about the whole path, not just the parameter:
app.get("/myapi/function/*")
In addition, the use of wildcard routing seems to be discouraged as bad practice. I'm not sure I understand what alternative the linked article is trying to suggest, and I'm not using the query as part of a database call nor am I uploading any information.
What's the proper way to do this?
You can use wildcard
app.get("/myapi/function/*")
And then get your path
req.params[0]
// Example
//
// For the route "/myapi/function/this/is/my/path"
// You will get output "this/is/my/path"
I want to query the yelp api, and have the following route:
app.get("/yelp/term/:term/location/:location", yelp.listPlaces)
When I make a GET request to
http://localhost:3000/yelp?term=food&location=austin,
I get the error
Cannot GET /yelp?term=food&location=austin
What am I doing wrong?
Have you tried calling it like this?
http://localhost:30000/yelp/term/food/location/austin
The URL you need to call usually looks pretty much like the route, you could also change it to:
/yelp/:location/:term
To make it a little prettier:
http://localhost:30000/yelp/austin/food
In the requested url http://localhost:3000/yelp?term=food&location=austin
base url/address is localhost:3000
route used for matching is /yelp
querystring url-encoded data is ?term=food&location=austin i.e. data is everything after ?
Query strings are not considered when peforming these matches, for example "GET /" would match the following route, as would "GET /?name=tobi".
So you should either :
use app.get("/yelp") and extract the term and location from req.query like req.query.term
use app.get("/yelp/term/:term/location/:location") but modify the url accordingly as luto described.
I want to add to #luto's answer. There is no need to define query string parameters in the route. For instance the route /a will handle the request for /a?q=value.
The url parameters is a shortcut to define all the matches for a pattern of route so the route /a/:b will match
/a/b
/a/c
/a/anything
it wont match
/a/b/something or /a
Express 4.18.1 update:
using app.get("/yelp/term/:term/location/:location"), your query string can be yelp/term/food/location/austin
So your request url will look like this:
http://localhost:3000/yelp/term/food/location/austin
I'm attempting to implement permalinks, in the form /2013/02/16/title-with-hyphens. I'd like to use route parameters. If I try the following route:
app.get('/:href', function(req, res) { });
...then I get a 404, presumably because Express is only looking for one parameter, and thinks that there are 4.
I can work around it with /:y/:m/:d/:t, but this forces my permalinks to be of that form permanently.
How do I get route parameters to include slashes?
It seems that app.get("/:href(*)", ...) works fine (at least in Express 4). You will get your parameter value in req.params.href.
It will also be fired by / route, which is probably not what you want. You can avoid it by setting app.get('/', ...) elsewhere in your app or explicitly checking for an empty string.
Use a regular expression instead of a string.
app.get(/^\/(.+)/, function(req, res) {
var href = req.params[0]; // regexp's numbered capture group
});
Note that you cannot use the string syntax (app.get('/:href(.+)')) because Express only allows a small subset of regular expressions in route strings, and it uses those regular expressions as a conditional check for that particular component of the route. It does not capture the matched content in the conditional, nor does it allow you to match across components (parts of the URL separated by slashes).
For example:
app.get('/:compa([0-9])/:compb([a-z]/')
This route only matches if the first component (compa) is a single digit, and the second component (compb) is a single letter a-z.
'/:href(.+)' says "match the first component only if the content is anything", which doesn't make much sense; that's the default behavior anyway. Additionally, if you examine the source, you'll see that Express is actually forcing the dot in that conditional to be literal.
For example, app.get('/:href(.+)') actually compiles into:
/^\/(?:(\.+))\/?$/i
Notice that your . was escaped, so this route will only match one or more periods.
You can do this with regex routing
app.get('/:href(\d+\/\d+\/\d+\/*)', function(req, res) { });
I don't know if the regex is right, but you get the idea
EDIT:
I don't think the above works, but this does
app.get(/^\/(\d+)\/(\d+)\/(\d+)\/(.*)/, function(req, res) { });
Going to http://localhost:3000/2012/08/05/hello-i-must-be yeilds req.params = [ '2012', '08', '05', 'hello-i-must-be' ]
You can use this if your parameters has include slashes in it
app.get('/:href(*)', function(req, res) { ... })
It works for me. In my case, I used parameters like ABC1/12345/6789(10).
Hopefully this useful.
Can anyone tell me if it is possible to mix views arguments with static strings?
For example in the path section of a view feed display I need:
/mypath/%.xml
with the ".xml" part being the static string.
Thanks in advance.
I figured it out finally.
Under validation, choose PHP code. Then I entered:
// strip ".xml" from incoming
$new_arg = preg_replace('/\.xml$/', '', $argument ); argument
$handler->argument = $new_arg;
return TRUE; //must return something
That works. Now Drupal sends "foo" to the SQL query, even if the incoming argument via the url is "foo.xml"
I just tested this, and you can't do the exact path you posted above. Views appears to only recognize '%' as an argument placeholder if it sits between slashes, or by itself at the end. So, what will work is something like this:
/mypath/%/rss.xml
or
/mypath/static/%
In path, anyway, you should set path/%
But you can check argument %.xml in validating code:
In views argument additing/editing window:
Validator options - Validator - PHP Code:
Enter PHP code that returns TRUE or FALSE. No return is the same as FALSE, so be SURE to return something if you do not want to declare the argument invalid. Do not use . The argument to validate will be "$argument" and the view will be "$view". You may change the argument by setting "$handler->argument".
Use strpos to check if there xml string.
Also you can modify argument as it wrote in comment: $handler->argument