Build a seat booking app with SQLite in Durable Objects
In this tutorial, you will learn how to build a seat reservation app using Durable Objects. This app will allow users to book a seat for a flight. The app will be written in TypeScript and will use the new SQLite storage backend in Durable Object to store the data.
Using Durable Objects, you can write reusable code that can handle coordination and state management for multiple clients. Moreover, writing data to SQLite in Durable Objects is synchronous and uses local disks, therefore all queries are executed with great performance. You can learn more about SQLite storage in Durable Objects in the SQLite in Durable Objects blog post ↗.
The application will function as follows:
- A user navigates to the application with a flight number passed as a query parameter.
- The application will create a new Durable Object for the flight number, if it does not already exist.
- If the Durable Object already exists, the application will retrieve the seats information from the SQLite database.
- If the Durable Object does not exist, the application will create a new Durable Object and initialize the SQLite database with the seats information. For the purpose of this tutorial, the seats information is hard-coded in the application.
- When a user selects a seat, the application asks for their name. The application will then reserve the seat and store the name in the SQLite database.
- The application also broadcasts any changes to the seats to all clients.
Let’s get started!
- Sign up for a Cloudflare account ↗.
- Install
Node.js
↗.
Node.js version manager
Use a Node version manager like Volta ↗ or
nvm ↗ to avoid permission issues and change
Node.js versions. Wrangler, discussed
later in this guide, requires a Node version of 16.17.0
or later.
Create a new Worker project to create and deploy your app.
-
Create a Worker named
seat-booking
by running:For setup, select the following options:
- For What would you like to start with?, choose
Hello World example
. - For Which template would you like to use?, choose
Hello World Worker Using Durable Objects
. - For Which language do you want to use?, choose
TypeScript
. - For Do you want to use git for version control?, choose
Yes
. - For Do you want to deploy your application?, choose
No
(we will be making some changes before deploying).
- For What would you like to start with?, choose
-
Change into your new project directory to start developing:
The frontend of the application is a simple HTML page that allows users to select a seat and enter their name. The application uses Workers Static Assets to serve the frontend.
-
Create a new directory named
public
in the project root. -
Create a new file named
index.html
in thepublic
directory. -
Add the following HTML code to the
index.html
file:
public/index.html
- The frontend makes an HTTP
GET
request to the/seats
endpoint to retrieve the available seats for the flight. - It also uses a WebSocket connection to receive updates about the available seats.
- When a user clicks on a seat, the
bookSeat()
function is called that prompts the user to enter their name and then makes aPOST
request to the/book-seat
endpoint.
- Update the bindings in
wrangler.toml
to configureassets
to serve thepublic
directory.
- If you start the development server using the following command, the frontend will be served at
http://localhost:8787
. However, it will not work because the backend is not yet implemented.
The application already has the binding for the Durable Objects class configured in wrangler.toml
. If you update the name of the Durable Objects class in src/index.ts
, make sure to also update the binding in wrangler.toml
.
- Update the binding to use the SQLite storage in Durable Objects. In
wrangler.toml
, replacenew_classes=["Flight"]
withnew_sqlite_classes=["Flight"]
,name = "FLIGHT"
withname = "FLIGHT"
, andclass_name = "MyDurableObject"
withclass_name = "Flight"
. Yourwrangler.toml
should look like this:
Your application can now use the SQLite storage in Durable Objects.
- Add the
initializeSeats()
function to theFlight
class. This function will be called when the Durable Object is initialized. It will check if the table exists, and if not, it will create it. It will also insert seats information in the table.
For this tutorial, the function creates an identical seating plan for all the flights. However, in production, you would want to update this function to insert seats based on the flight type.
Replace the Flight
class with the following code:
- Add a
fetch
handler to theFlight
class. This handler will return a text response. In Step 5 You will update thefetch
handler to handle the WebSocket connection.
- Next, update the Worker’s fetch handler to create a unique Durable Object for each flight.
Using the flight ID, from the query parameter, a unique Durable Object is created. This Durable Object is initialized with a table if it does not exist.
- Add the
getSeats()
function to theFlight
class. This function returns all the seats in the table.
- Add the
assignSeat()
function to theFlight
class. This function will assign a seat to a passenger. It takes the seat number and the passenger name as parameters.
The above function uses the broadcastSeats()
function to broadcast the updated seats to all the connected clients. In the next section, we will add the broadcastSeats()
function.
All the clients will connect to the Durable Object using WebSockets. The Durable Object will broadcast the updated seats to all the connected clients. This allows the clients to update the UI in real time.
- Add the
handleWebSocket()
function to theFlight
class. This function handles the WebSocket connections.
- Add the
broadcastSeats()
function to theFlight
class. This function will broadcast the updated seats to all the connected clients.
- Next, update the
fetch
handler in theFlight
class. This handler will handle all the incoming requests from the Worker and handle the WebSocket connections using thehandleWebSocket()
method.
- Finally, update the
fetch
handler of the Worker.
The fetch
handler in the Worker now calls appropriate Durable Object function to handle the incoming request. If the request is a GET
request to /seats
, the Worker returns the seats from the Durable Object. If the request is a POST
request to /book-seat
, the Worker calls the bookSeat
method of the Durable Object to assign the seat to the passenger. If the request is a WebSocket connection, the Durable Object handles the WebSocket connection.
You can test the application locally by running the following command:
This starts a local development server that runs the application. The application is served at http://localhost:8787
.
Navigate to the application at http://localhost:8787
in your browser. Since the flight ID is not specified, the application displays an error message.
Update the URL with the flight ID as http://localhost:8787?flightId=1234
. The application displays the seats for the flight with the ID 1234
.
To deploy the application, run the following command:
Navigate to the [DEPLOYED_APP_LINK]
to see the application. Again, remember to pass the flight ID as a query string parameter.
In this tutorial, you have:
- used the SQLite storage backend in Durable Objects to store the seats for a flight.
- created a Durable Object class to manage the seat booking.
- deployed the application to Cloudflare Workers!
The full code for this tutorial is available on GitHub ↗.