![[images/introduction-to-fastapi/Pasted image 20240816183405.png|Thumbnail of The different between Django, Flask, and FastAPI]]
Hi, it’s Ekky. I’m a freelance developer with experience in web development and web scraping. I am also known as a Python Developer. I greatly use Python in my work, from simple scripts to full-stack applications. You also can find my portfolio website here.
In this article, I want to introduce you to FastAPI, a Python library you can use to build an API. And then, I compared it to other Python libraries like Django and Flask in terms of speed.
What is API?
If you are new to programming and have no clue what API is.
API is a short-term for Application Programming Interface. It’s a server-side application and is mostly used for data transactions on the client side like desktop apps, mobile apps, and also web apps simultanously.
![[images/introduction-to-fastapi/Pasted image 20240816134309.png|source: https://elancer.co.kr]]
You just have to build it once and use it on the other app.
What is FastAPI?
FastAPI is a modern and fast web framework for building APIs in Python, designed with simplicity, flexibility, and performance in mind. Maintained by Sebastián Ramírez known as @tiangolo
The first time I discovered it, I was surprised at how easy to get FastAPI running on my local machine. What you have to do is just:
- Install the FastAPI library
pip install fastapi uvicorn
- Write the code below
from fastapi import FastAPI app = FastAPI() @app.get("/") def read_root(): return {"Hello": "World"}
- Then run the code using uvicorn from your terminal
uvicorn main:app --reload
It will output something like this:
INFO: Will watch for changes in these directories: ['/your-app-path']
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [31469] using StatReload
INFO: Started server process [31471]
INFO: Waiting for application startup.
INFO: Application startup complete.
Visit the website on http://localhost:8000
or http://localhost:8000/docs
for the swagger version
Comparing FastAPI to Django and Flask
As a comparison to the other Python API frameworks, I will show how API is built on Django, Flask, and FastAPI. The app it self is about library inventory management.
Django Rest Framework
Let’s assume we’re creating a simple API for a book library.
- Set up the Django project
- Install Django Rest Framework
pip install django djangorestframework
- Configure DRF in your project
settings.py
:INSTALLED_APPS = [ # ... 'rest_framework', 'your_app_name', ]
- Create a model in
your_app/models.py
:from django.db import models class Book(models.Model): title = models.CharField(max_length=100) author = models.CharField(max_length=100) publication_date = models.DateField() def __str__(self): return self.title
- Create a serializer in
your_app/serializers.py
:from rest_framework import serializers from .models import Book class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = ['id', 'title', 'author', 'publication_date']
- Define views in your_app/views.py:
from rest_framework import viewsets from .models import Book from .serializers import BookSerializer class BookViewSet(viewsets.ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer
- Setup URL routing in your_project/urls.py:
from django.contrib import admin from django.urls import path, include from rest_framework.routers import DefaultRouter from your_app.views import BookViewSet router = DefaultRouter() router.register(r'books', BookViewSet) urlpatterns = [ path('admin/', admin.site.urls), path('api/', include(router.urls)), ]
- Run the migrations
python manage.py makemigrations python manage.py migrate
- Run the server
python manage.py runserver
This setup creates a full CRUD API for the Book model. You can now:
- List all books: GET /api/books/
- Create a new book: POST /api/books/
- Retrieve a specific book: GET /api/books/{id}/
- Update a book: PUT /api/books/{id}/
- Delete a book: DELETE /api/books/{id}/
Flask
Building an API using Flask is quite straightforward compared to Django. I’ll provide a similar example to the Django one, creating a simple API for a book library. Here’s how you can build an API using Flask:
- Install required packages
pip install flask flask-sqlalchemy flask-marshmallow marshmallow-sqlalchemy
- Create
app.py
from flask import Flask, request, jsonify from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow from marshmallow import fields import os # Initialize app app = Flask(__name__) basedir = os.path.abspath(os.path.dirname(__file__)) # Database app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'db.sqlite') app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # Initialize db db = SQLAlchemy(app) # Initialize ma ma = Marshmallow(app) # Book Model class Book(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), unique=True) author = db.Column(db.String(100)) publication_date = db.Column(db.Date) def __init__(self, title, author, publication_date): self.title = title self.author = author self.publication_date = publication_date # Book Schema class BookSchema(ma.Schema): class Meta: fields = ('id', 'title', 'author', 'publication_date') # Initialize schema book_schema = BookSchema() books_schema = BookSchema(many=True) # Create a book @app.route('/book', methods=['POST']) def add_book(): title = request.json['title'] author = request.json['author'] publication_date = request.json['publication_date'] new_book = Book(title, author, publication_date) db.session.add(new_book) db.session.commit() return book_schema.jsonify(new_book) # Get all books @app.route('/book', methods=['GET']) def get_books(): all_books = Book.query.all() result = books_schema.dump(all_books) return jsonify(result) # Get single book @app.route('/book/<id>', methods=['GET']) def get_book(id): book = Book.query.get(id) return book_schema.jsonify(book) # Update a book @app.route('/book/<id>', methods=['PUT']) def update_book(id): book = Book.query.get(id) title = request.json['title'] author = request.json['author'] publication_date = request.json['publication_date'] book.title = title book.author = author book.publication_date = publication_date db.session.commit() return book_schema.jsonify(book) # Delete book @app.route('/book/<id>', methods=['DELETE']) def delete_book(id): book = Book.query.get(id) db.session.delete(book) db.session.commit() return book_schema.jsonify(book) # Run server if __name__ == '__main__': app.run(debug=True)
- Create the database
from app import db db.create_all()
- Run the application
python app.py
This Flask app provides similar functionality to the Django example:
- Create a book: POST /book
- Get all books: GET /book
- Get a specific book: GET /book/
- Update a book: PUT /book/
- Delete a book: DELETE /book/
The main differences are:
- Flask is more lightweight and requires less boilerplate code.
- You need to explicitly define routes for each operation.
- SQLAlchemy is used for database operations instead of Django’s ORM.
- Marshmallow is used for serialization instead of Django REST Framework’s serializers.
FastAPI
Here’s how you can implement the same functionality in FastAPI:
- First, install the required packages:
pip install fastapi uvicorn sqlalchemy pydantic
- Create
main.py
from fastapi import FastAPI, HTTPException, Depends from sqlalchemy import create_engine, Column, Integer, String, Date from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, Session from pydantic import BaseModel from datetime import date from typing import List # Database setup SQLALCHEMY_DATABASE_URL = "sqlite:///./books.db" engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base() # Database model class BookDB(Base): __tablename__ = "books" id = Column(Integer, primary_key=True, index=True) title = Column(String, unique=True, index=True) author = Column(String, index=True) publication_date = Column(Date) # Pydantic models class BookBase(BaseModel): title: str author: str publication_date: date class BookCreate(BookBase): pass class Book(BookBase): id: int class Config: orm_mode = True # Create tables Base.metadata.create_all(bind=engine) # FastAPI app app = FastAPI() # Dependency def get_db(): db = SessionLocal() try: yield db finally: db.close() # Create a book @app.post("/books/", response_model=Book) def create_book(book: BookCreate, db: Session = Depends(get_db)): db_book = BookDB(**book.dict()) db.add(db_book) db.commit() db.refresh(db_book) return db_book # Get all books @app.get("/books/", response_model=List[Book]) def read_books(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): books = db.query(BookDB).offset(skip).limit(limit).all() return books # Get a specific book @app.get("/books/{book_id}", response_model=Book) def read_book(book_id: int, db: Session = Depends(get_db)): book = db.query(BookDB).filter(BookDB.id == book_id).first() if book is None: raise HTTPException(status_code=404, detail="Book not found") return book # Update a book @app.put("/books/{book_id}", response_model=Book) def update_book(book_id: int, book: BookCreate, db: Session = Depends(get_db)): db_book = db.query(BookDB).filter(BookDB.id == book_id).first() if db_book is None: raise HTTPException(status_code=404, detail="Book not found") for var, value in vars(book).items(): setattr(db_book, var, value) if value else None db.add(db_book) db.commit() db.refresh(db_book) return db_book # Delete a book @app.delete("/books/{book_id}", response_model=Book) def delete_book(book_id: int, db: Session = Depends(get_db)): book = db.query(BookDB).filter(BookDB.id == book_id).first() if book is None: raise HTTPException(status_code=404, detail="Book not found") db.delete(book) db.commit() return book if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)
- Run the application
uvicorn main:app --reload
This FastAPI app provides the same functionality as the Django and Flask examples:
- Create a book: POST /books/
- Get all books: GET /books/
- Get a specific book: GET /books/{book_id}
- Update a book: PUT /books/{book_id}
- Delete a book: DELETE /books/{book_id}
Key differences and advantages of FastAPI:
- FastAPI uses type hints for request and response models, providing automatic data validation.
- It generates OpenAPI (Swagger) documentation automatically, which you can view at
http://localhost:8000/docs
when running the app. - It’s built on top of Starlette and Pydantic, offering high performance.
- It uses async/await syntax, though this example doesn’t showcase it for simplicity.
- Dependency injection is used for database sessions.
Conclusion
FastAPI is a modern and fast web framework for building APIs in Python, designed with simplicity, flexibility, and performance in mind. It offers several advantages over other Python web frameworks such as Django and Flask. Hence, it’s a fantastic choice for developers who want to create robust APIs quickly and easily.
This article also featured on Medium