Add a New Rust Project

The code for this example is available on GitHub:

Supported Features

We'll be using an Nx Plugin for Rust called @monodon/rust.

✅ Run Tasks ✅ Cache Task Results ✅ Share Your Cache ✅ Explore the Graph ✅ Distribute Task Execution ✅ Integrate with Editors ✅ Automate Updating Nx ✅ Enforce Module Boundaries ✅ Use Code Generators ✅ Automate Updating Framework Dependencies

Create the workspace with the @monodon/rust preset

We'll use the preset created by the @monodon/rust plugin to create the workspace with everything we need to build Rust applications.

npx -y create-nx-workspace@latest acme --preset=@monodon/rust

Using the preset provided by @monodon/rust will:

  • Remove any unnecessary configuration files for working with Rust projects, such as tsconfig.json and .prettierrc
  • Remove unnecessary dependencies, such as @nx/js, as we're working with a Rust project
  • Add a root Cargo.toml to manage workspace members

Create the application

Let's generate a new application using @monodon/rust.

Directory Flag Behavior Changes

The command below uses the as-provided directory flag behavior, which is the default in Nx 16.8.0. If you're on an earlier version of Nx or using the derived option, omit the --directory flag. See the as-provided vs. derived documentation for more details.

nx g @monodon/rust:binary myapp --directory=apps/myapp

Create a library

Let's generate a new library using @monodon/rust.

Directory Flag Behavior Changes

The command below uses the as-provided directory flag behavior, which is the default in Nx 16.8.0. If you're on an earlier version of Nx or using the derived option, omit the --directory flag. See the as-provided vs. derived documentation for more details.

nx g @monodon/rust:library cats --directory=libs/cats

Update the cats library

First, let's update the Cargo.toml file to define the dependencies for the library.

libs/cats/Cargo.toml
1[package] 2name = "cats" 3version = "0.1.0" 4edition = "2021" 5 6[dependencies] 7actix-web = "4" 8 9[dependencies.serde] 10version = "1" 11features = ["derive"] 12 13# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 14

Now, let's add the code to handle the cats route.

libs/cats/src/lib.rs
1use std::collections::HashSet; 2use std::sync::Mutex; 3 4use actix_web::web::*; 5use actix_web::{get, post, HttpResponse, Responder, Scope}; 6 7pub struct Cats { 8 cats: Mutex<HashSet<Cat>>, 9} 10 11#[derive(Eq, Hash, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)] 12struct Cat { 13 name: String, 14 age: u8, 15} 16 17#[get("")] 18async fn get_cats(data: Data<Cats>) -> impl Responder { 19 let cats = data.cats.lock().unwrap(); 20 21 println!("Cats {:?}", &cats); 22 23 Json(cats.clone()) 24} 25 26#[post("/add")] 27async fn add_cat(cat: Json<Cat>, data: Data<Cats>) -> impl Responder { 28 let mut cats = data.cats.lock().unwrap(); 29 30 println!("Adding {:?}", &cat); 31 32 cats.insert(cat.into_inner()); 33 34 HttpResponse::Ok() 35} 36 37pub fn create_cat_data() -> Data<Cats> { 38 Data::new(Cats { 39 cats: Mutex::new(HashSet::new()), 40 }) 41} 42 43pub fn create_cat_scope(data: &Data<Cats>) -> Scope { 44 scope("/cats") 45 // Cloning is cheap here because internally, Data uses `Arc` 46 .app_data(Data::clone(data)) 47 .service(add_cat) 48 .service(get_cats) 49} 50 51#[cfg(test)] 52mod tests { 53 #[test] 54 fn it_works() { 55 let result = 2 + 2; 56 assert_eq!(result, 4); 57 } 58} 59 60

Update the application

Let's create the http-server application and use the library to add the cats route.

First, we need to update the Cargo.toml file to define the application's dependencies.

apps/myapp/Cargo.toml
1[package] 2name = "myapp" 3version = "0.1.0" 4edition = "2021" 5 6 7[dependencies] 8actix-web = "4" 9cats = { path = "../../libs/cats" } 10 11 12# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 14

Now, let's update the application's code itself.

apps/myapp/src/main.rs
1use actix_web::{App, HttpServer}; 2 3use cats::{create_cat_data, create_cat_scope}; 4 5#[actix_web::main] 6async fn main() -> std::io::Result<()> { 7 // HttpServer:new creates multiple threads to handle requests. 8 // We need to make sure that the shared cat data is created once before the HttpServer 9 // We can then pass this reference to the create_cat_scope so that all threads have access to the same data 10 let cat_data = create_cat_data(); 11 HttpServer::new(move || App::new().service(create_cat_scope(&cat_data))) 12 .bind(("127.0.0.1", 8080))? 13 .run() 14 .await 15} 16 17

Build and Run the Application

To run the application, run the following command and then navigate your browser to http://localhost:8080/cats

nx run myapp:run

To build the application, run the following command:

nx build myapp

More Documentation