Creating a Web Server Using Rust Rocket | by Joseph Talon | Jun, 2022

In this tutorial, we will go over how to use Rust’s Rocket web framework to create a simple web server/API

image by author

Rust is a very versatile language, with many applications from game engines to entire websites. Rust also has an active and healthy community, developing many useful packages. In this tutorial, we will be looking at one of these packages called Rocket, which describes itself as:

“A web framework for Rust that makes it simple to write fastsecure web applications without sacrificing flexibility, usability, or type safety”

Coming from an Express background, I have found Rust’s Rocket to be quite simple to get the hang of once you get used to a few things — most of which have to do with Rust as a language rather than the framework itself.

In this tutorial, we are creating a simple web server that returns information about the current or future dates using Rocket, but this should set you up to create a more advanced web server/applications when you are more comfortable with Rust. This web server will handle simple GET and POST requests, so we can better understand how Rocket handles receiving and returning information.

This is a Rocket tutorial, so I will assume some beginner’s knowledge of Rust, but you can probably follow along even if you are not comfortable with it yet. If you haven’t already, be sure to install Cargo, the Rust package manager. If you haven’t, more information on Cargo can be found here.

The final code can all be found at the end of the tutorial if you would prefer to just have an example to follow.

First, we need to create a new project using Cargo. If you have cargo installed, this can be done from a command line using:

$ cargo new rust_web_server --bin

This will generate the base of a Rust binary program for us. The new directory the command created should look like this:

rust_web_server/
├─ src/
│ ├─ main.rs
├─ Cargo.toml

The Cargo.toml file is where we add our dependencies. In our case, we want to add Rocket, Serde (Serde will be used to deserialize JSON requests), and Chrono (a time library). With these dependencies added, your Cargo.toml should look similar to this:

Cargo.toml

If you wanted to, you could put all your code in the main.rs file, but I like to split it up so it feels more organized, especially once you start adding more routes and features. You can structure it to your preference, but I will be using the following structure:

rust_web_server/
├─ src/
│ ├─ main.rs
│ ├─ routes/
│ │ ├─ mod.rs
│ │ ├─ date.rs
│ ├─ services/
│ │ ├─ mod.rs
│ │ ├─ date.rs
├─ Cargo.toml

The routes folder is where we will be writing the code for our GET/POST requests, and the services folder is where we will store any logic needed for each route. In Rust, we can split related things into modules, and the mod.rs file is needed to tell the compiler what that module includes.

Now, you’ll want to run the cargo build command to install the dependencies. With that done, open main.rs so we can create the web server. We will start with a route in main.rs so we can see how Rocket works, but will then move it to the proper location in the routes folder. Go ahead and delete what’s currently in the file and replace it with the following:

main.rs

In this code, we are importing Rocket. We then declare a GET route at /, meaning that it is the default route wherever we mount it. In Rocket, we always declare the route with the structure [#type(“/location”)], followed by a function that handles any logic and returns the value we want to send back. In this example, we are returning the string Hello, welcome to the api!.

Finally, we start the web server by using #[launch] and declaring the rocket function as seen above. In this function, we can mount the routes at a certain location such as the default / or /api. Whatever routes we mount at this location can then be accessed by going to that location plus the route’s location. So in our example, we would access our route by going to server_address/api/.

This is the base of how Rust’s Rocket web framework works. If you run the command cargo runit should compile and start the web server (likely at 127.0.0.1:8000). Now, if you open a new tab in your browser and navigate to that address, you’ll get a 404 error. That’s because we mounted our route at the /api location. If you add /api to the end of the address (127.0.0.1/api), then you should see the message our say_hello() function returns.

Results

Now that we’ve seen how Rocket works, let’s move the route to its proper location and add some actual logic.

Inside routes/date.rs, let’s add a new route. This route will return the current date in JSON format. The actual logic for this will be in services/date.rs though, while routes/date.rs will just handle the request.

routes/date.rs

Here, we create a Date struct, which can be serialized and deserialized as JSON. Then, we create a GET route at /date/get-current-date which returns a JSON serialized Date object by calling our get_current_date() function inside services/date.rs and converting it to JSON.

To actually use this route, we need to go into routes/mod.rs and add the line:

pub mod date;

This lets the compiler know we want to use the date.rs module. Do the same for services/mod.rs.

services/date.rs

In our date service, we are using Chrono — a time library for Rust. In order to use our date object, we need to import it from our date route. Then, we create the function get_current_date() with the return type Date. We use Chrono to get the current UTC time, and then the year, month, and day from that. Finally, we assign it to a Date object known as current_date and return it to our route which will convert it to JSON and return that JSON to wherever the route was called.

Results

Now that we understand how to create a GET request using Rust’s Rocket, you may be wondering how we can use data sent in the API call. To show you how, we will create a POST route that will take JSON data representing a date and return the date a month from then.

Just like our get-current-date route, let’s create a date-plus-month route inside routes/date.rs.

routes/date.rs

This POST request looks a little different from our earlier GET request. the format = ‘json’ part tells Rocket that it expects only JSON data to be sent. The data = ‘<date>’ Tells Rocket to expect a variable called date in the associated function which will take the data sent to the route.

services/date.rs

In our date_plus_month service, we accept a mutable date variable of type Json<Date>, which means it is JSON but must have the same structure as our Date struct. Then, we add one month to the existing month and set it to 1 if it’s over 12, meaning we set it to January if it passes December. We also add a year in this case. Then, we assign it to a new Date struct, just like we did for our GET route, along with the other JSON values, and return it to where it’s called in the route, where it is converted into JSON and returned to the caller.

Now, just be sure to add it to the routes! macro in main.rs.

main.rs

After running cargo runwe can test the route using Postman by sending JSON following the same structure as our Date struct.

Postman results

As you can see, it worked! We sent the date 03/06/2022 and got back 03/07/2022.

Here is all the final code:

main.rs
routes/mod.rs and services/mod.rs
routes/date.rs
services/date.rs

Now, you have a basic understanding of how to handle requests and responses in Rust’s Rocket web framework. Of course, you can create much more advanced web servers and APIs than we did here, but how it’s done will remain very similar to this.

I hope that this example has helped you to better understand how Rocket works and you can now create amazing web servers using your new knowledge!

Leave a Comment