Backend services for mobile apps and SPAs in FastAPI
Implementing backend services for mobile apps and single-page applications (SPAs) using FastAPI involves creating RESTful APIs that handle various operations such as user authentication, data storage, and retrieval. FastAPI, with its asynchronous support and easy integration with databases, is well-suited for building efficient and scalable backend services. Below, I'll guide you through setting up a simple example for each aspect: user authentication and data management.
Setting Up FastAPI for Backend Services
1. Installation
First, make sure you have FastAPI and uvicorn
installed:
pip install fastapi uvicorn
2. Create a FastAPI App
Let's create a basic FastAPI application in a file named main.py
.
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello World"}
3. Running the FastAPI App
Run your FastAPI application using uvicorn
:
uvicorn main:app --reload
Now, your FastAPI application is running locally on http://localhost:8000
.
Implementing User Authentication
1. Setting Up Authentication Endpoints
Let's add endpoints for user authentication using JWT (JSON Web Tokens) for authentication and authorization.
2. Install Required Packages
Install pyjwt
for JWT handling and passlib
for password hashing:
pip install pyjwt passlib
3. Define User Model and Authentication Functions
Create a models.py
file to define a User
model and a crud.py
file to handle user authentication operations.
models.py:
from pydantic import BaseModel
class User(BaseModel):
username: str
password: str
crud.py:
from passlib.context import CryptContext
from datetime import datetime, timedelta
import jwt
from jwt import PyJWTError
from typing import Optional
from .models import User
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
def get_password_hash(password):
return pwd_context.hash(password)
def authenticate_user(username: str, password: str):
# Replace with your actual authentication logic (e.g., querying from a database)
fake_password_hash = get_password_hash("fakepassword")
fake_user = User(username="testuser", password=fake_password_hash)
if username == fake_user.username and verify_password(password, fake_user.password):
return fake_user
return None
4. Implement Authentication Endpoint
Update main.py
to include an authentication endpoint:
from fastapi import Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from datetime import timedelta
from . import crud
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = crud.authenticate_user(form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=401, detail="Incorrect username or password")
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = crud.create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
5. Protecting Endpoints with Authentication
To protect your API endpoints, use the Depends
function from FastAPI along with oauth2_scheme
.
For example, modify main.py
to include a protected endpoint:
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(oauth2_scheme)):
return {"username": current_user.username}
Handling Data Management for SPAs
1. Connecting to a Database
FastAPI supports various databases. Here’s an example using SQLite for simplicity. Install sqlalchemy
and sqlite
:
pip install sqlalchemy databases
2. Define Database Models and CRUD Operations
models.py:
from sqlalchemy import Column, Integer, String
from databases import Database
database = Database("sqlite:///test.db")
class Item(Base):
__tablename__ = "items"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String, index=True)
crud.py:
from sqlalchemy import select
from .models import Item, database
async def create_item(item: Item):
query = Item.insert().values(
title=item.title,
description=item.description,
)
return await database.execute(query)
async def get_items():
query = select([Item])
return await database.fetch_all(query)
# Initialize database connection
async def startup():
await database.connect()
# Shutdown database connection
async def shutdown():
await database.disconnect()
3. Implementing CRUD Endpoints
Update main.py
to include endpoints for CRUD operations:
from fastapi import FastAPI, Depends
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker, Session
from .models import Item, database
from .crud import create_item, get_items, startup, shutdown
app = FastAPI()
@app.on_event("startup")
async def startup_event():
await startup()
@app.on_event("shutdown")
async def shutdown_event():
await shutdown()
@app.post("/items/")
async def create_item(item: Item):
return await create_item(item)
@app.get("/items/", response_model=list[Item])
async def read_items():
return await get_items()
4. Running the Application
Run your FastAPI application with uvicorn
:
uvicorn main:app --reload
Conclusion
FastAPI provides a robust framework for implementing backend services for mobile apps and SPAs. It supports authentication, data management, and integration with various databases efficiently. By following these steps, you can build scalable and performant backend APIs that meet the needs of modern web and mobile applications.