The goal of this assignment is to start using a real database to store application data. The assignment requirements are listed below.
You are provided some starter code in this repository that implements a
solution to assignment 1. The starter code's API server is implemented
in server.js
, and individual routes are modularized within the api/
directory. Tests and a testing environment for the API are included in
the tests/
directory. You can import these tests into either Postman
or Insomnia and build on them if you like. Note that, depending on
where you're running your API server, you may need to update the
baseUrl
variable in the included testing environment to reflect the
URL for your own server.
The starter code also includes an openapi.yaml
file in the public/
directory. You can import this file into the OpenAPI editor at
https://editor.swagger.io/ to generate documentation for the server to
see how its endpoints are set up.
Feel free to use this code as your starting point for this assignment. You may also use your own solution to assignment 1 as your starting point if you like.
Your overarching goal for this assignment is to modify the API server to use a database to store the following resources:
- Businesses
- Reviews
- Photos
You may choose either MySQL or MongoDB for this purpose (or another DB implementation you're interested in, with permission). Whichever database you choose, it should completely replace the starter code's existing JSON/in-memory storage for these resources. In other words, you should update all API endpoints in the original starter code to use your database.
You should use the official MySQL Docker image or the official MongoDB Docker image from Docker Hub to power your database. Whichever database you choose, your implementation should satisfy the criteria described below.
Before you run your application for the first time, you'll have to make sure your database is initialized and ready to store your application data. Use the mechanisms described below to initialize your database when you launch the database container, so the database is ready to use when you launch your app.
If you're using MySQL, you should make sure to set the following environment variables when launching your database container:
-
MYSQL_ROOT_PASSWORD
- This specifies the password that is set for the MySQLroot
user. You can also useMYSQL_RANDOM_ROOT_PASSWORD
to allow the container to generate a random password. -
MYSQL_DATABASE
- This specifies the name of a MySQL database to be created when your container first starts. -
MYSQL_USER
andMYSQL_PASSWORD
- These are used to create a new user, in addition to theroot
user, who will have permissions only for the database named inMYSQL_DATABASE
. This is the user you should use to connect to your database from your API server.
If you use Sequelize to interact with your MySQL database, Sequelize will handle the creation of tables for you.
If you're using MongoDB, you should make sure to set the following environment variables when launching your database container:
-
MONGO_INITDB_ROOT_USERNAME
andMONGO_INITDB_ROOT_PASSWORD
- These are used to create the MongoDBroot
user. -
MONGO_INITDB_DATABASE
- This specifies the name of a MongoDB database to be created when your container first starts.
While it is a security risk to do so in a production setting, it's fine if you interact with the database from your API server as the ROOT user for this assignment. Because MongoDB generally uses a "create on first use" approach, you won't have to worry about initializing collections.
Your database should store all resource data (i.e. businesses, photos, and reviews) for the API. Because the resources you're working with are closely tied to each other (e.g. each review is tied to both a specific business and a specific user), you'll have to think carefully about how you organize and access them in your database. Some suggestions are included below for each database.
If you're using MySQL, you will likely want to use foreign keys to link reviews and photos to their corresponding business. If you're using Sequelize, you can use associations to automatically manage foreign keys for you.
If you're using MongoDB, there are many valid ways to organize data in
your database. For example, you could use three separate collections to
store businesses, reviews, and photos. In this case, you can either use
$lookup
aggregation
or multiple queries to gather data for a specific business (i.e. for the
GET /businesses/{id}
endpoint).
Alternatively, you could store all photos and reviews as subdocuments of
their corresponding business document. In this case, you'll likely want
to use a
projection
to omit the photo and review data from businesses when returning a list
of all businesses (i.e. from the GET /businesses
endpoint). You'll
also have to think carefully about how you find data for a specific
user, e.g. a specific user's photos or reviews. Do do this, you can use
subdocument array
queries
to select businesses with reviews/photos by the specified user, and then
you can use some custom JS to select only matching reviews/photos from
those businesses. Alternatively, you can use MongoDB's aggregation
pipeline to
structure a single query to fetch exactly the reviews/photos you're
interested in.
Your API server should read the location (i.e. hostname, port, and database name) and credentials (i.e. username and password) for your database from environment variables.
You should write a simple Docker Compose specification that launches your entire application (i.e. API server and database server) from scratch with a single command. Your Docker Compose specification in this case will specify two containers, one running your API server and one running your database server.
When defining your Compose specification, make sure to specify the correct environment variables to initialize the database container and to allow the API server to connect to the database container, and make sure you publish the appropriate port(s) so you can communicate with your API. Note that there is already a Dockerfile in this repository representing an image to run your API server, and you can reference this Dockerfile within your Compose specification.
It's a good idea to think about the Docker Compose specification as a "production" version of your app. In other words, get your server working the way you want them to without Docker before you worry about getting things working with Compose. It'll lengthen your development cycle too much if you continually need to restart the Compose application every time you make changes to your server code.
Mongoose is an object modeling tool for MongoDB that's very similar in spirit to Sequelize for MySQL. If you choose to use MongoDB as your database, you can earn up to 10 points of extra credit by using Mongoose instead of the native MongoDB driver for Node.js. To earn this extra credit, you must use Mongoose for all of your database interactions.
Make sure your completed files are committed and pushed by the assignment's deadline to the main branch of your GitHub repo. Check your repo to make sure your files are submitted there.
This assignment is worth 100 total points, broken down as follows:
-
20 points: chosen database runs in a Docker container that is correctly initialized (e.g. by using appropriate environment variables the first time the container is launched)
-
60 points: all existing API endpoints in the starter code are modified to use your database
-
10 points: database connection parameters are correctly provided to API server via environment variables
-
10 points: a Docker Compose specification can be used to launch the entire application from scratch
As described above, you can also earn up to 10 points of extra credit for using Mongoose in conjunction with MongoDB.