How to Build RESTful APIs? The Unknown Hero Under The Hood (Part 2)

Fahmi Al-Najjar
Edraak Engineering
Published in
6 min readJan 17, 2021

In Part 1, we talked about how applications communicate and interact with each other, we said that each service has its own API and we use REST to provide a unified style of designing an API and to set a list of constraints to standardize how applications communicate with each other. We talked about the 6 main constraints of REST, and lastly, we discussed the benefits of REST.

How to build a REST API?

Photo by Nubelson Fernandes on Unsplash

Imagine that you are working in a big online learning platform and you have been requested to build a Course Service that provides CRUD (create, read, update, and delete) methods to deal with a course resource.

First, let’s go through DOs and DONTs, important principles, and best practices in RESTful APIs then I’ll walk you through hands-on steps on how you can build your RESTful API.

RESTful API Best Practices

  • Keep it simple
  • Use nouns instead of verbs unless you are based on business actions and you really need them
# GOOD
/courses
/courses/<int:course_id>
# BAD
/get_courses
/get_course/<int:course_id>
  • Use URL parameters for filtering, pagination, ordering, and any other use case
# GOOD
/courses?name=python&page=1
# BAD
/python_courses
  • Use nested resources for data relationships
    For example, if you have many lessons for each course the URL would be as follows:
# GOOD
/courses/88/lessons
# BAD
/lessons
  • Use the right HTTP methods
CRUD operations for course resource
  • Use the right HTTP status codes
    There are many HTTP status codes but the following are the most used ones:
Sample of HTTP Status Codes
  • Use pagination
    It’s highly recommended to use pagination in your API to prevent returning huge data. Let’s say that a client requested all courses, the result could be a massive response.
  • Unify your API content format
    You should decide if your requests and responses will be in JSON or XML format.
  • Handle errors
    You should return the HTTP status code that indicates what kind of error occurred with some informative details to eliminate confusion.
  • API documentation
    You should provide your clients with clear API documentation to inform them about how they can communicate with your service. For each API endpoint, you should include endpoint URL, expected request data, expected headers, a sample of the response, and a list of errors that could happen when calling the endpoint. I would recommend Swagger as a good tool for generating API documentation.

There are numerous ways of building a REST API but I would like to show you an example of my favorite one. Let’s walk through steps on how you can build a RESTful API for this service:

Step 0: Installation

  • We’ll use Python3.x so make sure that you have Python3.x installed on your machine
  • We’ll use SQLite as it’s easy for this demonstration purpose
  • We’ll create a virtual Python environment for our application using virtualenv

Step 1: Set up the application

  • First, create a directory for this application called course_service , the structure of your application will look like this:
course_service
|-- app
| |-- __init__.py # App entry point
| |-- api.py # API endpoints
| |-- errors.py # API errors
| |-- models.py # App models
| |-- configs.py # App configurations
|-- requirements.txt # App dependencies and requirements
  • Next, create a virtual environment for the application called venv :
$ cd course_service
$ virtualenv -p python3 venv
  • Activate the virtual environment:
$ source venv/bin/activate
  • Now add the application requirements to the requirements.txt file. The good thing about Flask that it’s a micro-library and you can add extensions to your application as you need.

We’ll be using Flask microframework, Flask-Restful extension to add support for REST APIs, Flask-SQLAlchemy extension to add support for SQLAlchemy, Flask-Script to provide support for writing command-line scripts, Flask-Migrate to handle SQLAlchemy database migrations for the Flask application, marshmallow (ORM/ODM/framework-agnostic library) to convert complex data types, such as objects, to and from native Python datatypes, and marshmallow-sqlalchemy because Flask-SQLAlchemy integration requires it to be installed:

Step 2: Install application requirements

Download and install all application requirements that we added to the requirements.txt file:

$ pip install -r requirements.txt

Step 3: Configure the application

Add the following configurations to the app/configs.py module, configurations might be database configs, debug mode, and so on:

Step 4: Create errors module

The app/errors.py module contains all errors that might occur in the API methods. There are two errors that might occur in the API methods, NoDataProvided which will be raised if a client didn’t send data with the request and CourseAlreadyExist if there is an existing course in the database with the same provided course name (course name is a unique field).

Step 5: Create the application entry point

The app/__init__.py module will be the entry point of our application, it initializes a new Flask application with the given configurations and it defines resource routing.

As you can see, I’m connecting the API errors dictionary with the API object, it will tell the API class to handle the errors that are defined in the app/errors.py module. You just have to raise exceptions in the API methods and it will take care of returning the response for clients.

Both /courses/<int:course_id> and /courses URLs route to the CourseAPI class.

Flask provides a great command-line interface (CLI). But, it only supports three commands, such as flask routes that shows the routes for the app, flask run that runs a development server, and flask shell that runs a shell in the app context. We want to add an extra extension to the Flask CLI which is flask db in order to perform database migrations, the following line does that:

Migrate(app=app, db=db)

Step 6: Create the models

In the app/models.py module, create a simple Course model (resource) that has an id as the primary key and a name field. CourseSchema uses marshmallow to define the output format (serialization/deserialization) of a course object.

Step 7: Create API endpoints

Flask-Rest provides a Resource class that defines routing from any given URL to the intended HTTP method. Define CourseAPI in the app/api.py module.

CourseAPI class will have 4 methods, a get method to handle course/s retrieve (either a list of courses or a specific course), a create method to handle course creation, a put method to handle updates for a specific course, and delete to delete a specific course.

As you can see, we’re using pagination in the get method to prevent returning a huge list of courses.

Step 8: Run the application server

  • First, initialize the database for the application. This command creates a new migration directory:
flask db init
  • Next, generate migration scripts (Python scripts) for the new models with detected changes, as in our case, a migration script to create the courses table:
$ flask db migrate
  • Run the generated migrations to apply them to the database:
$ flask db upgrade
  • Finally, you are good to go:
$ flask run

Try to manipulate a course resource using the CRUD-operations. You can use the basic CURL command or any other tool like Postman:

  • [GET, POST]: localhost:5000/api/courses
  • [GET, PUT, DELETE]: localhost:5000/api/courses/{ID}

I pushed the code of the application to Github, you can check it out at this link: https://github.com/Fahminajjar/rest-api-example

Conclusion

In case you need to communicate superior, APIs are the way to go, but if you designed them badly it will increase confusion. So you should design them very well.

Hopefully, you can now build your own REST API using Flask. I would like to thank you for going through this article, don’t forget to give it a few claps if you like it.

--

--