Creating performant REST APIs with Rust using Rocket, Diesel and Serde — Part 1

SphericalKat
The Startup
Published in
4 min readMay 6, 2020

I’ve been hearing about Rust and its powerful features for a while now, and I finally decided to try it out for myself. If you don’t know, here’s a short summary of why Rust is gaining popularity.

  1. Rust is extremely safe. It prevents the programmer from making mistakes that might lead to unsafe behaviour (such as data races).
  2. Rust is highly performant, on par with C/C++. This makes it a great alternative for systems programming, where speed and safety are critical.
  3. Rust has a growing community, and an official package manager called cargo, with many packages (called crates) available at crates.io.

What’s in scope for this tutorial?

We’ll cover everything from setting up Rust to the final outcome in detail. Don’t hesitate to ask any questions you have! A companion repo for this project is available here.

Don’t be alarmed if you don’t understand everything straightaway, Rust does have a rather steep learning curve, but the rewards are worth it! :)

Note: I do expect a basic understanding of programming, syntax, and the ownership model of Rust. If you’re unfamiliar, check out the Rust Book before proceeding.

Crates we’ll be using

  1. Rocket - Write fast, secure web applications without compromising on flexibility.
  2. Serde - Popular framework for Serializing and Deserializing Rust data structures into JSON.
  3. Diesel - Safe, Extensible ORM and Query Builder for Rust.

Setting up Rust on your machine

If you don’t have Rust installed already, it’s very easy to get it up and running! Simply follow the instructions at rustup.rs, and you’ll have a working Rust install.

After ensuring Rust is installed, we need to set up a Rust project. This can be done using the following command.

cargo new hello-rocket --bin && cd hello-rocket

Before we continue, we need to switch to the nightly Rust build, because Rocket requires some features which aren’t in the stable branch yet.

rustup override set nightly
rustup update && cargo update

These commands will switch you to the nightly channel for this project only, and ensure everything is up-to-date. With that out of the way, let’s move on to a simple hello-world REST API.

Hello, World!

Every programmer knows these words, and for good reason. While it looks deceptively simple at first, there’s actually a lot we can learn from a Hello World application. Let’s begin by adding some base dependencies to our Cargo.toml file.

Note: Cargo.toml is an analogue to package.json for NPM projects or go.mod for Go modules.

[dependencies]
rocket = "0.4.4"
rocket_codegen = "0.4.4"

These will get us set up for creating an API using Rocket. Let’s take a look at the basic hello-world application. Add the following code to src/main.rs.

Let’s examine what each part does. The top feature flags are used to enable some nightly features that Rocket uses. Not much to look at there.

The next statement brings rocket’s public functions and macros into local scope. Think of it as being similar to using namespace in C++.

The index handler

Next we have a function with an interesting attribute: #[get("/<name>")]. Let’s break it down.

  1. get annotates that this handler will be triggered by a GET request.
  2. ("/<name>") adds a route variable. The name of the variable will be name and the type is determined by handler function just below it. In this case, the type is String.
  3. The return type of the function is String. The value returned from the Handler is sent as the response. In this case, we’re returning a greeting to the name the handler was called with.

Launching the application server

Moving on to the main function, we see some more interesting stuff.

  1. rocket::ignite(). This simply creates a new instance of Rocket.
  2. The subsequent call to mount adds the index handler function to the /base path.
  3. launch starts up the application server, starts listening to listening for and dispatching requests to the mounted handlers.

Let’s see a demo!

We can start the application by running cargo run. This builds and runs the app in debug mode.

Launching Rocket

Looks pretty cool! Let’s see if we get the response by opening http://localhost:8000/<some-name> in our browser.

Response from index handler

Looks like it works! But what if we tried accessing other nonexistent routes?

Nonexistent routes

Looks like Rocket takes care of that for us too. How convenient!

Request logging

If we take a look at our console where we launched rocket, we’ll see the following.

We see neatly formatted logs for each request. This is especially useful during debugging, and can be disabled in production environments by setting ROCKET_ENV=production.

Conclusion… For now!

So far, we’ve done the following:

  1. Installed Rust and switched to the nightly channel for this project.
  2. Installed rocket as a dependency.
  3. Created a simple hello-world handler.
  4. Mounted and launched the handler.

Congratulations! You’ve created a very basic REST API in Rust. In the next part, we’ll continue with connecting to a database using diesel and serializing/deserializing JSON data using serde.

--

--