Variables and converters

Another feature provided by the routing system is variables.

You can use variables using the <VARIABLE_NAME> syntax. This notation is pretty standard (Bottle uses the same), and allows you to describe endpoints with dynamic values.

For example, if you want to create a function that handles all requests to /person/N, with N being the unique ID of a person, you could use /person/<person_id>.

When Flask calls your function, it converts the value it finds in the URL section as the person_id argument:

    @app.route('/api/person/<person_id>') 
def person(person_id):
response = jsonify({'Hello': person_id})
return response

$ curl localhost:5000/api/person/3
{
"Hello": "3"
}
If you have several routes that match the same URL, the mapper uses a particular set of rules to determine which one it calls. This is the implementation description taken from Werkzeug's routing module:
  1. Rules without any arguments come first for performance. This is because we expect them to match faster and some common rules usually don't have any arguments (index pages, and so on).
  2. The more complex rules come first, so the second argument is the negative length of the number of weights.
  3. Lastly, we order by the actual weights.
Werzeug's Rules have, therefore, weights that are used to sort them, and this is not used or surfaced in Flask. So, it boils down to picking views with more variables first, then the others --in order of appearance--when Python imports the different modules. The rule of thumb is to make sure that every declared route in your app is unique, otherwise, tracking which one gets picked will give you headaches.

There's also a basic converter that will convert the variable to a particular type. For instance, if you want an integer, you would use <int:VARIABLE_NAME>. In the person example, that translates to /person/<int:person_id>.

If a request matches a route, but a converter fails to change a value, Flask will return a 404 Error unless another route matches the same path.

Built-in converters are string (the default, a Unicode string), int, float, path, any, and uuid.

The path converter is like the default converter, but includes slashes. It's similar to the [^/].*? regular expression.

The any converter allows you to combine several values. It's a bit too smart, and rarely used. The uuid converter matches the UUIDs strings.

It's quite easy to create your custom converter. For example, if you want to match users' IDs with usernames, you could create a converter that looks up a database, and converts the integer into a username.

To do this, you need to create a class derived from the BaseConverter class, which implements two methods: the to_python() method to convert the value to a Python object for the view, and the to_url() method to go the other way (used by url_for() described in the next section uses to_url()):

    from flask import Flask, jsonify, request 
from werkzeug.routing import BaseConverter, ValidationError

_USERS = {'1': 'Tarek', '2': 'Freya'}
_IDS = {val: id for id, val in _USERS.items()}

class RegisteredUser(BaseConverter):
def to_python(self, value):
if value in _USERS:
return _USERS[value]
raise ValidationError()

def to_url(self, value):
return _IDS[value]

app = Flask(__name__)
app.url_map.converters['registered'] = RegisteredUser

@app.route('/api/person/<registered:name>')
def person(name):
response = jsonify({'Hello hey': name})
return response

if __name__ == '__main__':
app.run()

The ValidationError method is raised in case the conversion fails, and the mapper will consider that the route simply does not match that request.

Let's try a few calls to see how that works in practice:

$ curl localhost:5000/api/person/1 
{
"Hello hey": "Tarek"
}

$ curl localhost:5000/api/person/2
{
"Hello hey": "Freya"
}

$ curl localhost:5000/api/person/3

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p> The requested URL was not found on the server. If you entered
the URL manually please check your spelling and try again.</p>

But beware that this was just an example to demonstrate the power of converters. In real applications, we would need to be careful not to rely on too many converters, because it would be painful to change all the routes when the code evolves.

The best practice for routing is to keep it as static and straightforward as possible, and see it as mere labels you put on your functions.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset