Skip to main content

Tutorial: Minimal Project

In this tutorial, we will create a minimal application with simple hello-world endpoints, a visits counter, a rate-limiting middleware, and the respective tests.

A minimal project is a project that does not use a database. It's a simple web server along with code for reading in configuration settings and a CLI for creating e.g. controllers and other project files.

Create a new minimal project with

gerust my-app --minimal

That creates a basic project structure:

.
├── Cargo.toml
├── README.md
├── cli
│   ├── Cargo.toml
│   ├── README.md
│   ├── blueprints
│   │   └── …
│   └── src
│   ├── bin
│   │   └── generate.rs
│   ├── lib.rs
│   └── util
│   ├── mod.rs
│   └── ui.rs
├── config
│   ├── Cargo.toml
│   ├── README.md
│   ├── app.toml
│   ├── environments
│   │   ├── development.toml
│   │   ├── production.toml
│   │   └── test.toml
│   └── src
│   └── lib.rs
├── macros
│   └── …
└── web
├── Cargo.toml
├── README.md
├── src
│   ├── controllers
│   │   ├── greeting.rs
│   │   └── mod.rs
│   ├── error.rs
│   ├── lib.rs
│   ├── main.rs
│   ├── middlewares
│   │   └── mod.rs
│   ├── routes.rs
│   ├── state.rs
│   └── test_helpers
│   └── mod.rs
└── tests
└── api
├── greeting_test.rs
└── main.rs

The structure contains the cli, config, macros, and web crates. The cli crate contains a binary for creating project files like controllers or middlewares. The config crate contains code for reading configuration values and managing them in a Config struct. The macros crate contains macros that are used for testing. And the web crate contains the system HTTP interface implementation, which essentially is a standard axum application. More on the different crates, their purpose and elements, in the Architecture guide.

Running the Project

Run the generated project with:

cargo run

That starts up the server at 127.0.0.1:3000. To verify everything works as intended, request the demo endpoint that Gerust created by default:

» curl http://localhost:3000/greet
{"hello":"world"}%

The implementation of the endpoint is in web/src/controllers/greeting.rs:

use axum::response::Json;
use serde::{Deserialize, Serialize};

/// A greeting to respond with to the requesting client
#[derive(Deserialize, Serialize)]
pub struct Greeting {
/// Who do we say hello to?
pub hello: String,
}

/// Responds with a [`Greeting`], encoded as JSON.
#[axum::debug_handler]
pub async fn hello() -> Json<Greeting> {
Json(Greeting {
hello: String::from("world"),
})
}

Testing the Project

Run the tests with:

cargo test

Along with the /greet demo endpoint, Gerust also created the corresponding test:

use my_app_web::test_helpers::{BodyExt, RouterExt, TestContext};
use googletest::prelude::*;
use my_app_macros::test;
use my_app_web::controllers::greeting::Greeting;

#[test]
async fn test_hello(context: &TestContext) {
let response = context.app.request("/greet").send().await;

let greeting: Greeting = response.into_body().into_json().await;
assert_that!(greeting.hello, eq(&String::from("world")));
}

The project comes preconfigured with a CI setup for GitHub Actions that covers format checking with rustfmt and clippy for linting besides running the project's own tests.

Building the Project

Build the project with

cargo build

or

cargo build --release

for a release build.

The binary in target/release/my-app-web is your deployment artifact which in the case of a minimal project has no external dependencies since no database or similar is being used.

Documenting the Project

Gerust projects come with complete API documentation out of the box. Generate the documentation with

cargo doc --workspace --all-features

and access it via target/doc/my_app_web/index.html. The API documentation is a great way to explore in more detail all of the elements of the codebase that Gerust generated.


Let's now extend the minimal project step-by-step and explore its various elements along the way.