Skip to content

Commit 5b044ab

Browse files
committed
Merge dev into main
2 parents 29ba85f + 0f52050 commit 5b044ab

46 files changed

Lines changed: 2625 additions & 719 deletions

Some content is hidden

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

.github/workflows/ci-pipeline__dev.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ jobs:
4040
- run-unit-tests
4141

4242
publish-to-pypi:
43+
if: False
4344
permissions:
4445
id-token: write
4546
name: "Publish to PYPI"
Lines changed: 381 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,381 @@
1+
# FastAPI Serverless Project Setup Guide
2+
*A complete guide to CI/CD repository configuration before writing application code*
3+
4+
## Why This Matters
5+
Setting up proper infrastructure before writing application code is crucial for long-term project success. Each component in this guide addresses specific challenges that become exponentially harder to implement as the codebase grows. By establishing these foundations early, we create a robust development environment that supports quality, testing, and automated deployments from day one.
6+
7+
### Key Benefits
8+
- Consistent development environment across team members
9+
- Automated quality checks and deployments from the start
10+
- Clear separation of development and production environments
11+
- Built-in testing practices that scale with the code
12+
- Infrastructure-as-code approach for reproducible deployments
13+
14+
## The CI/CD Pipeline
15+
On the topic of good engineering and quality code, this is the pipeline and setup that we should have on each new repo before adding application code.
16+
17+
This v1.0.0 approach ensures quality, maintainability, and proper CI/CD from day one.
18+
19+
- 1️⃣ Git repo
20+
- 2️⃣ FastAPI base app
21+
- 3️⃣ CI pipeline (dev and main)
22+
- 4️⃣ Unit, integration and QA tests
23+
- 5️⃣ 100% code coverage
24+
- 6️⃣ Auto-tagging on commits
25+
- 7️⃣ Create Docker container
26+
- 8️⃣ Push Docker container to AWS ECR
27+
- 9️⃣ Create AWS Lambda
28+
- 🔟 Enable AWS Function URL
29+
- 1️⃣1️⃣ Ensure AWS Lambda/FastAPI works
30+
31+
Adding these elements later when complexity has grown becomes exponentially more difficult. This guide provides step-by-step instructions to implement this foundation correctly from the start.
32+
33+
## 1. Repository Setup
34+
Repository setup establishes the foundation for the entire development workflow. A well-structured repository ensures consistent development practices, clear code organization, and efficient collaboration. The directory structure follows separation of concerns principles and supports independent testing of each component.
35+
36+
### Initial Structure
37+
```bash
38+
mkdir my-fastapi-project
39+
cd my-fastapi-project
40+
git init
41+
42+
# Create core directories
43+
mkdir -p {src,tests/{unit,integration,qa},deploy/{docker,lambdas},.github/workflows}
44+
45+
# Create essential files
46+
touch README.md LICENSE pyproject.toml requirements-test.txt
47+
touch .gitignore .env.example
48+
```
49+
50+
### Base Configuration Files
51+
Configuration files establish project dependencies, testing requirements, and build settings. Poetry provides reliable dependency management while maintaining reproducible environments. The test requirements ensure consistent quality checks across all environments.
52+
53+
**pyproject.toml**
54+
```toml
55+
[tool.poetry]
56+
name = "my_fastapi_project"
57+
version = "v0.0.1"
58+
description = "FastAPI Serverless Project"
59+
authors = ["Your Name <your.email@domain.com>"]
60+
license = "Apache 2.0"
61+
readme = "README.md"
62+
63+
[tool.poetry.dependencies]
64+
python = "^3.11"
65+
fastapi = "*"
66+
mangum = "*"
67+
httpx = "*"
68+
uvicorn = "*"
69+
70+
[build-system]
71+
requires = ["poetry-core>=1.0.0"]
72+
build-backend = "poetry.core.masonry.api"
73+
```
74+
75+
**requirements-test.txt**
76+
```text
77+
pytest
78+
pytest-cov
79+
coveralls
80+
```
81+
82+
## 2. FastAPI Base Application
83+
FastAPI applications require clear structure to support scalability and maintenance. This setup separates routes, utilities, and core application logic while maintaining AWS Lambda compatibility through Mangum. The structure supports independent testing of components and clear separation of concerns.
84+
85+
### Core Application Structure
86+
```
87+
src/
88+
├── app/
89+
│ ├── __init__.py
90+
│ ├── main.py
91+
│ ├── routes/
92+
│ │ ├── __init__.py
93+
│ │ └── info.py
94+
│ └── utils/
95+
│ ├── __init__.py
96+
│ └── version.py
97+
└── handler.py
98+
```
99+
100+
### Basic FastAPI Application (main.py)
101+
The main application file serves as the entry point, combining route configuration with AWS Lambda integration. Mangum handles the translation between AWS Lambda events and FastAPI requests, ensuring seamless serverless operation while maintaining local development capabilities.
102+
103+
```python
104+
from fastapi import FastAPI
105+
from mangum import Mangum
106+
from app.routes import info
107+
108+
app = FastAPI()
109+
app.include_router(info.router, prefix="/info", tags=["info"])
110+
111+
# Lambda handler
112+
handler = Mangum(app)
113+
114+
if __name__ == "__main__":
115+
import uvicorn
116+
uvicorn.run(app, host="0.0.0.0", port=8000)
117+
```
118+
119+
### Info Routes (routes/info.py)
120+
Route modules provide clear API endpoint organization. The info routes offer essential system health checks and version information, crucial for monitoring and deployment verification. This structure supports easy addition of new endpoints while maintaining code organization.
121+
122+
```python
123+
from fastapi import APIRouter
124+
from app.utils.version import get_version
125+
126+
router = APIRouter()
127+
128+
@router.get("/version")
129+
async def version():
130+
return {"version": get_version()}
131+
132+
@router.get("/ping")
133+
async def ping():
134+
return "pong"
135+
```
136+
137+
## 3. CI Pipeline Setup
138+
Continuous Integration ensures code quality and automated deployments. The dual pipeline approach (dev/main) enables feature development while maintaining stable production code. Automated versioning and testing prevent broken deployments and maintain consistent release practices.
139+
140+
### GitHub Actions Workflows
141+
142+
**.github/workflows/ci-pipeline-dev.yml**
143+
```yaml
144+
name: CI Pipeline - DEV
145+
on:
146+
push:
147+
branches:
148+
- dev
149+
150+
env:
151+
RELEASE_TYPE: 'minor'
152+
153+
jobs:
154+
run-tests:
155+
name: "Run tests"
156+
runs-on: ubuntu-latest
157+
steps:
158+
- uses: actions/checkout@v4
159+
- name: Install dependencies
160+
run: |
161+
python -m pip install --upgrade pip
162+
pip install -r requirements-test.txt
163+
- name: Run tests
164+
run: pytest tests/ --cov=src/
165+
166+
increment-tag:
167+
needs: run-tests
168+
runs-on: ubuntu-latest
169+
steps:
170+
- uses: actions/checkout@v4
171+
- name: Increment version
172+
run: |
173+
# Version increment logic here
174+
git tag v0.1.0
175+
git push origin --tags
176+
```
177+
178+
**.github/workflows/ci-pipeline-main.yml**
179+
```yaml
180+
name: CI Pipeline - MAIN
181+
on:
182+
push:
183+
branches:
184+
- main
185+
186+
env:
187+
RELEASE_TYPE: 'major'
188+
189+
jobs:
190+
# Similar to dev pipeline but with additional deployment steps
191+
deploy-to-aws:
192+
needs: [run-tests, increment-tag]
193+
runs-on: ubuntu-latest
194+
steps:
195+
- name: Configure AWS credentials
196+
uses: aws-actions/configure-aws-credentials@v1
197+
with:
198+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
199+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
200+
aws-region: ${{ secrets.AWS_REGION }}
201+
```
202+
203+
## 4. Testing Framework
204+
Multi-layer testing catches issues at different stages of development. Unit tests verify component behavior, integration tests ensure proper system interaction, and QA tests validate production deployment. 100% coverage ensures no untested code paths exist.
205+
206+
### Unit Tests (tests/unit/test_version.py)
207+
```python
208+
from unittest import TestCase
209+
from app.utils.version import get_version
210+
211+
class TestVersion(TestCase):
212+
def test_get_version(self):
213+
version = get_version()
214+
assert isinstance(version, str)
215+
assert version.startswith('v')
216+
```
217+
218+
### Integration Tests (tests/integration/test_routes.py)
219+
Integration tests validate the complete request-response cycle using FastAPI's test client. These tests ensure proper routing, middleware functionality, and response formatting. They catch issues that unit tests might miss while verifying the entire API behavior.
220+
221+
```python
222+
from fastapi.testclient import TestClient
223+
from app.main import app
224+
225+
client = TestClient(app)
226+
227+
def test_version_endpoint():
228+
response = client.get("/info/version")
229+
assert response.status_code == 200
230+
assert "version" in response.json()
231+
232+
def test_ping_endpoint():
233+
response = client.get("/info/ping")
234+
assert response.status_code == 200
235+
assert response.json() == "pong"
236+
```
237+
238+
### QA Tests (tests/qa/test_lambda.py)
239+
QA tests validate the deployed Lambda function through its public URL. These tests verify the complete deployment pipeline, including AWS configuration, networking, and Lambda execution environment. They serve as the final quality gate before production traffic.
240+
241+
```python
242+
import pytest
243+
import requests
244+
from unittest import TestCase
245+
246+
class TestLambdaEndpoints(TestCase):
247+
@classmethod
248+
def setUpClass(cls):
249+
cls.lambda_url = "your-lambda-url"
250+
251+
def test_version_endpoint_live(self):
252+
response = requests.get(f"{self.lambda_url}/info/version")
253+
assert response.status_code == 200
254+
assert "version" in response.json()
255+
```
256+
257+
## 5. Docker Configuration
258+
Docker containers ensure consistent environments across development and production. The configuration includes AWS Lambda compatibility layers and optimized Python settings. Multi-stage builds and proper base images maintain small deployment sizes while supporting development needs.
259+
260+
### Dockerfile
261+
```dockerfile
262+
FROM python:3.11-slim
263+
264+
RUN pip install mangum uvicorn fastapi
265+
266+
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4 \
267+
/lambda-adapter /opt/extensions/lambda-adapter
268+
269+
WORKDIR /app
270+
COPY ./src /app/src
271+
ENV PYTHONPATH="/app"
272+
ENV PORT=8080
273+
274+
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8080"]
275+
```
276+
277+
### docker-compose.yml
278+
Docker Compose facilitates local development by matching production container configurations. It provides volume mounting for live code updates and port mapping for local access. This setup ensures development closely matches production behavior while maintaining developer productivity.
279+
280+
```yaml
281+
services:
282+
app:
283+
build:
284+
context: .
285+
dockerfile: deploy/docker/Dockerfile
286+
ports:
287+
- "8080:8080"
288+
volumes:
289+
- ./src:/app/src
290+
```
291+
292+
## 6. AWS Lambda Deployment
293+
Serverless deployment reduces operational overhead and provides automatic scaling. The Lambda setup includes proper memory allocation, timeout configurations, and URL endpoints. Infrastructure-as-code ensures reproducible deployments and proper version tracking.
294+
295+
### Lambda Function Setup
296+
```python
297+
from typing import Dict
298+
from aws_cdk import (
299+
aws_lambda as _lambda,
300+
aws_ecr as ecr,
301+
core
302+
)
303+
304+
class LambdaStack(core.Stack):
305+
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
306+
super().__init__(scope, id, **kwargs)
307+
308+
# Create Lambda function
309+
function = _lambda.DockerImageFunction(
310+
self, 'FastAPIFunction',
311+
code=_lambda.DockerImageCode.from_ecr(
312+
repository=ecr.Repository.from_repository_name(
313+
self, 'ECRRepo',
314+
repository_name='your-repo-name'
315+
)
316+
),
317+
memory_size=1024,
318+
timeout=core.Duration.seconds(30),
319+
)
320+
321+
# Add function URL
322+
function.add_function_url(
323+
auth_type=_lambda.FunctionUrlAuthType.NONE
324+
)
325+
```
326+
327+
## 7. Validation Steps
328+
Comprehensive validation prevents deployment issues and ensures system health. The steps cover local development, container verification, and production deployment checks. Automated validation in CI/CD pipelines prevents manual errors and maintains deployment quality.
329+
330+
### Local Testing
331+
```bash
332+
# Start local server
333+
uvicorn src.main:app --reload
334+
335+
# Run test suite
336+
pytest tests/ --cov=src/
337+
338+
# Build and run Docker container
339+
docker-compose up --build
340+
```
341+
342+
### AWS Deployment Validation
343+
Deployment validation ensures the entire pipeline functions correctly. These commands verify ECR push permissions, container registry access, and Lambda URL functionality. Regular validation prevents deployment-related downtimes and ensures system reliability.
344+
345+
```bash
346+
# Push to ECR
347+
aws ecr get-login-password --region region | docker login --username AWS --password-stdin aws_account_id.dkr.ecr.region.amazonaws.com
348+
docker push aws_account_id.dkr.ecr.region.amazonaws.com/your-repo:latest
349+
350+
# Test Lambda URL
351+
curl https://your-lambda-url/info/version
352+
```
353+
354+
## Best Practices
355+
These practices form the foundation of professional development workflows. Each category addresses specific challenges in modern software development, ensuring code quality, team collaboration, and system reliability.
356+
357+
1. **Version Control**
358+
- Use semantic versioning
359+
- Maintain clean git history
360+
- Protect main branch
361+
- Require PR reviews
362+
363+
2. **Testing**
364+
- Maintain 100% code coverage
365+
- Implement all test types from start
366+
- Use fixtures for test data
367+
- Mock external services
368+
369+
3. **CI/CD**
370+
- Automate all deployments
371+
- Include security scans
372+
- Test in multiple Python versions
373+
- Maintain deployment history
374+
375+
4. **Documentation**
376+
- Keep README updated
377+
- Document all endpoints
378+
- Include setup instructions
379+
- Document deployment process
380+
381+
Remember: This foundation guarantees maintainable, scalable applications. Invest time in setting it up correctly before writing application code.

0 commit comments

Comments
 (0)