Subscribe

Let's build a REST API in Rust πŸ¦€ - Part 2

Nov 03, 2024

Last week we built a very simple REST API in Rust with a health endpoint. Today I want to show you step-by-step how to add a second endpoint that will return historical NYC Taxi Data.

Github repository


You can find all the source code in this repository
Give it a star ⭐ on Github to support my work

 

The starting point πŸ“ 

Our initial API does nothing especial, apart from saying “Hey! I am alive”.

We accomplished this by:

  1. Adding a /health route to our HttpServer,

  2. Attaching an async function health() to handle requests to this endpoint, and

  3. Implementing this health() function.

Let me show you step-by-step how to add a second endpoint to our HttpServer, to serve historical data of NYC taxi trips from this website.

 

🚨 Attention 🚨

To keep things simple, and not get overwhelmed, we will be returning fake data today.

Next week I will show you how to get real data by

  • Parsing from the GET request the time period for which the client app requests data,

  • Downloading the necessary Parquet files asynchronously from this website.

  • Processing the the data using Polars (similar to pandas)

  • Returning the data as JSON

 

Step 1. Add a new /trips endpoint 🚩 

The steps are:

  • Add a trips route to our actix web app

  • Define the trips() function to handles get requests to this endpoint, and

  • Parse 2 input parameters from the GET request

    • from_ms → timestamp in milliseconds from which we want data, and

    • n_results → number of data points to return to the client app.

What is web::Query<TripQuery> β“

This is Actix-web's way of handling query parameters in URLs.

  • web::Query is a struct provided by Actix-web that extracts and deserializes query parameters from the URL

  • TripsQuery is our custom struct that specifies the expected structure of the query parameters:

When a client app makes a request to your endpoint like:

GET /trips?from_ms=1234567890&n_results=10

Actix-web will:

  • Extract these query parameters from the URL

  • Automatically deserialize them into your TripsQuery struct

  • Make them available to our handler function as query.from_ms and query.n_results

Cool! We have an endpoint that extracts the parameters of the GET request. Let’s now move to the business logic.

 

Step 2. Extract business logic to another file πŸ’‘ 

It is best to decouple the function handlers, and the underlying functions that do the heavy work.

Create another file called backend.rs, with one public function called get_fake_trips()

Why is get_fake_trips() public❓

The pub keyword in this function makes it publicly accessible from our main.rs file. In Rust, privacy is enforced by the compiler:

  • pub = like a normal Python function (accessible everywhere)

  • no modifier = truly private (only accessible in the same module)

  • pub(crate) = accessible only within your project (no equivalent in Python)

So while Python's privacy is "we trust you not to use this", Rust's privacy is "you literally cannot use this unless allowed".

Inside the get_fake_trips we randomly generate a vector of n_result Trips

Let’s now use this function.

 

Step 3. Call the get_fake_trips πŸ“ž

Finally, we

  • import the get_fake_trips function into scope, and

  • call it, and

  • handle its return value using the match expression

What is match and why do we need it here❓

get_fake_trips() returns a Result type, which in Rust is an enum that can be either:

  • Ok(value) - containing the successful result

  • Err(error) - containing an error if something went wrong

The match expression checks which variant we got and handles each case:

  • If we got Ok(trips), it returns an HTTP 200 response with the trips data as JSON

  • If we got Err(e), it returns an HTTP 500 error with the error message

 

Step 4. Test the endpoint works πŸ”Ž

From the command line run

$ curl -X GET "http://localhost:$(PORT)/trips?from_ms=1714204800000&n_results=100"

and you should see a nice batch of 100 (fake) taxi trips.

 

Next steps πŸ‘£ 

Next week we will

  • fetch and serve Real World data of NYC taxi trips from this website,

  • add some logging, and

  • dockerize our REST API for production

 

Let’s Rust ! πŸ¦€

On November 18th, 19 brave students will join my on a LIVE ADVENTURELet’s Rust!

It will take us 2 weeks, 4 sessions, and 12 hours of intensive coding sessions πŸ”₯πŸ”₯πŸ”₯ to build and deploy an ML model in Rust.

Are you ready for the challenge? 😎

 

Click here to read the details 

 

Talk to you next week,

Enjoy the weekend,

Pau

The Real World ML Newsletter

Every Saturday

For FREE

Join 20k+ ML engineers ↓