Self-paced

Explore our extensive collection of courses designed to help you master various subjects and skills. Whether you're a beginner or an advanced learner, there's something here for everyone.

Bootcamp

Learn live

Join us for our free workshops, webinars, and other events to learn more about our programs and get started on your journey to becoming a developer.

Upcoming live events

Learning library

For all the self-taught geeks out there, here is our content library with most of the learning materials we have produced throughout the years.

It makes sense to start learning by reading and watching videos about fundamentals and how things work.

Search from all Lessons


LoginGet Started
← Back to Lessons
Edit on Github

Starting a project for API Development (with Flask)

How to Start coding?
Adding an endpoint

🎥 Here's a video tutorial about creating Flask API's using this boilerplate.

How to Start coding?

Starting with the flast-rest-hello boilerplate, you can find an example API working with a database. All your application code should be written inside the ./src/ folder.

  • src/app.py: It's where the app initializes, in small API's you can also code your different endpoints here, please be advised that coding the endpoints here is only recommended if there is no routes.py file in the project already.
  • src/routes.py (optional): If your project has a src/routes.py file, here is where you must code to add your endpoints.
  • src/models.py: Your database tables and serialization logic.
  • src/utils.py: Some reusable classes and functions.
  • src/admin.py: Add your models to the admin and manage your data easily.

For a more detailed explanation, look for the tutorial inside the docs folder.

Installing on Ubuntu, Mac and Windows

⚠️ Make sure you have python 3.6+ (Here we have a step-by-step guide of how to install python), pipenv (On this article, we explain what is pyenv and how to install pyenv) and Postgres installed on your computer, then make sure Postgres is running, and run the following commands:

1$ pipenv install # (to install pip packages) 2$ pipenv run migrate # (to create the database) 3$ pipenv run start # (to start the flask webserver)

⚠️ Local installation may work, but you can also try installing it online through 4Geeks' Click and Learn on top of Github Codespaces or Gitpod.

Adding an endpoint

For each endpoint you will need to have:

  1. One @app decorator that specifies the path for the endpoint.
    • You can have parameters in the URL like this <int:person_id>
    • You can specify what methods can be called on that endpoint like this methods=['PUT', 'GET']
  2. The method that will execute when that endpoint is called (in this case get_single_person).
  3. Inside the method you can specify what logic to execute of each type of request using if request.method == 'PUT'
  4. You have to always return a json and a status code (200, 400, 404, etc.)
1@app.route('/person/<int:person_id>', methods=['PUT', 'GET']) 2def get_single_person(person_id): 3 """ 4 Single person 5 """ 6 body = request.get_json() #{ 'username': 'new_username'} 7 if request.method == 'PUT': 8 user1 = Person.query.get(person_id) 9 user1.username = body.username 10 db.session.commit() 11 return jsonify(user1.serialize()), 200 12 if request.method == 'GET': 13 user1 = Person.query.get(person_id) 14 return jsonify(user1.serialize()), 200 15 16 return "Invalid Method", 404

How to validate request payload or query string


Let's say a request is coming from the client and we need to make sure it contains the right information.

We have to use conditionals to make the validations, if we want to validate the request body we have to retrieve it first and then add the condition, like this:

1body = request.get_json() 2if 'username' not in body: 3 raise APIException('You need to specify the username', status_code=400)
  • It's a good practice to raise exceptions because it will stop the code execution.
  • It's a good practice to return 400 because that way the client knows it was his mistake and not ours (the server).

Here is a full example of a POST request to add a new person into a database

1@app.route('/person', methods=['POST']) 2def handle_person(): 3 4 # First we get the payload json 5 body = request.get_json() 6 7 if body is None: 8 raise APIException("You need to specify the request body as a json object", status_code=400) 9 if 'username' not in body: 10 raise APIException('You need to specify the username', status_code=400) 11 if 'email' not in body: 12 raise APIException('You need to specify the email', status_code=400) 13 14 # at this point, all data has been validated, we can proceed to insert into the database 15 user1 = Person(username=body['username'], email=body['email']) 16 db.session.add(user1) 17 db.session.commit() 18 return "ok", 200

The Database

The Flask boilerplate comes with a Postgres database installed and running, take 6 min to watch this video about Postgres.

We also use SQLAlchemy to abstract our database, that means that you don't have to write SQL to deal with your database, everything will be done using python.

Add, Update & Delete data

Since we are not going to be using SQL directly, instead we are going to be working with SQLAlchemy using Python.

Flask Admin

Any API developed using this boilerplate will come with a quick and easy UI called: Flask Admin.

The flask admin allows you to quickly see, add, delete or update information from your database tables.

You can access your flask admin by adding /admin to the end of your API Host, for example:

If your API host is https://8000-blabla-us33.gitpod.io then you can access your database admin like this: https://8000-blabla-us33.gitpod.io/admin

🎥 Here is an 8 min video explaining the Flask Admin.

Adding your models to your Flask admin

With just a couple lines of code you can integrate your model into the Flask Admin, for example, if you have a Car model you can add the model into the admin like this:

1from models import Car 2... 3admin.add_view(ModelView(Car, db.session))

But you have to add those two lines inside the admin.py file like this:

1from flask_admin.contrib.sqla import ModelView 2from flask_admin import Admin 3from models import db, Car # < ------ Import the model 4 5def setup_admin(app): 6 admin = Admin(app, name='your_admin_name', template_mode='bootstrap3') 7 admin.add_view(ModelView(Car, db.session)) # < ------ Add the model to the admin

You can add as many models as you want, like this:

1from flask_admin.contrib.sqla import ModelView 2from flask_admin import Admin 3from models import db, Car, Person, Patient # < ------ Import the model 4 5def setup_admin(app): 6 admin = Admin(app, name='your_admin_name', template_mode='bootstrap3') 7 admin.add_view(ModelView(Car, db.session)) # < ------ Add the model to the admin 8 admin.add_view(ModelView(Person, db.session)) # < ------ Add the model to the admin 9 admin.add_view(ModelView(Patient, db.session)) # < ------ Add the model to the admin

Migrations

Database changes are tracked using alembic migrations. You have to migrate and upgrade the migrations for every update you make to your models that must be reflected in the tables structure:

1$ pipenv run migrate #(to make the migrations) 2$ pipenv run upgrade #(to update your database with the migrations)

Reset Migrations

Sometimes the migration folder can get messed up, it's really hard to fix some of the issues and, since we are still in development, it makes sense to reset the entire database and migrations.

This boilerplate contains a script that can help you to reset from scratch all your database in case you need it. To run it execute pipenv run reset_db, this will delete your entire database and rebuild it from the ground up, loosing all the data in the process. These are the actions that the script performs:

⚠️ Warning: your data will be lost

  1. Delete the entire migrations folder rm -R -f ./migrations.
  2. Create a new migration folder for flask flask db init
  3. Delete the database dropdb -h localhost -U gitpod example
  4. Create the database again createdb -h localhost -U gitpod example";
  5. Create the 'inaccent' extension psql -h localhost example -U gitpod -c 'CREATE EXTENSION unaccent;'
  6. Create the migration files again: pipenv run migrate
  7. Apply the migration files into your database pipenv run upgrade

⚠️ Note: Please remember, all your data will be lost.

Coding a typical CRUD operation

As an example, we are going to create a small API to manage a Person.

Adding Models

For each model you will have to declare a class with the model properties and a method serialize that returns a dictionary representation of the class:

1class Person(db.Model): 2 id = db.Column(db.Integer, primary_key=True) 3 username = db.Column(db.String(80), unique=True, nullable=False) 4 email = db.Column(db.String(120), unique=True, nullable=False) 5 6 # tell python how to print the class object on the console 7 def __repr__(self): 8 return '<Person %r>' % self.username 9 10 # tell python how to convert the class object into a dictionary ready to jsonify 11 def serialize(self): 12 return { 13 "username": self.username, 14 "email": self.email 15 }

📝 You can find more information on creating models here.

CRUD Operations

There are many ways to manipulate databases, but we decided to use Python and SQLAlchemy to do so. This means that you need no SQL knowledge, but we strongly recommend you still practice and master SQL for debugging purposes (most of the errors are shown in SQL language)

Querying (SELECT) data

Assuming you have a Person object in your models.py file.

1# get all the people 2people_query = Person.query.all() 3 4# get only the ones named "Joe" 5people_query = Person.query.filter_by(name='Joe') 6 7# map the results and your list of people inside of the all_people variable 8all_people = list(map(lambda x: x.serialize(), people_query)) 9 10# get just one person 11user1 = Person.query.get(person_id)

Inserting data

Assuming you have a Person object in your models.py file.

1user1 = Person(username="my_super_username", email="my_super@email.com") 2db.session.add(user1) 3db.session.commit()

Updating data

1user1 = Person.query.get(person_id) 2if user1 is None: 3 raise APIException('User not found', status_code=404) 4 5if "username" in body: 6 user1.username = body["username"] 7if "email" in body: 8 user1.email = body["email"] 9db.session.commit()

Delete data

1user1 = Person.query.get(person_id) 2if user1 is None: 3 raise APIException('User not found', status_code=404) 4db.session.delete(user1) 5db.session.commit()

How to implement a JWT schema on my API with Flask?

In this article you will find the details about how to implement this schema on your Flask API

Deploy

This template is 100% compatible with Heroku and Render.com, just make sure to read the quick deployment guides.

  1. How to deploy into Render.com (for free)
  2. How to deploy into Heroku.com (for $0.01 a month)