Python FastAPI Tutorial: Create a REST API from Scratch

Creating a REST API using FastAPI Python is no longer a trending but very common practice among developers today. FastAPI Python boasts speed, simplicity, and latest technologies that make working with APIs simpler for everyone. Whether it is an app, service integration, or developing a web backend, learning FastAPI for creating a REST API expands your horizons.

FastAPI is a high-performance Python framework for building APIs. It uses Python type hints. That means you get automatic data validation and interactive documentation for free. That makes it great for beginners as well as for experienced programmers. This tutorial on fastapi python for beginners will walk you through all these steps. You will learn to structure your project, endpoints, and then learn data handling. At the end, you will be able to develop your own working API.

Project Setup

Before we create RESTful API using FastAPI Python, we need to prepare our development environment. Follow these simple steps to get started. Before we create RESTful API using FastAPI Python, we need to prepare our development environment.

Create a Project Directory

Create a new folder for your project. This keeps your files organised and easy to manage.

mkdir fastapi-rest-api
cd fastapi-rest-api

Set Up a Virtual Environment

A virtual environment keeps your project dependencies separate from other projects. This prevents conflicts and keeps things clean.

// Ubuntu
python -m venv venv
source venv/bin/activate

//Windows
venv\Scripts\activate

It will setup virtual environment for your dependancies.

Install FastAPI and Uvicorn

Next thing, we need to do is to install FastAPI with Uvicorn. FastAPI needs an ASGI server to run. Uvicorn is a lightning-fast option that works perfectly with FastAPI.

Open terminal and enter below command to install:

pip install fastapi uvicorn pydantic

Project Structure

Before writing code, let us organise our project properly. A clean structure makes your code easier to maintain and scale. Create the following files and folders in your project directory.

fastapi-rest-api/
├── venv/
├── app/
│   ├── __init__.py
│   ├── main.py
│   ├── models.py
│   ├── database.py
│   └── routes/
│       ├── __init__.py
│       └── post.py

Building Your First REST API with Practical Example

Now let’s move to the exciting part. We will build REST API with FastAPI from scratch using a real-world scenario. Imagine you are building a simple blog platform that needs to manage posts. This python fastapi api example step by step shows you the complete process with organised code.

Creating the Data Model

Open app/models.py and define how a blog post looks in your system. Pydantic handles data validation automatically which saves you from writing extra code.

from pydantic import BaseModel
from typing import Optional
from datetime import datetime

class PostBase(BaseModel):
    title: str
    content: str
    author: str
    published: Optional[bool] = False

class PostCreate(PostBase):
    pass

class PostUpdate(BaseModel):
    title: Optional[str] = None
    content: Optional[str] = None
    author: Optional[str] = None
    published: Optional[bool] = None

class PostResponse(PostBase):
    id: int
    created_at: str

    class Config:
        from_attributes = True

We created four model classes here. The PostBase class contains common fields. The PostCreate class handles new post creation. The PostUpdate class allows partial updates. The PostResponse class defines what data users receive back.

Setting Up the Database

For this tutorial, we use a simple in-memory storage. Open app/database.py and add the following code.

from datetime import datetime

class Database:
    def __init__(self):
        self.posts = {}
        self.counter = 0

    def get_all_posts(self):
        return list(self.posts.values())

    def get_post_by_id(self, post_id: int):
        return self.posts.get(post_id)

    def create_post(self, post_data: dict):
        self.counter += 1
        post = {
            "id": self.counter,
            "title": post_data["title"],
            "content": post_data["content"],
            "author": post_data["author"],
            "published": post_data.get("published", False),
            "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        }
        self.posts[self.counter] = post
        return post

    def update_post(self, post_id: int, post_data: dict):
        if post_id not in self.posts:
            return None
        existing_post = self.posts[post_id]
        for key, value in post_data.items():
            if value is not None:
                existing_post[key] = value
        return existing_post

    def delete_post(self, post_id: int):
        if post_id in self.posts:
            del self.posts[post_id]
            return True
        return False

db = Database()

The Database class provides methods for all CRUD operations. CRUD stands for Create, Read, Update, and Delete. These are the four basic operations every API needs. We create a single instance called db at the bottom. This instance stays alive as long as your server runs. In production applications, you would replace this with a real database like PostgreSQL or MongoDB.

Creating Post Routes

Now let us create the API endpoints. Open app/routes/post.py and add the following code.

from fastapi import APIRouter, HTTPException, status
from typing import List
from app.models import PostCreate, PostUpdate, PostResponse
from app.database import db

router = APIRouter(prefix="/posts", tags=["Posts"])

@router.get("/", response_model=List[dict])
def get_all_posts():
    posts = db.get_all_posts()
    return posts

@router.get("/{post_id}")
def get_single_post(post_id: int):
    post = db.get_post_by_id(post_id)
    if not post:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Post with id {post_id} not found"
        )
    return post

@router.post("/", status_code=status.HTTP_201_CREATED)
def create_new_post(post: PostCreate):
    post_data = post.model_dump()
    new_post = db.create_post(post_data)
    return {
        "message": "Post created successfully",
        "post": new_post
    }

@router.put("/{post_id}")
def update_existing_post(post_id: int, post: PostUpdate):
    post_data = post.model_dump(exclude_unset=True)
    updated_post = db.update_post(post_id, post_data)
    if not updated_post:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Post with id {post_id} not found"
        )
    return {
        "message": "Post updated successfully",
        "post": updated_post
    }

@router.delete("/{post_id}", status_code=status.HTTP_200_OK)
def delete_existing_post(post_id: int):
    success = db.delete_post(post_id)
    if not success:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Post with id {post_id} not found"
        )
    return {"message": "Post deleted successfully"}

We use APIRouter to group related endpoints together. The prefix /posts applies to all routes in this file. Tags help organise the documentation. Each endpoint handles a specific task. The GET endpoints fetch data. The POST endpoint creates new posts. The PUT endpoint updates existing posts. The DELETE endpoint removes posts from the system.

Creating the Main Application

At Last, let’s connect everything together. Open app/main.py and modify as below.

from fastapi import FastAPI
from app.routes import post

app = FastAPI(
    title="Blog Post API",
    description="A simple REST API for managing blog posts",
    version="1.0.0"
)

app.include_router(post.router)

@app.get("/")
def read_root():
    return {
        "message": "Welcome to the Blog Post API",
        "documentation": "/docs",
        "endpoints": {
            "posts": "/posts"
        }
    }

@app.get("/health")
def health_check():
    return {"status": "healthy"}

The include_router method adds all post routes to your application. You can add more routers as your API grows. This keeps your main file clean and manageable. We also added a health check endpoint. This is useful for monitoring your API in production environments.

Running and Testing Your API

Start your server with Uvicorn from the project root directory.

uvicorn app.main:app --reload

Visit http://127.0.0.1:8000 to see the welcome message. Now all endpoints like /health for health check and /posts for getting all posts.

Conclusion

You have successfully attained the skills required to develop a REST API with FastAPI. All these have been done without using third-party tools. FastAPI simplifies and makes all these processes enjoyable and easy. It undertakes a variety of complex operations on your behalf. Automatic data validation, error handling, and generation of documentation occur. You will save on coding time and error considerations.

You can then extend your API in a number of ways. Include functionality for connecting your database. Create an authentication system so that your endpoints are secure. You can include more complicated business logics.