13 minutes read

It's time to refine our Flask skills and learn some important concepts. Today, we will talk about requests. They may seem relatively simple: a client sends a request; a server responds to it and sends a response back. Programming this sequence requires some amount of practical knowledge. We will cover it in this topic. Ready? Go!

Requests and responses as objects

Let's talk about the basics first. As you may know, there are two main request types — GET and POST. Don't forget that these are only the names; HTTP does not oblige you to use GET to obtain information and POST to forward it. Though that is what is most often implied. With the help of HTTP requests, we can send data, receive a response, and establish a connection between our computer and a server via the HTTP protocol. You can say that everything sounds familiar, then why repeat? That's a good point to step in and start discussing Flask features.

All data transmissions in Python are processed as objects. Namely, a request and response. As you may have guessed, these objects contain data about a request or response that a server sent or received. When you create an application, run it, and open the URL (127.0.0.1:5000), the browser sends a request logged in to the console immediately. If everything is fine, you will see the 200 response status code:

200 response status code

You can see that first is the IP address of the client who accessed our application (127.0.0.1), the time the request was received, the request type, the requested address, and the final server response — an HTTP code.

All these things are available in Flask, thanks to a library called Werkzeug. We will mention it here and there because Flask draws on it. We'll cover the library in detail in later topics. Still, it is essential (and enough) to say that Werkzeug provides a set of utilities to enable a Python application to communicate to a web server by processing requests and responses.

Processing requests

Now, let's write our application that will handle requests and see how we can process them. Imagine that we want to create an authorization system. What do we need? That's right — a page that will have a form for a username and password. It will send the data to the server as an authentication request.

Firstly, we need to import Flask as well as request, a new object we will work with:

from flask import Flask
from flask import request

The imported request is a global object that Flask uses to put the correct incoming request data in it. The request object is an instance of a built-in Request (note the capital letter!) subclass. Since we are not sending but mostly accepting requests, we don't need to create any new instances. It may sound a bit confusing, but at this point, let's carry on with the global object idea.

Once the import is complete, we can create our application:

app = Flask('main')

Ok, the foundation is ready. Now it's time to build the central part of the program. Before writing a function, we route the page using the familiar decorator. Note that this time, we add the methods parameter to show Flask which requests our app will accept:

@app.route('/', methods=['POST', 'GET'])

Flask route only answers to GET requests by default. Pass them into the list when defining the decorator to make the route able to handle other requests.

Now, let's declare a view function called login.

With the help of the method attribute of the request object, we can determine the request type and specify the behavior of the application:

def login():
    if request.method == 'GET':
        template = """
        <form method='POST'>
        <input type='text' placeholder='Username...'>
        <input type='password' placeholder='Password...'>
        <input type='submit' value='Auth'>
        </form>
        """
        return template

    elif request.method == 'POST':
        return 'Wow! Great, you logged in!'

We have created a template that we will show on the login page. You'll study building and showing templates in detail later. For now, you can copy and paste the template string into your code to make everything work.

Finally, let's launch our app:

app.run()

What it looks like

Run the program and make sure that everything works. You will see the following messages in the console:

template string into code

Now we can go to the app page and see how everything works:

empty page creation

Let's enter some data (even though, for now, it is just a formality, as the authorization system is not implemented) and click on the button. We will see the message that we specified earlier:

displayed message on the page

Wonderful! We can use the conditional construction and the request object, the method attribute, in particular, to determine whether users send data to us or want to see a web page. Below you can see the entire code:

from flask import request
from flask import Flask


app = Flask('main')

@app.route('/', methods=['POST', 'GET'])
def login():
    if request.method == 'GET':
        template = """
        <form method='POST'>
        <input type='text' placeholder='Username...'>
        <input type='password' placeholder='Password...'>
        <input type='submit' value='Auth'>
        </form>
        """
        return template

    elif request.method == 'POST':
        return 'Wow! Great, you logged in!'


app.run()

Query parameters

Using query strings or query parameters is another way to send data with your request. They are added to the main request URL, separated by a question mark ?. Query parameters are made of key=value pairs separated by an ampersand &. An example request URL with a query string looks like this:

http://127.0.0.1:5000/users?city=London&age=20

Query parameters are commonly used for filtering or limiting data. In the example above, say we have a /users endpoint that returns all the users present in a database. Sometimes, we don't need them all, and that's where it's easier to specify what kind of users the client exactly wants to see, even before sending a request. In this case, the server will filter only users from London, age 20.

Query parameters are also stored in the request object. You'll need its args attribute:

@app.route('/users')
def users():
    query_params = request.args  # returns a dictionary
    city = query_params.get("city")
    age = query_params.get("age")
    # ... do your magic with the params
    # considering you've had the predefined method 'get_users' for retrieving users
    result = get_users(city, age)
    return result

As the args attribute returns a dictionary; you can use the standard dictionary methods. Here, we've retrieved parameters via get() method to avoid crashing with the KeyError exception.

Besides method and args attributes, the request object has a few more frequently used properties. We will cover some of them in the following topics, but if you're curious now, you can check out the class flask.Request part of the documentation.

Conclusion

In this topic, we have found that we work with requests and responses as with objects in Flask. We have also learned how to process different types of requests with a view function, discovered what query parameters are, and tried to return different messages. Let's go and practice what we have learned!

47 learners liked this piece of theory. 1 didn't like it. What about you?
Report a typo