Full Stack React + FastAPI Example - TypeScript/Python

Will Sams

Backend Engineer
Frontend Engineer
Fullstack Engineer
Python
React
TypeScript
none
This example contains a frontend and backend:
The frontend is a React application using Bootstrap4 for view designs.
The backend is a GraphQL API providing the ability to create, delete, and list reservations plus available rooms for a given date range.
React JavaScript and Express MVC versions of this same idea are available.
Context:
When a room is reserved, it cannot be reserved by another guest on overlapping dates.
Whenever there are multiple available rooms for a request, the room with the lower final price is assigned.
Whenever a request is made for a single room, a double bedroom may be assigned (if no single is available?).
Smokers are not placed in non-smoking rooms.
Non-smokers are not placed in allowed smoking rooms.
Final price for reservations are determined by daily price * number of days requested, plus the cleaning fee.
Web UI Usage:
API Usage:
Example usage via curl:
# First, grab an access token provided by the API ACCESS_TOKEN=$(curl -s -X POST \ -H 'accept: application/json' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'grant_type=password&username=example-user&password=example-user' \ "http://localhost:$RESERVATION_PORT/development/token" | jq -r '.access_token') # List all existing booked reservations curl http://localhost:$RESERVATION_PORT/development/graphql \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -d '{"query": "query { getAllReservations { reservations { room_id checkin_date checkout_date } } }"}' # Create a new reservation # Note: if there is an overlap, you'll see a # 'Reservation dates overlap with an existing reservation' error message # To see the aforementioned error, run this mutation a multiple times curl http://localhost:$RESERVATION_PORT/development/graphql \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -d '{ "query": "mutation { createReservation( input: { room_id: \"91754a14-4885-4200-a052-e4042431ffb8\", checkin_date: \"2023-12-31\", checkout_date: \"2024-01-02\" }) { success errors reservation { id room_id checkin_date checkout_date total_charge } } }" }' # List Available Rooms for a given date range curl http://localhost:$RESERVATION_PORT/development/graphql \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -d '{"query": "query { getAvailableRooms( input: { checkin_date: \"2023-12-31\", checkout_date: \"2024-01-02\" }) { success errors rooms { id num_beds allow_smoking daily_rate cleaning_fee } } }" }'
Open API UI Usage:

Pre-requisites

To run the service, you will need to install the following tools.
The below are optional but highly recommended:
nvm - Used to manage NodeJS versions.
Direnv - Used to manage environment variables.
Install direnv for persisting environment variables needed for development.

Getting Started

First, we'll need to set up our environment variables. You can do this by the methods mentioned in /tools/ENV.md but I recommend using Direnv.

Install Python Packages

Execute the following in your terminal:
python -m venv venv source venv/bin/activate # for Windows, source venv/Scripts/activate python -m pip install --upgrade pip pip install -r requirements.txt

Install Node.js Packages

Execute the following within your terminal:
nvm use # To eliminate any issues, install/use the version listed in .nvmrc. npm i # install the packages needed for project cd ../frontend && npm i # install the packages needed for the frontend cd ../db && npm i # install the packages needed for database migrations cd .. # navigate back to the root of the repostiory

Create the database

Finally, let's create and seed the databases and our Reservations and Rooms tables:
# Create the databases and seed them NODE_ENV=development | npm run refresh && npm run seed
During development, you can just execute npm run dev:db-baseline to refresh the database back to the original seed data.

Development

To run both the frontend and backend concurrently:
docker-compose up -d # runs the database in the background npm run dev
Also, you just execute the backend via npm run dev:backend. to verify the backend is working:
curl http://localhost:$RESERVATION_PORT/$ENV/about
You can also accces the Ariadne GraphiQL (interactive test playground) instance at http://localhost:$RESERVATION_PORT/$ENV/graphql.

Testing

The backend uses Pytest and the frontend uses Jest. To run these tests, simply execute npm run test:backend or npm run test:frontend, respectively.

Containerization

Building the Backend Container

docker build backend/. -t acme-hotel-example-backend:latest \ --build-arg RESERVATION_PORT="80" \ --build-arg ENV="${ENV}" \ --build-arg IS_DEBUG="${IS_DEBUG}" \ --build-arg SECRET_KEY="$SECRET_KEY" \ --build-arg REFRESH_SECRET_KEY="$REFRESH_SECRET_KEY" \ --build-arg PG_URL="$PG_URL" # finally, to run a named container docker run --name backend-dev -p 8000:80 acme-hotel-example-backend
To verify the environment variables set, you can execute the following on the named container by:
CONTAINER_ID=$(docker ps -qf "name=backend-dev" -n 1) # this will display the container's environment variables in console docker exec $CONTAINER_ID printenv
If you need to re-create the container with the same name, do docker rm (i.e., backend-dev) first.

Building the Frontend Container

docker build frontend/. -t acme-hotel-example-frontend:latest \ --build-arg FRONTEND_PORT="80" \ --build-arg NODE_ENV=${NODE_ENV} # finally, to run a named container docker run --name frontend-dev -p 3000:80 acme-hotel-example-frontend
To verify, follow similar steps also explained in the above Building the Backend Container section.
Partner With Will
View Services