The Ultimate FastAPI Tutorial Part 12 - Setting Up a React Frontend
In part 12 of the FastAPI tutorial, we'll look at setting up a React frontend
Introduction
Welcome to the Ultimate FastAPI tutorial series. This post is part 11. The series is a project-based tutorial where we will build a cooking recipe API. Each post gradually adds more complex functionality, showcasing the capabilities of FastAPI, ending with a realistic, production-ready API. The series is designed to be followed in order, but if you already know FastAPI you can jump to the relevant part.
Code
Project github repo directory for this part of the tutorial
Tutorial Series Contents
Optional Preamble: FastAPI vs. Flask
Beginner Level Difficulty
Part 1: Hello World
Part 2: URL Path Parameters & Type Hints
Part 3: Query Parameters
Part 4: Pydantic Schemas & Data Validation
Part 5: Basic Error Handling
Part 6: Jinja Templates
Part 6b: Basic FastAPI App Deployment on Linode
Intermediate Level Difficulty
Part 7: Setting up a Database with SQLAlchemy and its ORM
Part 8: Production app structure and API versioning
Part 9: Creating High Performance Asynchronous Logic via async def
and await
Part 10: Authentication via JWT
Part 11: Dependency Injection and FastAPI Depends
Part 12: Setting Up A React Frontend
Part 13: Using Docker, Uvicorn and Gunicorn to Deploy Our App to Heroku
Part 14: Using Docker and Uvicorn to Deploy Our App to IaaS (Coming soon)
Part 15: Exploring the Open Source Starlette Toolbox - GraphQL (Coming soon)
Part 16: Alternative Backend/Python Framework Comparisons (i.e. Django) (Coming soon)
Post Contents
Theory Section - How Frontends Interact with FastAPI
Practical Section 1 - Setting Up React Create App
Practical Section 2 - Calling API from the Frontend
Theory Section - How Frontends Interact with FastAPI
So far in this tutorial series we’ve only interacted with our API via the Open API (swagger) UI, and by serving a fairly limited Jinja2 template. If your system is all backend microservices, then this is fine. However, if you’re looking to serve a more complex frontend then you’ll probably want to leverage a modern JavaScript framework like:
- React
- Angular
- Vue
Whilst each of these frameworks has their pros and cons, their interaction with FastAPI is quite similar.
Here is a rough architecture diagram:
TODO
Since React is the most popular of the modern frontend frameworks, this is the one I have chosen to use for the tutorial series. Whilst this isn’t a series on React, I will cover it in enough detail to give a meaningful example of how it would work with FastAPI - so I’m including common requirements like auth, and including multiple pages and components.
You could implement the backend in any language (node, PHP, Java…any language that can create a web server), but since this is a FastAPI tutorial, that choice is made for us :)
Note, we’ll look at deployment of both the front and backends in the next part of this series.
Practical Section 1 - Setting Up React Create App
If you’re not familiar with React then I suggest checking out the very approachable docs. The key thing to note here is that the create-react-app package we’re making use of is an officially supported tool that simplifies React apps:
Create React App is an officially supported way to create single-page React applications. It offers a modern build setup with no configuration.
Under the hood, React relies on:
- webpack: a static module builder
- babel: a JavaScript compiler mainly used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript)
- ESLint: A powerful code linter
Each of these usually requires configuring, and it can be a painful hurdle for those unfamiliar with the ecosystem. Create React App
basically
sets sensible defaults for you so you can skip all that setup. At any point you can call the eject
command (which is irreversable) and then all
the underlying config files are revealed so you can customize them. Given this simplification, it’s a great tool for when you are starting out, and
it offers flexibility as your app grows in complexity.
Setting Up the Project Structure
You’ll notice that in part 12 of our project repo we have a
new frontend
directory where all React code will be. To get started, cd
into this directory then install the dependencies:
- Note that
create-react-app
requires NodeJS 14+ - Run
npm install
in the directory where yourpackage.json
file is located (this lists our depenedencies) - To start the React app run
npm start
Your app will start, and if you then navigate over to http://localhost:3000/
you should see this:
TODO: Screenshot
You’ll notice that there are no recipes, and that is deliberate. The data for our frontend is stored in a SQL database and accessed via the FastAPI backend application. Before we hook up the backend, let’s inspect our frontend structure:
TODO: ASCII diagram
We have:
node_modules
where our frontend dependencies are installed- a
public
directory for things like a favicon and robots.txt src/components
src/pages
src/index.js
src/App.js
src/client.js
src/config.js
Practical Section 2 - Calling API from the Frontend
In this part we added the first test to our example app. The test runner is pytest.
If you’re not familiar with pytest, checkout this free pytest introduction lecture from my testing and monitoring ML models course.
For the purposes of this tutorial, the key thing to understand is that test fixtures in pytest are defined by convention
in a file called conftest.py
. So in our loan test file app/tests/api/test_recipe.py
we have a relatively
short bit of code hiding a lot more:
The key thing to note at comment (1) where the test takes the client
as its first argument. client
is a test
fixture defined in conftest.py
:
There is a lot happening here, let’s break it down by the comment numbers:
- We use the
pytest
fixture decorator to define a fixture - We access the FastAPI built-in test client via a context manager so we can easily perform clean-up (see 7)
- We use the FastAPI app dependency_overrides to replace dependencies. We replace what the selected
dependency (in this case
get_reddit_client
) callable is, pointing to a new callable which will be used in testing (in this caseoverride_reddit_dependency
) - We make use of the Python standard library unittest mock
MagicMock
(docs for those unfamiliar) - We specify the return value of a particular method in our mocked reddit client (
get_reddit_top
), here it will return dummy data - We
yield
the modified client - We perform clean up on the client, reverting the dependencies
This is an illustration of the power of dependency injection in a testing context. Whilst libraries like request-mock would also allow you to replace the return value of a particular HTTP call, we can also apply this approach to any callable, whether it’s:
- Interacting with a database
- Sending emails via SMTP
- Working with other protocols (e.g. ProtoBuf)
- Simply calling complex code we don’t need to worry about for a particular test.
All with fairly minimal setup, no monkey-patching, and fine-grained control. This is part of a broader pattern in software development: composition over inheritance (useful Python overview here).
Hopefully this shows the power and versatility of FastAPI’s dependency injection system. Learning the value of this approach will save you a lot of pain.
Continue Learning FastAPI
Next we’re going to consolidate what we’ve learned in a post on dependency injection
coming in late August