In order to create a nicely usable and developer-friendly web API, we need to be able to define separate access paths for the assets that we want to manage through the web API. These paths can be configured by defining custom routing inside Flask.
- [Instructor] Custom Routing Configuration. In the previous video, we looked at how to set up our development environment, and we created our first Flask application. In this video, we are going to take a look at how to configure routes inside the Flask application, how can we accept request parameters, and how can we convert these parameters to certain type of data. We will cover the basics of HTTP Verbs. We will start to lay down the first building blocks of the final project, which we will finish by the end of this video course. The idea of the project is to provide the web API for a database, which holds information about candidates.
The project will use standard HTTP protocol and we will use JSON as a data format. Now we will define a basing model for handling our data. We will create the Candidate, Experience, and Project classes. The candidates have an identifier which is unique and has Python's uuid type. Besides this, the candidate has first_name, last_name, and the collection of Experience objects. The Experience class has the main amount of years the candidate has experience with that domain, and possibly a list of projects that belong to that domain. The Project class also has an identifier, the same as the Candidate class has.
It has a name, description, start and end dates. The start and end date have the time type. These classes and the relationship between these will change during the course, as we add complexity to the API logic. These models are only getting started with the developing of the API. Now let's take a look at the Project class. It is a standard Python class, with class members. It has a constructor function, which receives parameters, name, start_date, end_date, and description. Inside the constructor function, we initialize the ID of the project.
For each class member, I define a getter and a setter. The more interesting part is the serialize method, which returns a dictionary with key value pairs. Keys representing the name of the properties of the class, like ID, name, start date, end date, and the actual values of the properties. We need to have this method because we want to have a Python dictionary-like representation of our object. You can ask why we need this. The response is fairly simple and logical.
Python dictionaries can be easily interpreted as JSON data. Since our web API will serve the clients using JSON data structure, it is convenient to have a dictionary-like representations of our object. The next code part we cover is the Experience class. The structure of the class is the same as in the case of the Project class. First we have the members, next the constructor function, then properties, and finally the serialize method. Inside the serialize method, I use Python's list comprehension feature, when serializing the project's list.
The third class which we will review is the Candidate class. This is very similar to the other two shown before. First we have members, then we have the constructor, then we have properties, and finally we have the serialize method. Besides the serialize method, we have another method, an Experience. Its name is self-explanatory, it adds to the experience list the newly passed experience parameter. Now let's take a look at the Flask application code.
To do this, let's open app.py file. Inside the code you can see highlighted the DataProviderService class. I created this service class to serve the data for the Flask application. At the current implementation, all the data with this class returns, is generated. But as we advance with the course, we will substitute the data generation logic to data loading logic from the database. I will cover the content of this class in a later video. Routing is used to bind a function or a piece of code to a URL. Inside Flask, routing can be configured in multiple ways.
One of the options is to use the app.route decorator. As you can see it in the code, this usually has two parameters. The first is the route bat, this is how we want to access the functionality from the web. The second is the list of HTTP verbs, which the method accept. These route will list all the available API paths defined for the application. Using the response given by this method on the client-side, we could build up a dynamic client for it. It's a best practice to have a route, which displays all the paths configured inside an application.
Another possibility is to define the methods we want to execute, when the client navigates to our path, and tries to use this method using the add URL method. This method has three parameters. The first is the path, the second is the endpoint, and the third is the function which we want to execute once the client navigates to a defined path. When developing a web API, there's a need to be able to specify dynamic routes. In this case, we define a variable HTTP request parameter, called ID.
We are using Flask request parameter converter to convert this to a string. Besides the string converter, there are converters for int, float, and path. This API can look up a candidate with a certain ID. If the candidate is found, it will return a new JSON with all the information about the candidate, otherwise it will send back HTTP 404 error code, which means the requested item was not found. The update method is more special, because here we use two dynamic parameters.
The first is the ID, and the second is the name, which we will assign to a new candidate. This method can be invoked only with the HTTP "PUT" verb. We usually use the PUT verb if we want to update some part of the data which we already have at server-side. In case we cannot find a candidate with the given ID, we abort it with HTTP 404. Otherwise, we return the number of updated items. Inside Flask, we can manipulate routes, and we can map multiple routes to one handler.
Here, for instance, we define the API random candidate rule. When a client application invokes this, the number of items parameter for the random method will have a value of one. This is because we specified this in the default objects. If the client application specifies the number of items parameter, then that gets automatically passed to the random method. In the delete method we remove the candidate from our list. The router's configured to be mapped with a delete HTTP verb.
In API perspective, the meaning of the delete HTTP verb is to remove an asset from the data store. We use the HTTP post method to send data from the client to the server-side. The post method is usually used when data comes to the API from a form. To access data entered into a form, we use the request object from the Flask application. This object has a form dictionary which contains key value pairs, sent from the client-side. We take the first name and last name parameters from the form dictionary, we create a new candidate, using the add candidate method.
This will return the ID of the newly created candidate. As a response, we send back the ID of the newly created candidate, and access path with it. We are using the url_for method, which have generate URL for our API, so we don't have to generate the URLs manually. The URL format takes two arguments: the endpoint which we want to generate the URL for, and the variable parameters. In our case, that is the ID of the new candidate. In the previous video, we had set up a development environment.
Now let's start the application with a Python app.py command, and take a look at some of the responses and results which we have. If we navigate to HTTP localhost:5000/api/candidate, then we will see all the candidates returned by our API. If we navigate to HTTP localhost:5000/api/candidate, and we specify an ID of a candidate, then our API will only return that instance of the candidate. If you want to create a new candidate, then we can use Postman, a Google Chrome extension, to build different HTTP requests.
In this case, I am sending a Post request to the http://localhost5000/api/candidate/ route. I set the form data parameters, first name, last name, email, and phone. When I press the Send button, in the lower region of the screen we can see the response coming from the API. The response contains an ID and a URL. If you press the send button multiple times, the response should always be different, because each time a new candidate is added to the data store on the server.
In this video, we covered some of the commonly used methods to set up routes within the Flask application. We covered what do HTTP get, post, put, and delete verbs stand for, and we reviewed the code for our first version of the API. In the next video, we will cover Flask templates, what are these, how to use them, and how to dynamically create websites using templates. Thank you for watching and see you in the next video.
Regardless of platform, you will need to build APIs to serve data between different client applications and endpoints. Good APIs are a necessity for web and mobile projects, especially with the modern, mobile-first approach to development. This course delivers the fundamental knowledge required to enable highly connected interactions between applications via RESTful web APIs. Follow along with Gergo Bogdan and learn how to build up and structure an effective web API that can be used by any client application accessing it over HTTP, using Flask, the Python microframework.
Find out how to implement CRUD operations using SQLAlchemy and MySQL as the data store. Get an understanding of how REST works relative to APIs, and learn how to test APIs written in Python with the support of Flask. Explore token-based authentication and find out how to store passwords securely in your database. Along the way, Gergo introduces best practices and design guidelines when building large applications.
- Setting up Flask
- Using Flask templates and routing
- Implementing CRUD operations
- Implementing pagination
- Configuring RESTful authentication
- HTTP caching
- Securing web APIs
- Testing the application