Hello World using functions

#![deny(warnings)]

use std::convert::Infallible;

use warp::Filter;

#[tokio::main]
async fn main() {
    let routes = setup_routes();

    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;
}

pub fn setup_routes() -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
    warp::path!().and(warp::get()).and_then(say_hello)
}

pub async fn say_hello() -> Result<impl warp::Reply, Infallible> {
    Ok(warp::reply::html("Hello, <b>World</b>!"))
}

#[cfg(test)]
mod test_hello_using_functions {
    #[tokio::test]
    async fn test_hello() {
        use super::setup_routes;
        use warp::test::request;
        use warp::http::StatusCode;

        let routes = setup_routes();
    
        let response = request()
            .method("GET")
            .path("/")
            .reply(&routes)
            .await;
    
        assert_eq!(response.status(), StatusCode::OK);
        assert_eq!(response.body(), "Hello, <b>World</b>!");
    }

    #[tokio::test]
    async fn test_other_path() {
        use super::setup_routes;
        use warp::test::request;
        use warp::http::StatusCode;

        let routes = setup_routes();
    
        let response = request()
            .method("GET")
            .path("/hi")
            .reply(&routes)
            .await;
    
        assert_eq!(response.status(), StatusCode::NOT_FOUND);
        assert_eq!(response.body(), "");
    }
 
    #[tokio::test]
    async fn test_post_method() {
        use super::setup_routes;
        use warp::test::request;
        use warp::http::StatusCode;

        let routes = setup_routes();
    
        let response = request()
            .method("POST")
            .path("/")
            .reply(&routes)
            .await;
    
        assert_eq!(response.status(), StatusCode::METHOD_NOT_ALLOWED);
        assert_eq!(response.body(), "HTTP method not allowed");
    }

}

In this example we have a function called setup_routes that creates all the mappings between URL pathes and requst methods (such as GET and POST) on one hand and functions that will fulfill those requests on the other hand. In this first example we have only one route that deals with the empty path (or / if you wish) as defined using the warp::path!() macro and the GET request method as defined by the warp::get() function call.

This request is mapped to the arbitrarily named say_hello function that will return some HTML using the warp::reply::html function call.

We can run this example with the following command:

cargo run --example hello_using_functions

Then we can visit http://localhost:3030/ and observe that the response is "Hello, World!". The word World being bold and we don't see the HTML tags. That's because instead of returning a plain string using Ok("Hello, <b>World</b>!"), the warp::reply::html function call set the Content-type to be text/html.

We can easily observe this using curl in another terminal:

$ curl -i  http://localhost:3030/
HTTP/1.1 200 OK
content-type: text/html; charset=utf-8
content-length: 20
date: Mon, 14 Apr 2025 15:41:21 GMT

Hello, <b>World</b>!

We can also check other pathes and observe they return a 404 Not Found with an empty page:

 $ curl -i  http://localhost:3030/hi
HTTP/1.1 404 Not Found
content-length: 0
date: Mon, 14 Apr 2025 15:42:02 GMT

Similarily using the POST method will yield a 405 Method Not Allowed error with some text:

$ curl -i -X POST  http://localhost:3030/
HTTP/1.1 405 Method Not Allowed
content-type: text/plain; charset=utf-8
content-length: 23
date: Mon, 14 Apr 2025 15:43:07 GMT

HTTP method not allowed

Testing

The second part of the file is the test. It tests the application through the route-handler (the Filter in warp terms) so it can test everything besides the web-server itself.

There are 3 test-cases. The first one checking the happy path, when the user accesses the main page with a GET request. The other two checks the two other requests that return various error status codes. It might be strange at first to test invalid requests, but even in a real-world application we'd want to make sure that invalid requests show the expected error message and not some garbage or some internal information. So it is a good practice to have tests for some invalid requests.

We can run the tests by running the following command:

cargo test --example hello_using_functions
```<style>
  footer {
    text-align: center;
    text-wrap: balance;
    margin-top: 5rem;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
  }
  footer p {
    margin: 0;
  }
</style>
<footer><p>Copyright © 2025 • Created with ❤️ by the authors of warp and <a href="https://szabgab.com/">Gabor Szabo</a></p>
</footer>