Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes
Sponsored Reserved space — layout preview until AdSense is connected

Tutorial

How to Build a REST API From Scratch in Under an Hour

Learn to build a complete REST API using Python's FastAPI in under 60 minutes. This step-by-step tutorial covers setup, models, endpoints with GET/POST/DELETE, and testing—no prior API experience needed.

June 2026 · 12 min read · 1 views · 0 hearts

How to Build a REST API From Scratch in Under an Hour

Most developers think building a REST API takes days of boilerplate setup, routing headaches, and debugging curl commands. It doesn't have to. With Python's FastAPI—a modern, async-first web framework—you can go from empty folder to working endpoints in under 60 minutes, even if you're new to APIs.

Why FastAPI Wins for Speed

FastAPI is built on Starlette and Pydantic. It auto-generates OpenAPI documentation, handles JSON validation out of the box, and runs async by default. No Flask-style decorator spaghetti needed.

What we'll build: A simple book library API. Users can list books, add new ones, fetch a book by ID, and delete books. That's enough to cover GET, POST, GET/{id}, and DELETE methods—the core of any RESTful service.

Step 1: Set Up Your Environment (5 minutes)

Create a new folder and install just three packages:

mkdir book-api
cd book-api
python -m venv venv
source venv/bin/activate   # On Windows: venv\Scripts\activate
pip install fastapi uvicorn

That's it. No database drivers yet—we'll use an in-memory list for speed. You can swap in SQLite or PostgreSQL later.

Step 2: Define a Model (5 minutes)

Create a file called main.py. The first few lines define what a book looks like:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List

app = FastAPI(title="Book Library API")

class Book(BaseModel):
    id: int
    title: str
    author: str
    year: int

class BookCreate(BaseModel):
    title: str
    author: str
    year: int

Book is the full model with an ID. BookCreate is what the client sends when adding a book—no ID, because the server assigns that. Pydantic handles validation automatically: if someone sends year="abc", they get a clean 422 error.

Step 3: Seed Some Data (2 minutes)

Add a tiny in-memory store right below the models:

books_db = [
    Book(id=1, title="The Pragmatic Programmer", author="Andrew Hunt", year=1999),
    Book(id=2, title="Clean Code", author="Robert C. Martin", year=2008),
]

next_id = 3

Yes, a global list. It works perfectly for learning. In production, you'd swap this for a database cursor. The next_id counter ensures IDs are auto-incrementing.

Step 4: Write the Endpoints (15 minutes)

Now the fun part. Each HTTP method maps to a Python function with a decorator.

GET all books

@app.get("/books", response_model=List[Book])
async def get_books():
    return books_db

FastAPI's response_model ensures the output matches the Book schema. If you accidentally return extra fields, they get dropped.

GET a single book by ID

@app.get("/books/{book_id}", response_model=Book)
async def get_book(book_id: int):
    for book in books_db:
        if book.id == book_id:
            return book
    raise HTTPException(status_code=404, detail="Book not found")

Path parameters are clean. The {book_id} syntax tells FastAPI to parse that part of the URL as an integer.

POST a new book

@app.post("/books", response_model=Book, status_code=201)
async def create_book(book: BookCreate):
    global next_id
    new_book = Book(id=next_id, **book.dict())
    books_db.append(new_book)
    next_id += 1
    return new_book

status_code=201 is the proper RESTful response for resource creation. The **book.dict() unpacks the validated fields into the Book constructor.

DELETE a book

@app.delete("/books/{book_id}", status_code=204)
async def delete_book(book_id: int):
    for idx, book in enumerate(books_db):
        if book.id == book_id:
            books_db.pop(idx)
            return
    raise HTTPException(status_code=404, detail="Book not found")

A 204 No Content means "successful deletion, nothing to show." Clean.

Step 5: Run It (1 minute)

In your terminal, start the server:

uvicorn main:app --reload

The --reload flag auto-restarts the server when you change code—essential for rapid iteration.

Open your browser to http://127.0.0.1:8000/docs. You'll see Swagger UI, generated automatically from your code. You can test every endpoint right there—no Postman needed.

Step 6: Test It (5 minutes)

Try these curl commands in another terminal window, or just use the Swagger UI:

# Get all books
curl http://127.0.0.1:8000/books

# Get a specific book
curl http://127.0.0.1:8000/books/1

# Add a new book
curl -X POST http://127.0.0.1:8000/books \
  -H "Content-Type: application/json" \
  -d '{"title":"Refactoring","author":"Martin Fowler","year":1999}'

# Delete a book
curl -X DELETE http://127.0.0.1:8000/books/2

Every response includes proper HTTP status codes and JSON bodies. You'll notice FastAPI returns validation errors with helpful messages if you send bad data.

Optional: Add a Database in 5 Minutes

If you want persistence, swap the in-memory list for SQLite. Add a single extra package:

pip install databases sqlite3

Then replace the in-memory operations with async queries. FastAPI's dependency injection system makes this clean—you define a function that returns a database connection, and endpoints call it. But honestly, for learning, the in-memory approach is fine.

What You've Learned

In under an hour, you've: - Created a complete REST API with four endpoints - Handled request validation automatically - Generated interactive API docs - Used proper HTTP status codes - Built something testable and extensible

The same pattern scales to hundreds of endpoints. Add authentication with FastAPI's Depends(), connect to PostgreSQL with SQLAlchemy, and deploy to Railway or Fly.io—each step takes less than 30 minutes. The hard part (getting the first API running) is already done.

Comments

Questions, corrections, and tips stay visible for everyone reading this page.

0 in thread

Join the discussion

Shown next to your comment.

Up to 4,000 characters

No comments yet

Be the first to leave a note — it helps the next reader.