Rust Web Server Tutorial

Introduction

In this tutorial, we’ll build a simple Rust web server from scratch using the actix-web framework. actix-web is one of the most popular and performant web frameworks for Rust, and it makes it easy to get a web server running quickly.

Prerequisites:

  • Basic understanding of Rust programming

  • Rust installed on your machine (rustc and cargo)

  • Basic understanding of HTTP and web servers


Step 1: Set Up Your Rust Project

First, set up a new Rust project using cargo. Open your terminal and run the following command:

bashCopy codecargo new rust-web-server

Navigate into your new project:

bashCopy codecd rust-web-server

This creates a basic Rust project with a src/main.rs file.

Step 2: Add Dependencies

We’ll need to add the actix-web crate to the project. Open Cargo.toml and add the following lines under [dependencies]:

tomlCopy code[dependencies]
actix-web = "4.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
  • actix-web will be the main framework for handling HTTP requests.

  • serde is for serializing/deserializing data.

  • serde_json will handle JSON formatting.

Then, update your dependencies by running:

Step 3: Create a Simple Web Server

Now, let’s build a simple "Hello, World!" web server. Open src/main.rs and replace its contents with the following:

Here’s what’s happening:

  • We define a route / using the #[get("/")] attribute.

  • The hello function returns a simple "Hello, World!" response using HttpResponse::Ok().

  • In the main function, we create a new HttpServer, bind it to port 8080, and attach our hello service to the server.

To run the server, use:

Now, go to http://127.0.0.1:8080/ in your browser, and you should see "Hello, World!"


Step 4: Adding JSON Support

Next, let’s handle JSON responses. This is useful when building APIs. We’ll define a route that returns JSON data.

Replace the existing code in main.rs with the following:

Here’s what changed:

  • We defined a MyResponse struct, deriving Serialize, which allows it to be converted to JSON.

  • In json_response, we create a MyResponse instance and return it as JSON using HttpResponse::Ok().json().

Run the server again, and navigate to http://127.0.0.1:8080/json. You’ll receive a JSON response like:


Step 5: Handling POST Requests

Now that we’ve covered GET requests, let’s implement a POST route. We'll create an endpoint that accepts JSON data and responds with a message.

Modify main.rs:

Here:

  • We define a POST route with #[post("/echo")].

  • The InputData struct is used to deserialize the incoming JSON body.

  • We extract the JSON from the request using web::Json<InputData> and return a personalized message.

To test this, send a POST request using a tool like curl or Postman:

You should get back:


Step 6: Handling Errors

Let’s add basic error handling to ensure the server behaves correctly when receiving invalid requests. We’ll modify the POST handler to return an appropriate error response when the JSON format is incorrect.

Here’s how you can modify the echo route to handle errors:

Here:

  • We use Result<impl Responder, actix_web::Error> to return either a valid response or an error.

  • If the name field is empty, the server returns a 400 Bad Request error with a custom message.


Step 7: Serving Static Files

Next, let’s add support for serving static files such as HTML, CSS, and JavaScript. This is useful when building full-fledged web applications.

First, create a directory named static in the root of your project and add a file called index.html inside:

Now, modify main.rs to serve this static file:

Here:

  • We use actix_files::Files to serve files from the static directory.

  • The index_file method specifies index.html as the default file to serve when accessing the root.

Now when you navigate to http://127.0.0.1:8080/, you’ll see the index.html content.


Step 8: Adding Middleware

Middleware allows you to modify requests and responses globally. For example, you might want to log every incoming request or add security headers.

Let’s add a simple logger middleware:

Modify main.rs:

  • The middleware::Logger::default() middleware logs each request.

  • You can customize it by passing a format string to Logger::new().

Make sure to enable actix-web’s logger by setting the environment variable:


Conclusion

We’ve built a simple web server using Rust and actix-web, covering essential web server features like routing, JSON handling, error handling, serving static files, and adding middleware. From here, you can explore more advanced features like databases, websockets, or authentication with actix-web.

This should give you a strong foundation for building web applications with Rust!

Last updated