Skip to content

Commit 883f1d1

Browse files
committed
add images to fastapi blog and split in two parts
1 parent 93f5fba commit 883f1d1

File tree

71 files changed

+4747
-1403
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+4747
-1403
lines changed

Diff for: __pycache__/main.cpython-310.pyc

3.12 KB
Binary file not shown.

Diff for: content/blogs/fastapi.md

+24-278
Large diffs are not rendered by default.

Diff for: content/blogs/fastapi2.md

+286
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
---
2+
title: "Building Efficient ML APIs with FastAPI: A Comprehensive Guide - Part 2"
3+
description: "FastAPI: Guide to building prototype ML applications quick and easy AF"
4+
slug: fastapi2
5+
date: 2024-07-13 00:00:00+0000
6+
image: /blogs/fastapi/fastAPI.webp #Fixit
7+
license: false
8+
categories:
9+
- Deployment
10+
- REST
11+
tags:
12+
- Model Deployment
13+
- REST
14+
- API
15+
- FastAPI
16+
weight: 1 # You can add weight to some posts to override the default sorting (date descending)
17+
---
18+
19+
## Advanced Features with FastAPI
20+
After learning how to be able to serve my models using FastAPI, I decided to extend it further in order to enhance the functionality, security and scalability of my API. For this, I read about additional topics like input validation, error handling and authentication, which although won't be help me much for the purpose for which I initially started learning FastAPI, i.e., to make demo apps for my ML models, but they are crucial for developing production-ready APIs and so I thought about giving them a read too.
21+
22+
### Input Validation
23+
Input validation ensures that incoming data meets specified criteria before processing. FastAPI integrates seamlessly with `Pydantic` for data validation, leveraging Python's type hints. Here’s how I implemented input validation in my FastAPI application:
24+
25+
```python
26+
from pydantic import BaseModel, Field
27+
28+
class Item(BaseModel):
29+
name : str = Field(..., decription = "The name of the item")
30+
price : float = Field(..., gt = 0, decription = "The price of the item")
31+
32+
@app.post('/items/')
33+
def create_item(item: Item):
34+
return {'name' : item.name, 'price' : item.price}
35+
```
36+
37+
- **Explanation:** In this example, the `Item` Pydantic model specifies that `name` is a required string field and `price` is a required float field greater than 0. FastAPI automatically validates incoming requests against these criteria and returns appropriate error responses if validation fails.
38+
39+
### Error Handling
40+
Error handling is crucial for providing informative responses when something goes wrong in an API request. FastAPI simplifies error handling with HTTPException and exception handling mechanisms. Here’s an example of handling errors in FastAPI which we've seen before too during CRUD operations.
41+
```python
42+
from fastapi import HTTPException
43+
44+
@app.get('items/{item_id}')
45+
def read_item(item_id : int):
46+
if item_id not in range(1, 6):
47+
raise HTTPException(status_code = 404, detail = "Item not found")
48+
return {'item' : item_id}
49+
```
50+
51+
- **Explanation:** In this example, if the `item_id` provided in the request path is not within the range of valid item IDs (1 to 5), FastAPI raises an `HTTPException` with a 404 status code and a detailed error message along with that.
52+
53+
### Authentication and Authorization
54+
Securing APIs with authentication and authorization mechanisms is essential for protecting sensitive data and restricting access to authorized users. FastAPI supports various authentication methods, including OAuth2, JWT (JSON Web Tokens), and basic authentication. Here’s a simple example of implementing JWT authentication in FastAPI:
55+
56+
```python
57+
from fastapi import Depends, HTTPException, status
58+
from fastapi.security import OAuth2PasswordBearer
59+
60+
security = OAuth2PasswordBearer(tokenurl='/token')
61+
62+
# Mock user database
63+
fake_users_db = {
64+
"johndoe": {
65+
"username": "johndoe",
66+
"hashed_password": "$2b$12$V2qBpWn5GDK/9QrF3l7AyO6x9BdFssEcVbOeYURVn8t62MzK4IO5u", # hashed version of password 'secret'
67+
"disabled": False,
68+
}
69+
}
70+
71+
def verify_password(username: str, password: str):
72+
user = fake_users_db.get(username)
73+
if not user or not password:
74+
return False
75+
if password == 'secret':
76+
return True
77+
78+
79+
def get_current_user(token: str = Depends(security)):
80+
username, _ = token.split(":")
81+
user = fake_users_db.get(username)
82+
83+
if not user:
84+
raise HTTPException(
85+
status_code = status.HTTP_401_UNAUTHORIZED,
86+
detail = 'Invalid Credentials',
87+
headers = {"WWW-Authenticate": "Bearer"}
88+
)
89+
return user
90+
91+
@app.get('users/me')
92+
def read_current_user(current_user : dict = Depends(get_current_user)):
93+
return current_user
94+
```
95+
96+
- **Explanation:** In this example, `OAuth2PasswordBearer` is used to define an authentication scheme using OAuth2 with password flow. The `get_current_user()` function verifies the JWT token and retrieves the current user from the mock database `(fake_users_db)`. The `read_current_user()` endpoint demonstrates accessing user information with authentication.
97+
98+
## Deployment Strategies for FASTApi
99+
Moving further, after building the app, it is also essential to be able to deploy it. FastAPI applications can be deployed using various deployment options, depending on scalability requirements, infrastructure preferences, and operational constraints. Here are some common deployment strategies.
100+
101+
- **Docker Containers:** Containerization with Docker allows packaging FastAPI applications and their dependencies into lightweight, portable containers. This approach facilitates consistent deployment across different environments and simplifies scaling.
102+
103+
- **Serverless Deployment:** Serverless platforms like AWS Lambda or Azure Functions offer auto-scaling and pay-per-use pricing models. FastAPI applications can be deployed as serverless functions, eliminating the need to manage infrastructure manually.
104+
105+
- **Traditional Servers:** Deploying FastAPI on traditional servers or virtual machines provides more control over infrastructure configuration and performance tuning. Platforms like AWS EC2, Google Compute Engine, or DigitalOcean Droplets are commonly used for this approach.
106+
107+
### Deployment Best Practices
108+
When deploying FastAPI applications in production, consider the following best practices to ensure reliability, security, and scalability:
109+
110+
111+
- **Environment Configuration:** Use environment variables for sensitive information (e.g., API keys, database credentials) and configuration settings (e.g., logging levels, debug mode).
112+
113+
- **Monitoring and Logging:** Implement monitoring solutions (e.g., Prometheus, Datadog) to track performance metrics, error rates, and application health. Centralized logging (e.g., ELK Stack, Splunk) helps in troubleshooting and debugging issues.
114+
115+
- **Security Measures:** Secure FastAPI applications with HTTPS/TLS encryption to protect data in transit. Implement authentication and authorization mechanisms (e.g., OAuth2, JWT) to control access to APIs and sensitive resources.
116+
117+
- **Scaling Strategies:** Plan for horizontal scaling by deploying multiple instances of FastAPI behind a load balancer to handle increased traffic. Use auto-scaling features offered by cloud providers for efficient resource utilization.
118+
119+
### Deployment with Docker
120+
For my learning purposes, I did not go in depth but still learned how to containerize a FASTApi application using Docker atleast.
121+
122+
1. **Dockerfile:** Create a `Dockerfile` in your FastAPI project directory.
123+
```Dockerfile
124+
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
125+
126+
COPY ./app /app
127+
```
128+
129+
Replace `./app` with the path to your FastAPI application directory.
130+
131+
2. **Build Docker Image:** Build the docker image
132+
```bash
133+
docker build -t fastapi-app
134+
```
135+
136+
3. **Run Docker Container:** Run the Docker container.
137+
```bash
138+
docker run -d -p 80:80 fastapi-app
139+
```
140+
141+
Adjust `-p 80:80` to map the container port to a desired host port.
142+
143+
## Continuous Integration and Delivery (CI/CD) for FastAPI
144+
Phewwww! Now that we've come all the way to deployment, I thought why not also add some CI/CD pipelines to it as it helps automate the building, testing and deployment processes, ensuring reliable and efficient software delivery.
145+
146+
### Setting up a CI/CD Pipeline
147+
CI/CD pipelines automate several key tasks in the software development lifecycle, including:
148+
149+
- **Code Compilation:** Compile and package the FastAPI application.
150+
- **Testing:** Execute automated tests to verify functionality and detect issues early.
151+
- **Deployment:** Deploy the application to staging or production environments automatically.
152+
153+
### Example CI/CD Pipeline with GitHub Actions
154+
Here's an example of setting up a CI/CD pipeline for FastAPI. I found this online and have yet to test it though.
155+
156+
```yaml
157+
name: CI/CD Pipeline
158+
159+
on:
160+
push:
161+
branches:
162+
- main
163+
pull_request:
164+
branches:
165+
- main
166+
167+
jobs:
168+
build:
169+
runs-on: ubuntu-latest
170+
171+
steps:
172+
- name: Checkout code
173+
uses: actions/checkout@v2
174+
175+
- name: Set up Python
176+
uses: actions/setup-python@v2
177+
with:
178+
python-version: 3.9
179+
180+
- name: Install dependencies
181+
run: |
182+
python -m pip install --upgrade pip
183+
pip install -r requirements.txt
184+
185+
- name: Run tests
186+
run: |
187+
pytest --cov=app tests/
188+
189+
- name: Build Docker image
190+
run: |
191+
docker build -t my-fastapi-app .
192+
docker tag my-fastapi-app:latest my-fastapi-app:$(git rev-parse --short $GITHUB_SHA)
193+
194+
- name: Push Docker image to registry
195+
uses: docker/login-action@v2
196+
with:
197+
username: ${{ secrets.DOCKER_USERNAME }}
198+
password: ${{ secrets.DOCKER_PASSWORD }}
199+
- name: Push Docker image
200+
run: docker push my-fastapi-app
201+
202+
- name: Deploy to staging
203+
if: github.ref == 'refs/heads/main'
204+
run: |
205+
ssh user@staging-server 'docker pull my-fastapi-app:latest'
206+
ssh user@staging-server 'docker-compose up -d'
207+
```
208+
209+
## Monitoring and Optimization for FastAPI
210+
Last but not the least, it is equally important to monitor and log the metrics of our FastAPI application as building one as monitoring provides us with insights into application behaviour and performance metrics and also helps enhance efficiency and responsiveness.
211+
212+
### Monitoring Strategies
213+
Effective monitoring helps identify issues, track performance metrics, and ensure the smooth operation of FastAPI applications. Consider the following monitoring strategies:
214+
215+
- **Logging:** Implement logging to record application events, errors, and debug information. Use structured logging for better analysis and troubleshooting.
216+
217+
- **Metrics Collection:** Monitor key performance indicators (KPIs) such as request/response times, error rates, and resource utilization (CPU, memory). Tools like Prometheus, DataDog, or AWS CloudWatch Metrics can be integrated for metrics collection.
218+
219+
- **Alerting:** Set up alerts based on predefined thresholds (e.g., high error rates, CPU utilization) to proactively address potential issues.
220+
221+
### Performace Optimization
222+
Optimizing FastAPI applications improves efficiency and responsiveness, enhancing user experience and reducing operational costs. Consider the following optimization techniques:
223+
224+
- **Code Profiling:** Identify performance bottlenecks using profiling tools (e.g., cProfile) to analyze execution times and optimize critical sections of code.
225+
226+
- **AsyncIO:** Leverage FastAPI's asynchronous capabilities and AsyncIO to handle concurrent requests efficiently, especially for I/O-bound operations.
227+
228+
- **Caching:** Implement caching mechanisms (e.g., Redis, Memcached) to store and retrieve frequently accessed data, reducing database load and improving response times.
229+
230+
- **Database Optimization:** Optimize database queries with indexes, query optimization techniques, and connection pooling to enhance database performance.
231+
232+
### Adding Metrics to FastAPI
233+
Integrate Prometheus for monitoring metrics in FastAPI:
234+
235+
1. Install Prometheus client
236+
```bash
237+
pip install prometheus-client
238+
```
239+
240+
2. Add Metrics Middleware
241+
```python
242+
from fastapi import FastAPI
243+
from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST
244+
from starlette.middleware.base import BaseHTTPMiddleware
245+
246+
app = FastAPI()
247+
248+
# Metrics
249+
REQUEST_COUNT = Counter("request_count", "Total count of requests", ["method", "endpoint", "status_code"])
250+
REQUEST_LATENCY = Histogram("request_latency_seconds", "Request latency in seconds", ["method", "endpoint"])
251+
252+
class PrometheusMiddleware(BaseHTTPMiddleware):
253+
async def dispatch(self, request, call_next):
254+
path = request.url.path
255+
method = request.method
256+
try:
257+
response = await call_next(request)
258+
status_code = response.status_code
259+
return response
260+
finally:
261+
REQUEST_COUNT.labels(method=method, endpoint=path, status_code=status_code).inc()
262+
latency = time.time() - request.scope["start_time"]
263+
REQUEST_LATENCY.labels(method=method, endpoint=path).observe(latency)
264+
265+
app.add_middleware(PrometheusMiddleware)
266+
```
267+
268+
3. Expose Metrics Endpoint:
269+
```python
270+
from fastapi.responses import Response
271+
272+
@app.get("/metrics")
273+
def get_metrics():
274+
return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST)
275+
```
276+
277+
4. Instrument Endpoints:
278+
```python
279+
@app.get("/items/")
280+
async def read_items():
281+
# Endpoint logic
282+
return {"message": "Items retrieved successfully"}
283+
```
284+
285+
## Conclusion
286+
And that's a wrap. Phewww.. While there is a lot to cover in FastAPI and certainly it can't be done in a single blog, I still attempted to atleast log some of the things which I learnt during this time of learning FastAPI. After all, this is not a book lol. Just a reference blog for me to look back to when I get stuck with something working with FastAPI again. I think it covers most of the basic stuff and just in case I missed out something, I can always go back and have a look at the FastAPI docs. For now, I'd say that FastAPI is truly amazing as for how easy it is to make and manage endpoints and deploying my ML apps to it. And the best part? It's fairly easy to learn too. It took me just 2 days to go through all this and I believe someone who works with Python will find it fairly easy to use. With that being said, I think that's all from my side regarding FastAPI for now. Until Next Time. Adios!

0 commit comments

Comments
 (0)