Book that explores the main features of the FastAPI web framework; it’s not super in-depth but covers the main use cases and components in fair detail.
Chapter 1. FastAPI offers a number of improvements over other Python frameworks. First, it has type hints that allow the IDE to detect type errors. Next is asynchronous processing, where logic is structured in coroutines instead of traditional functions. Every function is marked as async, and you call it with the asyncio module. This makes it better for multitasking; when one coroutine is blocked by IO operations, it can automatically switch to another one. Whereas traditional web frameworks used the WSGI interface, Fast API uses the ASGI interface, which is an asynchronous, non-blocking version of WSGI. It also uses a web server called uvicorn, which listens to incoming HTTP requests and forwards them to the framework.
FastAPI uses the REST architecture of HTTP to implement an API. The REST architecture is a simple and flexible interface for APIs and uses HTTP verbs like POST, GET, PUT, and DELETE. Some of the other dependencies include:
- Uvicorn is the web server that sits outside of Fast API and handles routing requests to it.
- Starlette supports a number of things like websockets, coroutines, serving static files, sessions, etc.
- Pydantic is used for data validation and parsing.
Chapter 2. How to set up a FastAPI project: use Uvicorn to call the main function. It can automatically reload when the source code changes. Swagger UI and ReDoc are useful for generating interactive API docs where you can access the endpoint, and they inform you of the required parameters and their types.
You can specify the parameters in two ways: they either pattern match the URL path, or they act as query parameters that come after the main path in a query string. In the Python method definition, you can specify the types of each parameter, whether they are optional or not, as well as additional validation constraints, like the minimum and maximum length of strings.
Chapter 3. Instead of passing individual arguments to the function, POST parameters can be passed in a JSON body; you can use Pydantic to annotate the types expected for these data. This approach is similar to using a dataclass, but extends a Pydantic BaseModel to annotate the expected argument names and types. Then, this annotated object can be passed into the argument of a POST function; FastAPI will automatically validate it and throw an error if anything is missing or invalid. Annotations can be used to define custom validation, such as requiring a string to be a URL or email. Complex data types containing other Pydantic classes, lists, etc., can also be passed in.
Chapter 4. By default, FastAPI returns a JSON response converted from a Python dictionary, but it can also return an HTML template. Instead of using string concatenation, the Jinja templating engine allows fields to be filled in dynamically; you can pass in variables, dictionaries, or even complex structures. Loops and conditionals can also be performed within the Jinja templating language. Static assets like scripts, CSS, and images can be served as well.
Chapter 5. The response object allows you to set cookies, get or set headers, and specify status codes. Several different types of responses exist; for example, StreamingResponse lets you return a generator that streams data over the connection, or you could return a file or a redirect.
Chapter 6. This chapter shows you how to set up SQLite, a simple embedded database, and connect to it from FastAPI using a context manager. You can use SQL directly or opt for an Object-Relational Mapping (ORM) tool like SQLAlchemy, which interfaces between Python objects and relational databases. SQLAlchemy allows you to perform queries using Python instead of writing SQL directly. Other databases like MongoDB can also be used; some may require installing packages to support asynchronous database calls.
Chapter 7. So far, everything has been in one file, but that won’t work for larger projects. The first thing to do is use APIRouter to group related endpoints with a prefix; then, you can set endpoints on the router instead of the global app. You can also create sub-applications, launch them separately, and then mount them on a prefix of endpoints. Dependency injection is useful when you have recurring setup needs across multiple endpoints, like a database connection; here, you can use the
Depends method to have FastAPI resolve these dependencies, which can also be parameterized for things like request authentication. Additionally, various middleware options are available to add headers, handle redirects, and manage CORS.
Chapter 8. Websockets create a duplex connection between client and server; the chapter provides examples for client-side JS and server-side implementation. Tools like Insomnia and Postman are useful for testing REST and WebSocket endpoints. GraphQL offers an efficient alternative to REST endpoints, as it only returns the resources requested by the client; the Strawberry library is recommended for implementing GraphQL on the server side. FastAPI can also be combined with other frameworks by mounting them to specific endpoints, like Flask or Django applications.
Chapter 9. Exceptions in FastAPI typically throw a 4xx error code by default, but you can define custom handlers to raise different HTTP status codes or error messages. For security, FastAPI provides utilities to easily implement OAuth. For testing, the HTTPX library is recommended to send get/post requests within unit tests; when you need to test logic that interacts with a database, you can override the dependency injection to replace the database object used in the endpoint with a mock object.
Chapter 10. Deployment options include Hypercorn, which is an alternative to Uvicorn that supports HTTP2; both Uvicorn and Hypercorn can accept a private key and certificate to serve requests over HTTPS. Since Uvicorn can only run a single process at a time, it’s recommended to use Gunicorn in production to support multiple processes that wrap around a Uvicorn worker. You can deploy the app to Render Cloud by specifying a run command; alternatively, you can use Dockerfiles to create a reproducible build, and similar steps can be taken to deploy to other clouds like Google Cloud or Deta Cloud.