How-to guides
A how-to guide:
- is goal-oriented
- shows how to solve a specific problem
- is a series of steps
Analogy: a recipe in a cookery book
How to install Roll
Roll requires Python 3.6+ to be installed.
It is recommended to install it within a pipenv or virtualenv.
You can install Roll through pip:
pip install roll
How to return an HTTP error
There are many reasons to return an HTTP error, with Roll you have to raise an HttpError instance. Remember our base example from tutorial? What if we want to return an error to the user:
from http import HTTPStatus
from roll import Roll, HttpError
from roll.extensions import simple_server
app = Roll()
@app.route('/hello/{parameter}')
async def hello(request, response, parameter):
if parameter == 'foo':
raise HttpError(HTTPStatus.BAD_REQUEST, 'Run, you foo(l)!')
response.body = f'Hello {parameter}'
if __name__ == '__main__':
simple_server(app)
Now when we try to reach the view with the foo
parameter:
$ http :3579/hello/foo
HTTP/1.1 400 Bad Request
Content-Length: 16
Run, you foo(l)!
One advantage of using the exception mechanism is that you can raise an HttpError from anywhere and let Roll handle it!
How to return JSON content
There is a shortcut to return JSON content from a view. Remember our base example from tutorial?
from roll import Roll
from roll.extensions import simple_server
app = Roll()
@app.route('/hello/{parameter}')
async def hello(request, response, parameter):
response.json = {'hello': parameter}
if __name__ == '__main__':
simple_server(app)
Setting a dict
to response.json
will automagically dump it to
regular JSON and set the appropriated content type:
$ http :3579/hello/world
HTTP/1.1 200 OK
Content-Length: 17
Content-Type: application/json; charset=utf-8
{
"hello": "world"
}
Especially useful for APIs.
How to serve HTML templates
There is an example in the examples/html
folder using
Jinja2 to render and return HTML views.
To run it, go to the examples
folder and run python -m html
.
Now reach http://127.0.0.1:3579/hello/world
with your browser.
To run associated tests: py.test html/tests.py
.
How to store custom data in the request
You can use Request
as a dict
like object for your own use, Roll
itself
never touches it.
request['user'] = get_current_user()
How to deal with cookies
Request cookies
If the request has any Cookie
header, you can retrieve it with the
request.cookies
attribute, using the cookie name
as key:
value = request.cookies['name']
Response cookies
You can add cookies to response using the response.cookies
attribute:
response.cookies.set(name='name', value='value', path='/foo')
See the reference for all the available set
kwargs.
How to consume query parameters
The query parameters (a.k.a. URL parameters) are made accessible via the request.query
property.
The very basic usage is:
# URL looks like http://localhost/path?myparam=blah
myparam = request.query.get('myparam', 'default-value')
assert myparam == 'blah'
other = request.query.get('other', 'default-value')
assert other == 'default-value'
You can also request the full list of values:
# URL looks like http://localhost/path?myparam=bar&myparam=foo
myparam = request.query.list('myparam', 'default-value')
assert myparam == ['bar', 'foo']
If you don't pass a default value, Roll will assume that you are getting a required
parameter, and so if this parameter is not present in the query,
a 400
HttpError will be raised.
The Query class has three getters to cast the value for
you: bool
, int
and float
.
# URL looks like http://localhost/path?myparam=true
myparam = request.query.bool('myparam', False)
assert myparam is True
If the parameter value cannot be casted, a 400
HttpError
will be raised.
See also "how to subclass roll itself" to see how to make your own Query getters.
How to use class-based views
In many situations, a function
is sufficient to handle a request, but in some
cases, using classes helps reducing code boilerplate and keeping things DRY.
Using class-based views with Roll is straightforward:
@app.route('/my/path/{myvar}')
class MyView:
def on_get(self, request, response, myvar):
do_something_on_get
def on_post(self, request, response, myvar):
do_something_on_post
As you may guess, you need to provide an on_xxx
method for each HTTP method
your view needs to support.
Of course, class-based views can inherit and have inheritance:
class View:
CUSTOM = None
async def on_get(self, request, response):
response.body = self.CUSTOM
@app.route("/tomatoes")
class Tomato(View):
CUSTOM = "tomato"
@app.route("/cucumbers")
class Cucumber(View):
CUSTOM = "cucumber"
@app.route("/gherkins")
class Gherkin(Cucumber):
CUSTOM = "gherkin"
Warning: Roll will instanciate the class once per thread (to avoid overhead at each request), so their state will be shared between requests, thus make sure not to set instance properties on them.
See also the advanced guides.