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.