Cargo workspace, monorepo for Rust

Reidar Sollid

Cargo workspace, monorepo for Rust

Cargo workspace har ett eller flere cargo prosjekter i seg. Dette egner seg godt for monorepoer og er en god måte å dele kode for tjenester i samme domenet.

Det finnes en workspace plugin for cargo, men vi har valgt å ikke bruke den, da den ikke gir oss noen verdi.

For å starte med workspace så må du lage en katalog for monorepoet ditt, det vi her har navngitt my_monorepo.

mkdir my_monorepo
cd my_monorepo

Inne i workspace katalogen så trenger vi en Cargo.toml fil, denne for å fortelle cargo hvilke prosjekter den skal compilere.

echo '[workspace]' > ./Cargo.toml

Vi legger til prosjektene vi skal ha i monorepoet som medlemmer av workspacet.

Vi har her valgt ett gRPC endepunkt, ett GraphQL endepunkt og ett delt repository.

[workspace]
members = [
    "grpc",
    "repository",
    "graphql",
]

Først legger vi til prosjektet gRPC, --bin er default, så vi kan bruke bare

cargo new grpc

Gå så inn i det prosjektet.

cd grpc

Her kan vi legge til avhengigheter fra crates.io med cargo add.

cargo add tonic

Vi kan også legge til workspace members med cargo add og cargo vil da velge workspace members først, hvis det ikke finnes så går den til crates.io. Her kan du lese mer om cargo add

cargo add repository

Vi har valgt å bruke github i stedet for en privat registry service, for å hente inn fra felles repo

cargo add toolshed-config --git https://github.com/amedia/toolshed-rust

Vi får da en Cargo.toml som ser ut som dette:

[package]
name = "grpc"
version = "0.1.0"
edition = "2021"

[dependencies]
repository = { version = "0.1.0", path = "../repository" }
tonic = "0.8.3"
toolshed-config = { git = "https://github.com/amedia/toolshed-rust", version = "0.1.0" }

Lokale avhengigheter/biblioteker og github repos, refereres til i koden på lik linje med tredjepartsbiblioteker.

//Fra samme workspace
use repository::*;
//Fra crates.io
use tonic::*;
//Fra private github repo
use toolshed-rust::*;

Repository er ett delt bibliotek, så her legger vi til --libflagget bak cargo new

cargo new repository --lib
cd repository

Rust har ikke runtime, men noen biblioteker trenger det for blant annet async, vi legger til actix rustls

cargo add sqlx -F runtime-actix-rustls

Vi får da Cargo.tomlfila:

[package]
name = "repository"
version = "0.1.0"
edition = "2021"

[dependencies]
sqlx = { version = "0.6.2", features = ["runtime-actix-rustls"] }

Så legger vi til det tredje prosjektet, som er ett GraphQL endepunkt, hvor vi bruker Juniper og Actix-Web integrasjonen.

cargo new graphql
cd graphql
cargo add repository
cargo add actix-web
cargo add juniper

Vi får da en Cargo.tomlfil som ser noe sånt ut:

[package]
name = "graphql"
version = "0.1.0"
edition = "2021"

[dependencies]
repository = { version = "0.1.0", path = "../repository" }
actix-web = "4.2.1"
juniper = "0.15.10"

Prosjekttreet skal da se noe sånt ut. Legg merke til at Cargo.lockfila er på rotnivå i workspacet.

Plantuml Diagram

Dette blir da sub-domenet my_monorepohvor da repositoryer ett lib inne i de to tjenestene.

Plantuml Diagram

Man kan bygge hele workspacet fra toppnivå med:

cargo build

Applikasjonene kan startes fra toppnivå med:

cargo run -p grpc

Eller kan startes fra det respektive prosjektet med bare

cargo run