The Request Object

The Request object encapsulates all the information passed by the client. It is passed as an argument to route handlers, as well as to before-request, after-request and error handlers.

Request Attributes

The request object provides access to the request attributes, including:

  • method: The HTTP method of the request.

  • path: The path of the request.

  • args: The query string parameters of the request, as a MultiDict object.

  • headers: The headers of the request, as a dictionary.

  • cookies: The cookies that the client sent with the request, as a dictionary.

  • content_type: The content type specified by the client, or None if no content type was specified.

  • content_length: The content length of the request, or 0 if no content length was specified.

  • json: The parsed JSON data in the request body. See below for additional details.

  • form: The parsed form data in the request body, as a dictionary. See below for additional details.

  • files: A dictionary with the file uploads included in the request body. Note that file uploads are only supported when the Multipart Forms extension is used.

  • client_addr: The network address of the client, as a tuple (host, port).

  • app: The application instance that created the request.

  • g: The g object, where handlers can store request-specific data to be shared among handlers. See The “g” Object for details.

JSON Payloads

When the client sends a request that contains JSON data in the body, the application can access the parsed JSON data using the json attribute. The following example shows how to use this attribute:

@app.post('/customers')
async def create_customer(request):
    customer = request.json
    # do something with customer
    return {'success': True}

Note

The client must set the Content-Type header to application/json for the json attribute of the request object to be populated.

Form Data

The request object also supports standard HTML form submissions through the form attribute, which presents the form data as a MultiDict object. Example:

@app.route('/', methods=['GET', 'POST'])
async def index(req):
    name = 'Unknown'
    if req.method == 'POST':
        name = req.form.get('name')
    return f'Hello {name}'

Note

Form submissions automatically parsed when the Content-Type header is set by the client to application/x-www-form-urlencoded. For form submissions that use the multipart/form-data content type the Multipart Forms extension must be used.

Accessing the Raw Request Body

For cases in which neither JSON nor form data is expected, the body request attribute returns the entire body of the request as a byte sequence.

If the expected body is too large to fit safely in memory, the application can use the stream request attribute to read the body contents as a file-like object. The max_body_length attribute of the request object defines the size at which bodies are streamed instead of loaded into memory.

Cookies

Cookies that are sent by the client are made available through the cookies attribute of the request object in dictionary form.

The “g” Object

Sometimes applications need to store data during the lifetime of a request, so that it can be shared between the before- and after-request handlers, the route function and any error handlers. The request object provides the g attribute for that purpose.

In the following example, a before request handler authorizes the client and stores the username so that the route function can use it:

@app.before_request
async def authorize(request):
    username = authenticate_user(request)
    if not username:
        return 'Unauthorized', 401
    request.g.username = username

@app.get('/')
async def index(request):
    return f'Hello, {request.g.username}!'

Request-Specific After-Request Handlers

Sometimes applications need to perform operations on the response object before it is sent to the client, for example to set or remove a cookie. A good option to use for this is to define a request-specific after-request handler using the after_request decorator. Request-specific after-request handlers are called by Microdot after the route function returns and all the application-wide after-request handlers have been called.

The next example shows how a cookie can be updated using a request-specific after-request handler defined inside a route function:

@app.post('/logout')
async def logout(request):
    @request.after_request
    def reset_session(request, response):
        response.set_cookie('session', '', http_only=True)
        return response

    return 'Logged out'

Request Limits

To help prevent malicious attacks, Microdot provides some configuration options to limit the amount of information that is accepted:

  • max_content_length: The maximum size accepted for the request body, in bytes. When a client sends a request that is larger than this, the server will respond with a 413 error. The default is 16KB.

  • max_body_length: The maximum size that is loaded in the body attribute, in bytes. Requests that have a body that is larger than this size but smaller than the size set for max_content_length can only be accessed through the stream attribute. The default is also 16KB.

  • max_readline: The maximum allowed size for a request line, in bytes. The default is 2KB.

The following example configures the application to accept requests with payloads up to 1MB in size, but prevents requests that are larger than 8KB from being loaded into memory:

from microdot import Request

Request.max_content_length = 1024 * 1024
Request.max_body_length = 8 * 1024