Building a CRUD API with Rust and MongoDB
Are you ready to dive into the world of Rust web development with MongoDB? In our previous post, we explored how to create a web API in Rust with Postgres. This time, we’ll show you how to build a similar app with MongoDB, a popular and widely-used document database.
Getting Started
To follow along, you’ll need a recent Rust installation (1.39+) and a way to start a local MongoDB instance, such as Docker. You’ll also need a tool to send HTTP requests, like curl or Postman. Create a new Rust project and edit the Cargo.toml file to add the necessary dependencies.
Project Structure
Our small example application will consist of three modules:
- db: database access logic
- error: errors and HTTP error response handling
- handler: CRUD HTTP handlers
Let’s start with the database access and work our way up.
Database Access
First, we’ll create a small abstraction for database access that we can pass around the application. Then, we’ll establish a way to initialize a MongoDB client. Creating a MongoDB client in Rust is straightforward: simply parse a connection string to create ClientOptions, set an application name, and initialize the client with the options.
Querying the Database
To make a simple query, such as finding all books in the database, we’ll use the get_collection()
helper to select a collection. This operation doesn’t actually talk to the database; it just sets the collection context we want to operate in. Next, we’ll execute the find()
command on this collection, passing no filter and no other options. We’ll then await the result of find()
to get a Cursor, which is a Stream. This stream can be iterated, and once it’s exhausted, the cursor will automatically fetch the next chunk of data until no more is left.
CRUD Handlers
Our handlers are simple: they receive some input and call the database abstraction. We’ll use the BookRequest
type as a data object for creating and editing books. Each handler has a DB
passed to it via a warp filter. The handlers simply call their respective functionalities in the database abstraction and return either a success message in the form of an HTTP 200 OK or, in the case of books_list_handler
, a list of the existing books.
Putting it all Together
In main
, we’ll define the shared Result
types and initialize the database abstraction. We’ll then define some routes, passing the MongoDB database wrapper to the handlers. Finally, we’ll start the actual web server.
Testing the API
Start a local MongoDB instance using Docker, create a book, and check to make sure it worked by fetching all books. Then, edit the book and test that it worked. Finally, test to make sure the books were successfully deleted.
The Future of Rust Web Development
This use case demonstrates the rapidly maturing Rust web ecosystem. The MongoDB driver provides strong support for both the tokio and async_std runtimes, offering full synchronous and asynchronous APIs. With its intuitive API and active maintenance, we’re excited to see the first Rust and MongoDB apps in production.
Debugging with LogRocket
Debugging Rust applications can be challenging, especially when users experience issues that are hard to reproduce. LogRocket provides full visibility into web frontends for Rust apps, allowing you to monitor and track performance, automatically surface errors, and track slow network requests and load time. Try LogRocket today to modernize how you debug your Rust apps!