October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk6 min

Build a Small JSON REST API with Flask, Step by Step

Create a small Flask JSON API with routes for a resource, explicit error responses, an application factory, tests, and a clear path from local development to deployment.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To build a small REST API with Flask, define routes for a resource, accept and return JSON, give errors explicit HTTP statuses, and test the app through Flask’s test client. This tutorial builds an in-memory book collection with list, create, retrieve, replace, and delete operations. It uses a small app factory so the same application can be configured for testing. The example is intentionally a starting point: it does not add authentication, database persistence, validation libraries, or API versioning.

What this tutorial builds

The API represents books at /api/books. It supports these operations:

As an Amazon Associate I earn from qualifying purchases.

Request Purpose Success response
GET /api/books List books 200 OK with a JSON array
POST /api/books Create a book 201 Created with the new book
GET /api/books/<id> Retrieve one book 200 OK with a JSON object
PUT /api/books/<id> Replace a book’s fields 200 OK with the updated book
DELETE /api/books/<id> Delete a book 204 No Content

These are tutorial choices, not a required Flask layout or a universal REST rule. Flask is flexible; its official tutorial demonstrates one structured approach using an application factory. This example keeps the data in memory, so it resets whenever the process restarts.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install Flask and create the application

Use a virtual environment, then install Flask:

python -m venv .venv
# macOS or Linux:
. .venv/bin/activate
# Windows PowerShell:
.venvScriptsActivate.ps1
python -m pip install Flask

Create a file named app.py. The factory initializes the Flask application and registers its routes. The in-memory dictionary is deliberately simple; it is not suitable for durable or multi-process storage.

from flask import Flask, jsonify, request


def create_app(test_config=None):
    app = Flask(__name__)
    app.config.from_mapping(SECRET_KEY="dev")

    if test_config is not None:
        app.config.update(test_config)

    # Teaching-only storage: data disappears on restart and is not shared
    # across separate worker processes.
    app.books = {}
    app.next_book_id = 1

    @app.get("/api/books")
    def list_books():
        return list(app.books.values())

    @app.post("/api/books")
    def create_book():
        data = request.get_json(silent=True)
        if not isinstance(data, dict):
            return {"error": "Expected a JSON object."}, 400

        title = data.get("title")
        if not isinstance(title, str) or not title.strip():
            return {"error": "A non-empty title is required."}, 400

        book = {
            "id": app.next_book_id,
            "title": title.strip(),
            "author": data.get("author", ""),
        }
        app.books[book["id"]] = book
        app.next_book_id += 1
        return book, 201

    @app.get("/api/books/<int:book_id>")
    def get_book(book_id):
        book = app.books.get(book_id)
        if book is None:
            return {"error": "Book not found."}, 404
        return book

    @app.put("/api/books/<int:book_id>")
    def replace_book(book_id):
        if book_id not in app.books:
            return {"error": "Book not found."}, 404

        data = request.get_json(silent=True)
        if not isinstance(data, dict):
            return {"error": "Expected a JSON object."}, 400

        title = data.get("title")
        if not isinstance(title, str) or not title.strip():
            return {"error": "A non-empty title is required."}, 400

        book = {
            "id": book_id,
            "title": title.strip(),
            "author": data.get("author", ""),
        }
        app.books[book_id] = book
        return book

    @app.delete("/api/books/<int:book_id>")
    def delete_book(book_id):
        if book_id not in app.books:
            return {"error": "Book not found."}, 404
        del app.books[book_id]
        return "", 204

    return app


app = create_app()

Flask converts returned dictionaries and lists to JSON responses. Values in those structures still need to be JSON-serializable: if you later return a database model, convert it to ordinary values such as strings, numbers, lists, and dictionaries first. The official Quickstart explains this behavior in About Responses.

Run the API and send requests

For local development, start Flask from the directory containing app.py:

flask --app app run --debug

Use another terminal to create a book. The request’s JSON content type tells Flask to parse its body as JSON:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -i -X POST http://127.0.0.1:5000/api/books 
  -H "Content-Type: application/json" 
  -d '{"title":"The Left Hand of Darkness","author":"Ursula K. Le Guin"}'

The response has status 201 Created and a JSON body similar to:

{
  "author": "Ursula K. Le Guin",
  "id": 1,
  "title": "The Left Hand of Darkness"
}

Then retrieve the collection and the individual record:

curl http://127.0.0.1:5000/api/books
curl http://127.0.0.1:5000/api/books/1

Try a replacement with PUT using a JSON object with a title, then delete the record:

curl -i -X PUT http://127.0.0.1:5000/api/books/1 
  -H "Content-Type: application/json" 
  -d '{"title":"The Dispossessed","author":"Ursula K. Le Guin"}'

curl -i -X DELETE http://127.0.0.1:5000/api/books/1

In this example, PUT replaces the fields the resource stores; it is not a partial update. A partial-update operation would need its own defined behavior and request validation.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep failures useful and consistent

The example returns an error property for expected client mistakes and missing records. It pairs the JSON body with a meaningful status: malformed or incomplete input gets 400, and an unknown book ID gets 404. A client can inspect the status without having to infer success or failure from the response text.

For larger APIs, centralize error formatting instead of repeating response construction in each route. Flask supports handlers for HTTP exceptions and custom exceptions. When an error handler constructs a response, return the intended status explicitly; registering a handler for a particular code does not automatically apply that code to the response. See Flask’s guide to Returning API Errors as JSON.

This small example only checks that the body is an object and that title is a non-empty string. It does not define a complete schema, field-length limits, or authentication rules. Those are separate API decisions, and should be implemented deliberately rather than assumed to come from Flask.

Why use an application factory?

create_app builds and returns an application instead of configuring the app only as a module-level global. That makes it practical to pass testing or other configuration when creating an instance, and to register routes and extensions in one setup point. A single-file application is fine for a tiny demonstration; the factory becomes more helpful as configuration and tests grow.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

As the project expands, move related endpoints into a blueprint and register it inside the factory. For Flask extensions, the documented pattern is to define the extension object separately, then initialize it with the app inside the factory. See the official guide to Application Setup.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Add persistence when the API needs it

The in-memory dictionary makes the route behavior easy to see, but it loses all records when the app stops and does not coordinate data between worker processes. For a small persistent learning project, Flask’s tutorial demonstrates SQLite: open a connection using the application context and close it during app-context teardown. SQLite is an option shown by Flask’s tutorial, not a requirement of Flask or a universal production database choice. The tutorial’s database pattern is documented in Define and Access the Database.

Test routes with a separate app instance

Factories let tests create an app with testing configuration, then exercise routes through Flask’s test client without starting a live server. Here is a minimal pytest test in test_app.py:

import pytest
from app import create_app


@pytest.fixture
def client():
    app = create_app({"TESTING": True})
    return app.test_client()


def test_create_and_retrieve_book(client):
    created = client.post(
        "/api/books",
        json={"title": "Kindred", "author": "Octavia E. Butler"},
    )
    assert created.status_code == 201
    book_id = created.json["id"]

    retrieved = client.get(f"/api/books/{book_id}")
    assert retrieved.status_code == 200
    assert retrieved.json["title"] == "Kindred"


def test_missing_book_is_json_404(client):
    response = client.get("/api/books/999")
    assert response.status_code == 404
    assert response.json == {"error": "Book not found."}

Install the test runner with python -m pip install pytest and run pytest from the project directory. Each fixture-created application starts with an empty in-memory collection, so the tests do not depend on request order. Flask documents the factory fixture and test-client approach in its Testing Flask Applications guide.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use a production server when deploying

The Flask development server and interactive debugger are for local work, not production traffic. Flask’s production guide states: “Do not use the development server when deploying to production.” Use a production WSGI server or a hosting platform configured to run the application. Waitress is one example in the Flask documentation; it is not the only deployment option. Follow the current Deploying to Production guidance for the server and platform you choose.

Before deployment, replace the in-memory data store with persistence appropriate to the application, configure secrets outside source code, and decide how the API should handle authentication, input validation, logging, and operational limits. Those concerns are not supplied automatically by these routes.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.