How to Create REST APIs in Python using FastAPI (Step-by-Step Guide)

Shaik SameerShaik Sameer
5 min read

Building APIs in Python has never been easier thanks to FastAPI. It’s modern, fast (high-performance), and super-friendly for developers — especially if you're already comfortable with Python.

In this guide, we’ll build a practical Product API — nothing generic, just clear and useful examples.


Topics Covered

  • What is FastAPI

  • How to install it

  • Build your first API (GET, POST, PUT, DELETE)

  • How to validate input using Pydantic

  • Try the API with Swagger UI

  • Recommended project structure

  • Final full code for reference


🧠 What is FastAPI?

FastAPI is a modern Python web framework designed for building APIs with:

  • Built-in data validation using Pydantic

  • Automatic documentation (Swagger/OpenAPI)

  • Type hints for clean code

  • Async support

  • Super performance (comparable to Node.js and Go)


Step 1: Install FastAPI and Uvicorn

To use FastAPI, you need to install it first. You also install Uvicorn, which is like a mini server to run your API.

Just type this in your terminal:

pip install fastapi uvicorn
  • fastapi: The main framework

  • uvicorn: A fast server to run your FastAPI app


Step 2: Create a Simple API

Let’s build a real-world example: Product Management API

You start by creating a file (e.g., main.py) and write some code that tells the computer what to do when someone visits certain links (like /products).

  • You use @app.get() to handle read requests.

  • You write a simple dictionary to store some product data.

  • You return that data when someone visits /products.

File: main.py

from fastapi import FastAPI

app = FastAPI()

# In-memory data storage (for simplicity)
products = {
    1: {"name": "Laptop", "price": 75000},
    2: {"name": "Smartphone", "price": 30000}
}

@app.get("/")
def home():
    return {"message": "Welcome to Product API"}

@app.get("/products")
def get_all_products():
    return products

@app.get("/products/{product_id}")
def get_product(product_id: int):
    if product_id in products:
        return products[product_id]
    return {"error": "Product not found"}

Run Your Server

Run this in terminal:

uvicorn main:app --reload

Now visit: http://127.0.0.1:8000/docs

🎉 You’ll see a beautiful Swagger UI to test your API.


Step 3: Add POST (Create Product)

To allow creating products, we need to accept input data and validate it.

To allow users to add a new product, you need to:

  • Accept user input

  • Make sure it's valid (like name and price are provided)

  • Save it

You use something called a Pydantic model (like a form) to check that the input is correct.

Create a Pydantic model:

from pydantic import BaseModel

class Product(BaseModel):
    name: str
    price: float

Add a POST endpoint:

@app.post("/products")
def create_product(product: Product):
    new_id = max(products.keys()) + 1 if products else 1
    products[new_id] = product.dict()
    return {"id": new_id, "product": products[new_id]}

product.dict() converts the Pydantic model into a normal Python dict.


Step 4: Add PUT (Update Product)

This lets users update a product that already exists.

  • It checks if the product exists.

  • If it does, it updates the name and price.

  • If it doesn’t, it shows an error message.

@app.put("/products/{product_id}")
def update_product(product_id: int, product: Product):
    if product_id not in products:
        return {"error": "Product not found"}
    products[product_id] = product.dict()
    return {"message": "Product updated", "product": products[product_id]}

Step 5: Add DELETE (Remove Product)

This lets users delete a product using its ID.

  • It checks if the product exists.

  • If yes, it removes it and returns a success message.

  • If no, it returns an error.

@app.delete("/products/{product_id}")
def delete_product(product_id: int):
    if product_id in products:
        deleted = products.pop(product_id)
        return {"message": "Product deleted", "product": deleted}
    return {"error": "Product not found"}

Step 6: Try It in Swagger UI

Visit:

You can test all your endpoints in the browser — no Postman needed.

Once your server is running, you can open http://127.0.0.1:8000/docs in your browser.

  • It shows all your API routes.

  • You can test everything (GET, POST, PUT,DELETE) without writing any code.


As your project grows, it’s better to keep your files organized.

  • Keep models (data structures) in models.py

  • Keep all routes (endpoints) in routes.py

  • Put everything in an app/ folder

  • Import these into your main app (main.py) to run everything together

When your app grows, split it into modules:

.
├── app
│   ├── main.py
│   ├── models.py
│   ├── routes.py
│   └── database.py (optional)
└── requirements.txt

Example: models.py

from pydantic import BaseModel

class Product(BaseModel):
    name: str
    price: float

Example: routes.py

from fastapi import APIRouter
from .models import Product

router = APIRouter()
products = {}

@router.post("/products")
def create_product(product: Product):
    ...

Then in main.py:

from fastapi import FastAPI
from app.routes import router

app = FastAPI()
app.include_router(router)

Full Final Code

Here’s the complete working code in one file for reference:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

products = {
    1: {"name": "Laptop", "price": 75000},
    2: {"name": "Smartphone", "price": 30000}
}

class Product(BaseModel):
    name: str
    price: float

@app.get("/")
def home():
    return {"message": "Welcome to Product API"}

@app.get("/products")
def get_all_products():
    return products

@app.get("/products/{product_id}")
def get_product(product_id: int):
    return products.get(product_id, {"error": "Product not found"})

@app.post("/products")
def create_product(product: Product):
    new_id = max(products.keys()) + 1 if products else 1
    products[new_id] = product.dict()
    return {"id": new_id, "product": products[new_id]}

@app.put("/products/{product_id}")
def update_product(product_id: int, product: Product):
    if product_id not in products:
        return {"error": "Product not found"}
    products[product_id] = product.dict()
    return {"message": "Product updated", "product": products[product_id]}

@app.delete("/products/{product_id}")
def delete_product(product_id: int):
    if product_id in products:
        deleted = products.pop(product_id)
        return {"message": "Product deleted", "product": deleted}
    return {"error": "Product not found"}

Wrapping Up

FastAPI is powerful but easy to use. We just built a complete REST API with:

✅ Type-safe request/response
✅ Input validation using Pydantic
✅ Full CRUD support
✅ Swagger docs auto-generated
✅ No extra setup needed

0
Subscribe to my newsletter

Read articles from Shaik Sameer directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Shaik Sameer
Shaik Sameer