4 APIs – The piping between our components
This chapter explores how APIs serve as the contract and connective tissue between components in a modern, distributed fintech system. It frames API-driven design around clear use cases, intentional versioning, living documentation, performance and scalability (paging and asynchronous work for large datasets), robust security and server-side validation, and continuous monitoring and analytics. While REST is the primary focus, the chapter briefly contrasts alternative approaches such as SOAP and GraphQL and underscores that operational concerns—governance, observability, SLAs, and cost transparency—are as important as interface design.
On the implementation side, the chapter builds a small file/record service with FastAPI, using routers to define GET and POST endpoints and stubbing responses to enable early testing before persistence exists. It demonstrates fast feedback with pytest and a BDD workflow using pytest-bdd, then packages the service with Docker and Uvicorn. OpenAPI-powered documentation is generated automatically and explored through interactive UIs, along with techniques to customize the specification and address version mismatches. To introduce governance and a single entry point, the chapter integrates an API manager (WSO2) and walks through importing the OpenAPI spec, deploying routes, issuing keys, and proxying traffic through the gateway.
For quality and resilience, the chapter layers in practical testing tools: Postman for scripted request/response assertions and collaboration, and Locust for load testing and performance insights. It highlights common pitfalls (trailing slash inconsistencies, incorrect status codes, missing auth) and shows how to harden the service with explicit assertions, prefixed and versioned routes (for example, /api/v1), and Pydantic models that drive schemas, examples, and strong server-side validation. A centralized exception handler maps validation errors to clear 400 responses, while the broader guidance emphasizes pagination and async processing for scale, security-first input validation, and API lifecycle management to keep systems reliable, discoverable, and maintainable as they grow.
Sequence Diagram produced by PlantUML
A typical testing pyramid.
Swagger Online Editor
FastAPI Documentation with Redoc
Lifecycle Management by WSO2
Software Testing Categories
Starting a new test with Locust
View of successive Locust Runs
Our updated AchFile schema, thanks Pydantic!
Summary
- API Driven design promotes an API first approach to development and ensures your software will meet today’s distributed nature.
- Exploring the design and testing of APIs is crucial for interaction with software components in microservices, distributed systems, and packages.
- REST is the primary API standard discussed, but GraphQL and SOAP are other important standards with unique pros and cons.
- APIs act as contracts requiring adherence to usage terms and provide stable, scalable endpoints with SLAs for consumers.
- API Driven Design emphasizes clear use cases, versioning, comprehensive documentation, and robust security and validation.
- Effective API monitoring and analytics are essential for capacity assessment, using tools like OpenTelemetry, Prometheus, and Grafana.
- Initial API tasks are simple, focusing on uploading and viewing files and records with a clear interaction flow.
- FastAPI is used for building APIs, starting with basic GET endpoints and supporting pagination and asynchronous processing for performance.
- Unit tests validate API endpoints during development, while additional tests like BDD can assess API behavior and performance.
- API documentation via OpenAPI standards ensures alignment between implementation and user understanding, offering tools like Swagger and Redoc.
- API Management tools like WSO2 centralize management, provide lifecycle control, and facilitate API monitoring, monetization, and user experience.
FAQ
Why does the chapter choose FastAPI, and what is the minimal project structure to start?
FastAPI is chosen for speed, type-driven dev, and built-in OpenAPI docs. Minimal structure: ApiSample/ with app/ (main.py, routers/files.py, __init__.py), tests/, and optionally docs/. In main.py create FastAPI and include the router; in routers/files.py instantiate APIRouter and add endpoints.How do I create a basic GET /files endpoint and test it quickly?
In routers/files.py add @router.get("/files") and return a simple list. In tests, use fastapi.testclient.TestClient(app) and assert response.status_code == 200 and expected JSON. You can also express the same flow in BDD with pytest-bdd using Given/When/Then scenarios.Why do I get 405 Method Not Allowed or 307 Temporary Redirect on my endpoints?
- 405 usually means the method/route isn’t defined (e.g., POST /files without @router.post) or the client path doesn’t match the server path.- 307 often comes from trailing slash mismatches (server defines "/files/" but client calls "/files"). Fix by making client and server paths consistent (either always include or omit trailing slashes).
How do I return 201 CREATED for a POST in FastAPI?
Decorate the route with a status code: @router.post("/files", status_code=status.HTTP_201_CREATED). This makes the endpoint return 201 on success. Later you can set status dynamically if you need different codes for error conditions.How do I document the API and where can I get the OpenAPI spec?
FastAPI auto-generates docs. Visit /docs for Swagger UI, /redoc for Redoc, and /openapi.json for the raw OpenAPI document. You can paste the JSON into the Swagger Editor for exploration or client/server code generation.WSO2 says “OpenAPI content validation failed!” because of version 3.1—how do I fix it?
Override FastAPI’s schema builder to emit OpenAPI 3.0.x. Create a custom_openapi function using fastapi.openapi.utils.get_openapi, set openapi_version="3.0.0", assign app.openapi = custom_openapi, rebuild, and point WSO2 to the updated /openapi.json.I get “code: 900902 Missing Credentials” in WSO2 when trying the API—what’s wrong?
You need to generate a token in the WSO2 “Try Out” view. Click Generate Key to obtain a temporary Authorization credential; WSO2 will then include it in requests to your API and the call will succeed.How do I version and organize endpoints like /api/v1/files?
Use APIRouter’s prefix. For example, router = APIRouter(prefix="/api/v1/files"), then define routes without repeating /files (e.g., @router.get("")). This centralizes URL structure for organization and versioning and reduces repeated path text.How do I add validation and richer docs to responses with Pydantic?
Create Pydantic models (class AchFile(BaseModel): file_id: str) and use Field(...) to add examples, titles, and descriptions. Return model instances from routes for typed responses. Add a FastAPI exception handler for ValidationError to return 400 with details. You can enforce patterns (e.g., file_id via regex) to validate inputs.How do I containerize and test performance of the API?
- Docker: Use a slim Python base (e.g., python:alpine), COPY requirements.txt and app/, pip install, and start with uvicorn. Expose 8000 and access http://localhost:8000/files.- Load testing: With Locust, write a locustfile.py (HttpUser, tasks calling /files etc.), set host to http://localhost:8000, start Locust at http://localhost:8089, and watch stats. Add simple assertions on status codes and ensure paths/methods match your API.
Build Financial Software with Generative AI (From Scratch) ebook for free