• Labs icon Lab
  • Core Tech
Labs

Guided: Building a RESTful API with Flask

Unlock the power of Flask and learn to build a robust RESTful API in this hands-on Code Lab. You’ll implement CRUD operations for a user management system while mastering JSON data handling, request validation with Marshmallow, and returning appropriate HTTP status codes. Gain practical experience in designing, validating, and testing API endpoints, ensuring your APIs are both reliable and scalable. Whether you’re new to Flask or looking to deepen your API development expertise, this Code Lab provides the perfect blend of theory and real-world application to level up your skills.

Labs

Path Info

Level
Clock icon Beginner
Duration
Clock icon 1h 1m
Published
Clock icon Feb 19, 2025

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Table of Contents

  1. Challenge

    Set Up the Project

    User Management API

    In this lab, you'll build an User Management API using Flask, SQLite, and Marshmallow. This project focuses on implementing a RESTful API for managing users, complete with input validation and database integration. You'll learn to handle common Create, Read, Update, and Delete (CRUD) operations while leveraging Marshmallow for schema validation to ensure your data is valid.


    What You'll Build

    The User Management API will allow clients to:

    1. Create Users: Add new users with validation for required fields like username, email, and password.
    2. Retrieve Users: Fetch a list of all users of retrieve a single user by ID.
    3. Update Users: Modify user details, such as their email or status.
    4. Delete Users: Remove users from the system. When working in your local environment, you would first need to install several dependencies for your project. Due to limitations in this environment, these are already installed to your instance. Here are a list of the dependencies:
    • flask: This is the web framework you'll use to build the API.
    • flask-sqlalchemy: This allows your framework to "talk" SQL and interact with relational databases. For this project, you'll use it to work with SQLite, a lightweight, file-based database.
    • flask-marshmallow: This is a library that integrates Marshmallow with Flask, making it easy to validate data schemas in your application.
    • marshmallow-sqlalchemy: This library enables Marshmallow to derive schemas directly from the SQLAlchemy models you create, reducing boilerplate and ensuring consistency.
    • flask-migrate: This library allows flask to handle incremental database migrations allowing for consistent changes across deployment environments.

    To install these dependencies in your local environment, you would need to run the following command:

    pip install flask flask-sqlalchemy flask-marshmallow marshmallow-sqlalchemy flask-migrate
    

    Here is the file structure you're going to follow:

    ├── /app
    │   ├── /models
    │   │   └── user.py        # User model definition
    │   ├── /schemas
    │   │   └── user_schema.py # Marshmallow schema for validation
    │   ├── /routes
    │   │   └── user_routes.py # User-related API routes
    │   ├── __init__.py        # App factory
    │   ├── extensions.py      # Initialise SQLAlchemy and Marshmallow
    │   └── config.py          # App configuration
    ├── run.py                  # Entry point
    ├── requirements.txt        # Python dependencies
    └── README.md               # Project documentation
    
  2. Challenge

    Define the Database Models

    Define the User Model Using SQLAlchemy

    In this step, you'll:

    • Configure the database in the Flask app.
    • Define the User model using SQLAlchemy.
    • Ensure that the database tables are created properly.

    Configure the Database in Flask

    SQLAlchemy is an Object Relational Mapper (ORM) that allows you to interact with databases using Python objects instead of raw SQL.

    First, modify the app/extensions.py file to set up SQLAlchemy so it can be used across the app. In the next task, you are going to make two extensions available to your application. These will allow interaction with the database and the ability to manage migrations. #### ✅ Why Do This?

    • This keeps your database setup separate from the main application logic.
    • You initialize the database once and import db wherever it's needed.

    Define the User Model

    Now, you will define the User model using SQLAlchemy. #### ✅ What This Does?

    • Configures SQLite (sqlite:///database.db)
    • Registers SQLAlchemy (db.init_app(app)) so it's linked to Flask
    • Ensures tables exist using db.create_all()

    Creating an App Factory

    In this step, you will implement an app factory pattern in Flask. This is a design pattern that allows you to create and configure a Flask application in a modular and reusable way. Instead of defining the app globally, you encapsulate its creation inside a function (create_app). This approach provides several benefits:

    • Modularity: The app factory allows you to separate the creation and configuration of the Flask app from the rest of the code. This makes it easier to manage and test the application.

    • Reusability: By using a factory function, you can create multiple instances of the app with different configurations (e.g., for testing, development, or production).

    • Dependency Management: The app factory ensures that extensions like SQLAlchemy and Flask-Migrate are properly initialized with the app instance, avoiding circular imports and ensuring clean separation of concerns. Now, you can migrate your database, which will create the database file and prepare it to persist your data.

    If you move away from SQLite, all you need to do is change the DATABASE_URI string.

    To initialize your database, run through these three commands:

    python3 -m flask db init
    python3 -m flask db migrate -m "Initial migration"
    python3 -m flask db upgrade
    

    As you make changes to the schema over time, you can run the migrate command to capture the incremental changes to your filesystem.

    Create an App Entry Point

    You can now use the factory you created to instantiate an instance of your app that you can run. The last task in this step is to create an Application Entry Point. With all of these steps completed, you should be able to run your development server with no errors. There are three approaches to this, and you can decide which you prefer.

    1. Use python3 to run app.py:

      	python3 run.py
      
    2. Use python3 to run the Flask library directly:

      	export FLASK_APP=run.py
      	python3 -m flask run
      
    3. Export the app name and run Flask directly:

      	export FLASK_APP=run.py
      	flask run
      

    You can try all three of these approaches in the Terminal and ensure the server starts without error. You haven't added any routes yet so you won't be able to view anything in your browser.

  3. Challenge

    Create Marshmallow Schema

    In this step, you will create the Marshmallow schema. This is used to serialize and deserialize between your database model and Python objects.

    You'll first register Marshmallow within your application and then use it to create your schema.

  4. Challenge

    Implement CRUD Endpoints

    Now, you are ready to start defining and configuring the routes for your API.

    As a RESTful API, you should use a consistent naming convention and HTTP methods to define your functionality.

    The resource will generally be plural and follow a pattern like the following:

    • GET /users - get all of the user resources
    • POST /users - create a new user resource
    • GET /users/<user_id> - get a particular user defined by their id
    • PUT /users/<user_id> - update a particular user
    • DELETE /users/<user_id> - delete a particular user

    With these routes defined, you'll have a complete RESTful CRUD API.

    Each of the following tasks will work through that CRUD cycle step-by-step.

  5. Challenge

    Test the API with `curl`

    As mentioned earlier, there are a few ways to start your API. You should start it in the first Terminal tab and then move to the second Terminal tab.

    python3 run.py
    

    Here are the curl commands to test the CRUD API for the /api/users routes of your API:

    1. Create a User (POST /api/users):

    curl -X POST http://localhost:5000/api/users 
         -H "Content-Type: application/json" 
         -d '{
               "username": "johndoe",
               "email": "johndoe@example.com",
               "password": "securepassword",
               "is_active": true
             }'
    

    Expected Response:

    {
      "id": 1,
      "username": "johndoe",
      "email": "johndoe@example.com",
      "is_active": true
    }
    

    2. Get All Users (GET /api/users):

    curl -X GET http://localhost:5000/api/users
    

    Expected Response:

    [
      {
        "id": 1,
        "username": "johndoe",
        "email": "johndoe@example.com",
        "is_active": true
      }
    ]
    

    3. Get a Single User by ID (GET /api/users/{user_id}):

    curl -X GET http://localhost:5000/api/users/1
    

    Expected Response:

    {
      "id": 1,
      "username": "johndoe",
      "email": "johndoe@example.com",
      "is_active": true
    }
    

    4. Update a User (PUT /api/users/{user_id}):

    curl -X PUT http://localhost:5000/api/users/1 
         -H "Content-Type: application/json" 
         -d '{
               "email": "john.doe@newdomain.com",
               "is_active": false
             }'
    

    Expected Response:

    {
      "id": 1,
      "username": "johndoe",
      "email": "john.doe@newdomain.com",
      "is_active": false
    }
    
    1. Delete a User (DELETE /api/users/{user_id}):
    curl -X DELETE http://localhost:5000/api/users/1
    

    Expected Response:

    {
      "message": "User deleted successfully"
    }
    

    Handling Errors

    User Not Found (GET)

    curl -X GET http://localhost:5000/api/users/999
    

    Expected Response:

    {
      "error": "User not found"
    }
    

    Invalid User Creation (POST - Missing Fields)

    curl -X POST http://localhost:5000/api/users 
         -H "Content-Type: application/json" 
         -d '{
               "username": "janedoe"
             }'
    

    Expected Response:

    {
      "error": "Missing required fields"
    }
    

    These curl tests cover all CRUD operations and common error scenarios for your Flask API. # Congratulations!

    You have now created a RESTful API that allows you to carry out CRUD operations on a given resource.

    These skills are transferable across different models or route sets you might build for a given operation.

    Good luck in your ongoing API building journey!

Kevin is a Developer Educator, speaker and writer based in beautiful Northern Ireland. He specializes in web development across a range of languages and frameworks.

What's a lab?

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Provided environment for hands-on practice

We will provide the credentials and environment necessary for you to practice right within your browser.

Guided walkthrough

Follow along with the author’s guided walkthrough and build something new in your provided environment!

Did you know?

On average, you retain 75% more of your learning if you get time for practice.