BlogAtlas Vector Search voted most loved vector database in 2024 Retool State of AI reportLearn more >>
MongoDB Developer
Atlas
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Productschevron-right
Atlaschevron-right

Build a CRUD API With MongoDB, Typescript, Express, Prisma, and Zod

Onyedikachi Kindness Eni9 min read • Published Jun 12, 2024 • Updated Jun 12, 2024
PrismaTypeScriptAtlas
FULL APPLICATION
Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty

Project overview

Traditional technologies often struggle to keep pace with the demands for scalability, maintainability, and rapid development cycles. These systems are plagued by monolithic architectures, difficult-to-maintain codebases, and a lack of modern tooling, leading to inefficiencies and increased development costs.
Enter the modern stack: TypeScript, Express, Prisma, MongoDB, and Zod. This powerful combination offers a robust, type-safe, and scalable solution for building web applications. TypeScript enhances JavaScript with static typing, reducing runtime errors and improving developer productivity. Express, a minimalist web framework, simplifies the creation of APIs with its lightweight yet powerful routing and middleware capabilities. Prisma, a next-generation ORM, provides a type-safe interface to interact with databases, bridging the gap between application logic and database operations. MongoDB Atlas, a leading NoSQL database and data platform, excels in handling large volumes of unstructured data and horizontal scaling. Finally, Zod ensures data integrity with its TypeScript-first schema declaration and validation.
Using this modern stack, we will build a basic user management API that will perform the following CRUD operations:
  • Create user accounts
  • Read user profiles
  • Update user information
  • Delete user accounts
Express will be used to build the web server, Prisma the ORM, MongoDB as the database, and Zod to validate payloads.

Prerequisites

  • Working knowledge of Typescript
  • Familiarity with Express
  • MongoDB Atlas cluster
  • Code editor — such as VS Code
  • Node.js latest LTS installed on your computer
The source code for this project can be found on GitHub.

Project setup

Installing dependencies

Create a project directory called CRUD-API and navigate to it.
Next, initialize a new project and install Typescript and Prisma:
The preceding command creates a package.json file with a Typescript setup:
Next, initialize TypeScript:
Run the following command to invoke Prisma CLI.
Run the following command to set up your Prisma ORM project:
The preceding commanding does the following:
  • Creates a new prisma directory with a schema.prisma file
  • Creates a .env file, where the environment variable used for the database connection will be defined
Run the following command to install the @prisma/client package, which will allow us to use Prisma Client.
In the preceding command, we installed the @prisma/client package, express, and zod. The @prisma/client package will allow us to use Prisma Client for database access.
Finally, run the following command:
After installing the dependencies, your package.json file should look like this:
The tree structure of the project should look like this:

Setting up Express

In the root directory of the project, create a src sub-directory. The src directory will include the source code of the API.
Next, in the src directory, create an app.ts file and enter the following code:

Running Express

To launch our server, we have to add a new script to our package.json file. Add the following line to the scripts property of the package.json file:
In the preceding code, we are using the nodemon command. nodemon is an excellent tool for Node.js applications. It can restart your server when the source changes.
Enter the command below to start the server:
Now, when you go to your browser and enter http://localhost:3000, you will see the text Hello World! from our Express callback function. HelloWorldHealthCheck

Connecting to the database (MongoDB)

To store our data, we will use MongoDB Atlas. A database connection URL is required to connect the database via Prisma. Follow the guide to set up a MongoDB Atlas cluster and [get a connection]((https://www.mongodb.com/docs/guides/atlas/connection-string/) URL.
Next, in the .env file, add the connection URL as an environment variable:
In the prisma.schema file, enter the following code:
The preceding code provides the required data for Prisma to connect to our database. In the datasource block, the value passed to the provider represents the type of database being used (MongoDB, in this case), while the value of url is the database connection URL.

Creating the Prisma schema

Since we are building a basic user management API, only a single collection will be required.

User model

The user model will define the user details to be stored in the database, with the following attributes:
  • name: String, required field to store user’s name
  • email: String, required field to store user’s email
  • phoneNumber: String, required field to store user’s phone number
  • gender: String, required field to store user gender

API endpoints for user CRUD

To enable and handle user CRUD operations on the database, we will implement the following API endpoints.
Now, let’s create the API schema.
In the prisma/schema.prisma file, add the following code:
In a traditional relational database, a model will create a table, but since we are using MongoDB, our model creates a collection. Notice the id field is mapped with @map("_id") decorator because _id is the default provided by MongoDB.
Now, let’s generate the Prisma Client by running the following command:
The Prisma Client gives us type-safe access to our database.
Next, we will implement our route controllers which will utilize Prisma Client to perform database operations.

Controllers

Fundamentally, routers and controllers enable the structured handling of requests and responses in an application. The routers map incoming HTTP requests to specific endpoints, while the controllers receive the requests from routers, process any business logic, interact with the database, and return the appropriate responses to the client.
Now, let’s create the routes and controllers.
In the src directory, create a client.ts file and enter the following code:
In the preceding code, we created a Prisma Client instance, which will be used for database interaction.
Next, in the src directory, create the routes and controllers sub-directories.
By default, a controller handles incoming requests, processes them, and provides an appropriate response. Let’s implement the controllers for our API.
In the controllers subdirectory, create a user.route.ts file.

createUser controller

The createUser handles POST requests for creating new users.
Enter the following code in the user.route.ts file.

getUsers controller

The getUser controller handles GET requests for all users.
Enter the following in the user.route.ts file.
In the preceding code, the getUser controller gets a single user.

deleteUser controller

Enter the following in the user.route.ts file.
In the preceding code, the deleteUser controller deletes a user.

updateUser controller

Enter the following in the user.route.ts file.
In the preceding code, the updateUser controller updates a user.
Next, let’s create the routes that will utilize the controllers.

Routes

In the routes subdirectory, create an index.ts and user.routes.ts file.
In index.ts, enter the following code:

Testing with Postman

The GET route can be seen in the browser, but to check the other routes, we will use the POSTMAN tool.

POST

Let’s create a new user via the POST method. In the address bar in Postman, enter the request URL http://localhost:3000/users, enter the payload, and hit the send button. We will receive back the correct JSON and also the status of 201 — confirming a resource has been created. enter image description here POST Request: Create a User

GET

The GET method is used to fetch all users. It requires no payload. enter image description here GET Request: Get all Users
However, to fetch a single user, we have to provide the user id. The endpoint will be http://localhost:3000/users/id.
enter image description here GET Request: Get a single user

DELETE

For the DELETE method, the id of the user being deleted will be provided. Again, we are using the endpoint http://localhost:3000/users/id. enter image description here DELETE: delete a user

PATCH

For the PATCH method also, we have to provide an id of the user being updated. We will use the endpoint http://localhost:3000/users/id. enter image description here PATCH: update a user
Notice we passed an invalid value james.com in the e-mail field and it’s seen as valid. This won’t be the case after we implement the validation middleware.

Validation with Zod

Now, let’s validate the payload of incoming requests (POST, PATCH) to ensure they meet the required data format as specified in our model — i.e., an e-mail must be a valid e-mail address (not just any string).

Validation schema

First, we will create a Zod schema to describe the required data format.
Create a schemas subdirectory in the src directory, and then create a user.schema.tsfile.
Enter the following code in user.schema.ts:
In the preceding code, the following schemas were created:
  • createUserSchema: This validates the payload coming into the createUser controller via the POST request.
  • updateUserSchema: This validates the payload coming into the updateUser controller.

Validation middleware

Now, let’s create a validation middleware that uses the schema to validate an incoming payload.
In the preceding code, the Zod schema is used to parse the request body. If the parsing is successful, the next function is called. Otherwise, a JSON response with a 401 status code and an error message are returned.

Using the validation middleware

Now, let’s modify the user.routes.ts file by adding the validation middleware to the createUser and updateUser routes.
In comparison to our previous implementation (without validation), sending an invalid payload will return an error now.
Let’s test the PATCH method again: enter image description here PATCH: Invalid e-mail field
This time, we get an error indicating the value of the e-mail field is invalid.
Now, if we use a valid e-mail address, the errors are gone: enter image description here PATCH: Valid e-mail field

Conclusion

In this tutorial, we created a simple CRUD API with Express, MongoDB, and Zod. You learned how to create a server with Express, set up a Prisma schema, validate payloads with Zod, and test API with Postman. Feel free to clone the project from GitHub, sign up for MongoDB Atlas, and build on this foundation. If you want to continue the conversation, join us in the MongoDB Developer Community.

Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Article

Cross Cluster Search Using Atlas Search and Data Federation


Jul 22, 2022 | 3 min read
Tutorial

Visually Showing Atlas Search Highlights with JavaScript and HTML


Feb 03, 2023 | 7 min read
Article

Triggers Treats and Tricks - Auto-Increment a Running ID Field


Sep 23, 2022 | 3 min read
Tutorial

How to Use Custom Archival Rules and Partitioning on MongoDB Atlas Online Archive


May 31, 2023 | 5 min read
Table of Contents