### Creating a New Gerust Project (Full Example) Source: https://github.com/mainmatter/gerust/blob/main/README.md Command to create a new Gerust project named 'my-app' including example implementations of various concepts using the '--full' flag, suitable for getting started. ```Shell gerust my-app --full ``` -------------------------------- ### Install Gerust CLI Tool Source: https://github.com/mainmatter/gerust/blob/main/site/docs/index.md Install the Gerust command-line interface tool using the Rust package manager, Cargo. This command fetches the latest version of Gerust from crates.io and compiles/installs it into your Cargo bin directory, making the `gerust` command available in your terminal. ```Shell cargo install gerust ``` -------------------------------- ### Starting Docker Containers via CLI Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/the-entity.md Command to start the Docker containers defined in the `docker-compose.yml` file. This is used here to start the PostgreSQL database server required for migrations. ```Shell docker compose up ``` -------------------------------- ### Installing Dependencies with pnpm - Shell Source: https://github.com/mainmatter/gerust/blob/main/site/README.md Installs project dependencies using the pnpm package manager. This command should be run after cloning the repository to set up the project environment. ```Shell $ pnpm i ``` -------------------------------- ### Running Gerust Project Server (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/index.md This command compiles and runs the main web server binary of the Gerust project using Cargo. It starts the server, typically listening on 127.0.0.1:3000 by default. ```Shell cargo run ``` -------------------------------- ### Testing Working Endpoint with Curl Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/new-endpoint.md Example curl command demonstrating a successful call to the `/greet_me` endpoint after implementation, showing the personalized greeting in the JSON response. ```Shell » curl -H 'Content-Type: application/json' -d '{ "name": "Ferris"} ' -X POST http://127.0.0.1:3000/greet_me {"hello":"Ferris","visit":1}% ``` -------------------------------- ### Testing Note CRUD Endpoints with Curl (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/writing-endpoints.md Provides command-line examples using `curl` to verify the functionality of the `POST`, `GET`, `PUT`, and `DELETE` endpoints for notes. It shows creating a note, retrieving all notes, updating a note, deleting a note, and finally verifying the deletion. ```Shell » curl -X POST 127.0.0.1:3000/notes -H 'Content-Type: application/json' -d '{"text": "do something"}' {"id":"8dd74edb-6187-4588-b976-5529590ea667","text":"do something"}% » curl -i http://127.0.0.1:3000/notes HTTP/1.1 200 OK content-type: application/json content-length: 69 date: Wed, 26 Mar 2025 16:29:04 GMT [{"id":"8dd74edb-6187-4588-b976-5529590ea667","text":"do something"}]% » curl -X PUT 127.0.0.1:3000/notes/8dd74edb-6187-4588-b976-5529590ea667 -H 'Content-Type: application/json' -d '{"text": "do something else"}' {"id":"8dd74edb-6187-4588-b976-5529590ea667","text":"do something else"}% » curl -X DELETE 127.0.0.1:3000/notes/8dd74edb-6187-4588-b976-5529590ea667 » curl -i http://127.0.0.1:3000/notes HTTP/1.1 200 OK content-type: application/json content-length: 2 date: Wed, 26 Mar 2025 16:33:08 GMT []% ``` -------------------------------- ### Starting Local Development Server with pnpm - Shell Source: https://github.com/mainmatter/gerust/blob/main/site/README.md Starts a local development server for the Docusaurus website using pnpm. This command typically watches for file changes and automatically reloads the browser. ```Shell $ pnpm start ``` -------------------------------- ### Testing Gerust Default Endpoint (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/index.md This command uses the 'curl' utility to send an HTTP GET request to the default '/greet' endpoint provided by the generated project. It verifies that the server is running and responds with the expected JSON output. ```Shell curl http://localhost:3000/greet {"hello":"world"}% ``` -------------------------------- ### Executing Database Transaction with sqlx (Rust) Source: https://github.com/mainmatter/gerust/blob/main/blueprint/db/README.md Shows how to start a transaction using `transaction(&app_state.db_pool)`, perform database operations within it (e.g., `create_user`), and then commit the transaction. This ensures multiple operations are treated as a single atomic unit. Handles potential errors during transaction start. ```Rust let user_changeset: UserChangeset = Faker.fake(); match transaction(&app_state.db_pool).await { Ok(mut tx) => { create_user(user_changeset.clone(), &mut *tx) .await .unwrap(); tx.commit()?; } Err(e) => Err(anyhow!("Could not start transaction!")), } ``` -------------------------------- ### Installing Gerust CLI Source: https://github.com/mainmatter/gerust/blob/main/README.md Command to install the Gerust project generator command-line tool using Cargo, Rust's package manager. ```Shell cargo install gerust ``` -------------------------------- ### Calling New Endpoint with Curl Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/new-endpoint.md Example curl command to test the new `/greet_me` endpoint, sending a JSON payload with the user's name. ```Shell curl -H 'Content-Type: application/json' \ -d '{ "name": "Ferris"} ' \ -X POST \ http://127.0.0.1:3000/greet_me ``` -------------------------------- ### Generating CRUD Controller with Gerust Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/reading-endpoints.md Use the `cargo generate` command provided by Gerust to quickly create a new controller file (`web/src/controllers/notes.rs`) pre-populated with example implementations for standard CRUD operations. ```Shell cargo generate crud-controller notes ``` -------------------------------- ### Example JSON Object Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/auth-middleware.md A simple JSON object containing a unique identifier ('id') and a descriptive text field ('text'). This structure is commonly used for transferring basic data. ```JSON {"id":"ddb15cf7-587b-4221-aca8-7f889673d1fe","text":"do something"} ``` -------------------------------- ### Initializing AppState with Default in Rust Tests Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/application-state.md Updates the test helper function `setup` to initialize the `AppState` using `Default::default()`. This replaces the previous attempt to use struct literal syntax, which failed due to private fields, and correctly provides a default `AppState` instance for the test router. ```Rust // web/src/test-helpers/mod.rs use crate::routes::init_routes; use crate::state::AppState; use axum::{ body::{Body, Bytes}, http::{Method, Request}, response::Response, Router, }; // diff-add +use std::default::Default; … pub async fn setup() -> TestContext { let init_config: OnceCell = OnceCell::new(); let _config = init_config.get_or_init(|| load_config(&Environment::Test).unwrap()); // diff-add + let app_state: AppState = Default::default(); // diff-add + let app = init_routes(app_state); // diff-remove - let app = init_routes(AppState {}); TestContext { app } } ``` -------------------------------- ### Routing Read Endpoints in Rust Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/reading-endpoints.md Configure the application's routes in `web/src/routes.rs` using Axum's `Router`. This involves importing the notes controller functions and mapping the GET requests for "/notes" to `notes::read_all` and "/notes/{id}" to `notes::read_one`, attaching the shared application state to the router. ```Rust // diff-add +use crate::controllers::notes; use crate::state::AppState; // diff-remove -use axum::Router; // diff-add +use axum::{routing::get, Router}; use std::sync::Arc; /// Initializes the application's routes. /// /// This function maps paths (e.g. "/greet") and HTTP methods (e.g. "GET") to functions in [`crate::controllers`] as well as includes middlewares defined in [`crate::middlewares`] into the routing layer (see [`axum::Router`]). pub fn init_routes(app_state: AppState) -> Router { let shared_app_state = Arc::new(app_state); // diff-remove - Router::new().with_state(shared_app_state) // diff-add + Router::new() // diff-add + .route("/notes", get(notes::read_all)) // diff-add + .route("/notes/{id}", get(notes::read_one)) // diff-add + .with_state(shared_app_state) } ``` -------------------------------- ### Testing Read All Endpoint with Curl Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/reading-endpoints.md Use the `curl` command-line tool to send a GET request to the newly configured "/notes" endpoint. This verifies that the endpoint is accessible and returns the expected response, which is an empty JSON array `[]` if no notes are currently in the database. ```Shell » curl -i http://127.0.0.1:3000/notes HTTP/1.1 200 OK content-type: application/json content-length: 2 date: Wed, 22 Jan 2025 14:01:54 GMT []% ``` -------------------------------- ### Testing Axum Application with Database Isolation using #[db_test] (Rust) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/architecture/the-web-crate.md Demonstrates how to write application tests for the Gerust web crate using the `#[db_test]` macro. This macro provides a `DbTestContext` with access to the axum application (`app`) and a connection pool (`db_pool`) configured for a test-specific, isolated database. The example shows creating data in the test database and then making a request to the application to verify the data, ensuring tests are independent and can run in parallel. ```Rust pub struct DbTestContext { /// The axum application that is being tested. pub app: Router, /// A connection pool connected to the test-specific database; the app is set up to use this database automatically pub db_pool: DbPool, } #[db_test] async fn test_read_all(context: &DbTestContext) { let task_changeset: TaskChangeset = Faker.fake(); create_task(task_changeset.clone(), &context.db_pool) // create a task in the database .await .unwrap(); let response = context .app .request("/tasks") .method(Method::GET) .send() .await; // load all tasks assert_that!(response.status(), eq(StatusCode::OK)); let tasks: TasksList = response.into_body().into_json::().await; assert_that!(tasks, len(eq(1))); assert_that!( // assert the task created above is returned (as the application uses the same database) tasks.first().unwrap().description, eq(task_changeset.description) ); } ``` -------------------------------- ### Testing Backend Endpoint with Database Access (Rust) Source: https://github.com/mainmatter/gerust/blob/main/README.md Demonstrates a typical application test using the `#[db_test]` macro in Gerust. The test receives a `DbTestContext` providing access to the application router and a database pool connected to a test-specific database. It shows how to seed the database using a utility function (`create_task`), make an HTTP GET request to an endpoint (`/tasks`), and assert the response status and body content, verifying that the application interacts correctly with the isolated test database. ```Rust pub struct DbTestContext { /// The axum application that is being tested. pub app: Router, /// A connection pool connected to the test-specific database; the app is set up to use this database automatically pub db_pool: DbPool, } #[db_test] async fn test_read_all(context: &DbTestContext) { let task_changeset: TaskChangeset = Faker.fake(); create_task(task_changeset.clone(), &context.db_pool) // create a task in the database .await .unwrap(); let response = context .app .request("/tasks") .method(Method::GET) .send() .await; // load all tasks assert_that!(response.status(), eq(StatusCode::OK)); let tasks: TasksList = response.into_body().into_json::().await; assert_that!(tasks, len(eq(1))); assert_that!( // assert the task created above is returned (as the application uses the same database) tasks.first().unwrap().description, eq(task_changeset.description) ); } ``` -------------------------------- ### Testing Notes API Read All Success in Rust Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/reading-endpoints.md Tests the GET /notes endpoint to ensure it returns a 200 OK status code and retrieves all notes from the database. It verifies that a previously created note is returned and its text property matches the original changeset. Requires a `DbTestContext`. ```Rust #[db_test] async fn test_read_all(context: &DbTestContext) { let changeset: entities::notes::NoteChangeset = Faker.fake(); entities::notes::create(changeset.clone(), &context.db_pool) .await .unwrap(); let response = context .app .request("/notes") .send() .await; assert_that!(response.status(), eq(StatusCode::OK)); let notes: Vec = response.into_body().into_json::>().await; assert_that!(notes, len(eq(1))); assert_that!( notes.first().unwrap().text, eq(&changeset.text) ); } ``` -------------------------------- ### Testing Notes API Read One Nonexistent in Rust Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/reading-endpoints.md Tests the GET /notes/{id} endpoint with a non-existent UUID to ensure it returns a 404 Not Found status code. Requires a `DbTestContext`. ```Rust #[db_test] async fn test_read_one_nonexistent(context: &DbTestContext) { let response = context .app .request(&format!("/notes/{}", Uuid::new_v4())) .body(Body::from(payload.to_string())) .send() .await; assert_that!(response.status(), eq(StatusCode::NOT_FOUND)); } ``` -------------------------------- ### Testing Notes API Read One Success in Rust Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/reading-endpoints.md Tests the GET /notes/{id} endpoint with a valid, existing note ID to ensure it returns a 200 OK status code and retrieves the correct note. It verifies the returned note's ID and text property match the created note. Requires a `DbTestContext`. ```Rust #[db_test] async fn test_read_one_success(context: &DbTestContext) { let note_changeset: entities::notes::NoteChangeset = Faker.fake(); let note = entities::notes::create(note_changeset.clone(), &context.db_pool) .await .unwrap(); let note_id = note.id; let response = context .app .request(&format!("/notes/{}", note_id)) .send() .await; assert_that!(response.status(), eq(StatusCode::OK)); let note: entities::notes::Note = response.into_body().into_json::().await; assert_that!(note.id, eq(note_id)); assert_that!(note.text, eq(¬e_changeset.text)); } ``` -------------------------------- ### Create New Gerust Project (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/index.md Initializes a new project directory with the specified name using the Gerust CLI tool. This command sets up the basic project structure including various crates for different functionalities. ```Shell gerust my-app ``` -------------------------------- ### Creating Gerust Minimal Project (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/index.md This command uses the Gerust CLI tool to create a new project directory named 'my-app'. The '--minimal' flag specifies that the project should be set up without database dependencies. ```Shell gerust my-app --minimal ``` -------------------------------- ### Generating Gerust Project Documentation (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/index.md This command generates API documentation for all crates in the workspace using `rustdoc`. The `--all-features` flag ensures documentation is generated for all features. The output is accessible via `target/doc/my_app_web/index.html`. ```Shell cargo doc --workspace --all-features ``` -------------------------------- ### Testing Gerust Greeting Endpoint (Rust) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/index.md This Rust code provides an integration test for the '/greet' endpoint. It uses custom test helpers (`TestContext`, `RouterExt`, `BodyExt`) to send a request to the running application and assert the content of the JSON response using `googletest`. ```Rust 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"))); } ``` -------------------------------- ### Displaying Gerust DB CLI Help (Shell) Source: https://github.com/mainmatter/gerust/blob/main/README.md Shows the available commands and options for the `db` binary, which is used for managing the project's database, including operations like migration, creation, seeding, and preparing query metadata. ```Shell » cargo db A CLI tool to manage the project's database. Usage: db [OPTIONS] Commands: drop Drop the database create Create the database migrate Migrate the database reset Reset (drop, create, migrate) the database seed Seed the database prepare Generate query metadata to support offline compile-time verification help Print this message or the help of the given subcommand(s) Options: -e, --env Choose the environment (development, test, production). [default: development] --no-color Disable colored output. --debug Enable debug output. -h, --help Print help -V, --version Print version ``` -------------------------------- ### Building Gerust Project Release (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/index.md This command compiles the Gerust project and its dependencies in release mode with optimizations enabled. The resulting executable, suitable for deployment, is placed in the `target/release` directory. ```Shell cargo build --release ``` -------------------------------- ### Implementing Gerust Greeting Controller (Rust) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/index.md This Rust code defines the handler for the '/greet' endpoint. It uses `axum` for routing, `serde` for JSON serialization/deserialization, and defines a `Greeting` struct to represent the response payload. ```Rust 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 { Json(Greeting { hello: String::from("world"), }) } ``` -------------------------------- ### Building Gerust Project (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/index.md This command compiles the Gerust project and its dependencies in debug mode. The resulting executable is placed in the `target/debug` directory. ```Shell cargo build ``` -------------------------------- ### Running Cargo Tests and Viewing Output Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/writing-endpoints.md This snippet shows the command used to run the tests (`cargo test`) and the resulting output, indicating that all 10 tests, including the re-enabled create, update, and delete tests, passed successfully. ```Shell » cargo test Compiling my-app-web v0.0.1 (/Users/marcoow/Code/gerust/my-app/web) … running 10 tests test notes_test::test_create_invalid ... ok test notes_test::test_create_success ... ok test notes_test::test_delete_nonexistent ... ok test notes_test::test_delete_success ... ok test notes_test::test_update_invalid ... ok test notes_test::test_update_nonexistent ... ok test notes_test::test_update_success ... ok test notes_test::test_read_one_nonexistent ... ok test notes_test::test_read_all ... ok test notes_test::test_read_one_success ... ok test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.22s ``` -------------------------------- ### Displaying Gerust Generate CLI Help (Shell) Source: https://github.com/mainmatter/gerust/blob/main/README.md Shows the available commands and options for the `generate` binary, which is used for generating various project files such as middlewares, controllers, tests, migrations, and entities. ```Shell » cargo generate A CLI tool to generate project files. Usage: generate [OPTIONS] Commands: middleware Generate a middleware controller Generate a controller controller-test Generate a test for a controller migration Generate a migration entity Generate an entity entity-test-helper Generate an entity test helper crud-controller Generate an example CRUD controller crud-controller-test Generate a test for a CRUD controller help Print this message or the help of the given subcommand(s) Options: --no-color Disable colored output. --debug Enable debug output. -h, --help Print help -V, --version Print version ``` -------------------------------- ### Deriving Default for AppState in Rust Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/application-state.md Modifies the `AppState` struct definition to derive the `std::default::Default` trait. This allows the struct to be easily initialized with default values, resolving an error in test setup where private fields could not be directly set. ```Rust // web/src/state.rs use my_app_config::Config; // diff-add +use std::default::Default; … // diff-add +#[derive(Default)] pub struct AppState { counter: AtomicUsize, } ``` -------------------------------- ### Running Gerust Project Tests (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/index.md This command executes all tests defined within the Gerust project's workspace using Cargo. It includes unit tests, integration tests, and any other tests configured in the Cargo.toml files. ```Shell cargo test ``` -------------------------------- ### Run Application (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/the-entity.md Command to compile and run the Rust application using cargo, confirming the database interface functions are working and leveraging sqlx's compile-time query checking. ```Shell » cargo run ``` -------------------------------- ### Migrate Test Database - Shell Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/reading-endpoints.md Command line instruction to run database migrations specifically for the test database environment, as configured in `.env.test`. This is a prerequisite for running tests that interact with the database. ```Shell cargo db migrate -e test ``` -------------------------------- ### Displaying Database CLI Help (Rust) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/architecture/the-cli-crate.md Shows the available commands and options for the `db` binary, used for managing the project's database, including dropping, creating, migrating, resetting, seeding, and preparing the database. ```Rust CLI Output A CLI tool to manage the project's database. Usage: db [OPTIONS] Commands: drop Drop the database create Create the database migrate Migrate the database reset Reset (drop, create, migrate) the database seed Seed the database prepare Generate query metadata to support offline compile-time verification help Print this message or the help of the given subcommand(s) Options: -e, --env Choose the environment (development, test, production). [default: development] --no-color Disable colored output. --debug Enable debug output. -h, --help Print help -V, --version Print version ``` -------------------------------- ### Creating a New Gerust Project (Empty) Source: https://github.com/mainmatter/gerust/blob/main/README.md Command to create a new Gerust project named 'my-app' with the default empty structure, providing the basic directory layout. ```Shell gerust my-app ``` -------------------------------- ### Displaying Generate CLI Help (Rust) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/architecture/the-cli-crate.md Shows the available commands and options for the `generate` binary, used for creating new project files like middleware, controllers, migrations, and entities. ```Rust CLI Output A CLI tool to generate project files. Usage: generate [OPTIONS] Commands: middleware Generate a middleware controller Generate a controller controller-test Generate a test for a controller migration Generate a migration entity Generate an entity entity-test-helper Generate an entity test helper crud-controller Generate an example CRUD controller crud-controller-test Generate a test for a CRUD controller help Print this message or the help of the given subcommand(s) Options: --no-color Disable colored output. --debug Enable debug output. -h, --help Print help -V, --version Print version ``` -------------------------------- ### Run Tests - Shell Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/reading-endpoints.md Command line instruction to execute the test suite. This command will run all tests, including those using the `#[db_test]` macro after the test database has been migrated. ```Shell cargo test ``` -------------------------------- ### Create Fake Data and Entity - Rust Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/reading-endpoints.md Demonstrates how to generate fake data for a `NoteChangeset` using `Faker` and then use it to create a new note entity in the database via `entities::notes::create`. This pattern is used to set up test data. ```Rust let changeset: entities::notes::NoteChangeset = Faker.fake(); entities::notes::create(changeset.clone(), &context.db_pool) .await .unwrap(); ``` -------------------------------- ### Applying Database Migrations (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/auth-middleware.md Executes the `cargo db migrate` command to run any new or pending SQL migration files found in the migrations directory against the configured database, applying schema changes like creating the `users` table. ```Shell » cargo db migrate ``` -------------------------------- ### Applying Database Migrations via CLI Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/the-entity.md Command to apply pending database migrations using the Gerust CLI. It reads the database URL from the `.env` file and runs any migration files that haven't been applied yet. ```Shell cargo db migrate ``` -------------------------------- ### Generating Full Sandbox App (Shell) Source: https://github.com/mainmatter/gerust/blob/main/README.md Command to generate a new project directory named `my-app` with the full set of features enabled, used for manual testing of changes made to the Gerust framework itself. ```Shell cargo run -- --full my-app ``` -------------------------------- ### Making HTTP Requests to Axum Router in Tests using Test Helpers (Rust) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/architecture/the-web-crate.md Illustrates the usage of test helper extensions provided by the `test-helpers` feature in the `web` crate. These helpers simplify making HTTP requests directly against the axum `Router` instance within application tests, allowing concise specification of the path, method, and sending the request. ```Rust let response = context .app .request("/tasks") .method(Method::GET) .send() .await; ``` -------------------------------- ### Generating Axum Middleware with Gerust CLI (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/middleware.md Uses the Gerust command-line interface to generate the initial file structure and boilerplate code for a new middleware named 'rate-limiter' in the 'web/src/middlewares' directory. ```Shell » cargo generate middleware rate-limiter ``` -------------------------------- ### Generating User Migration File (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/auth-middleware.md Uses the `cargo generate` command to create a new, timestamped SQL migration file in the database migrations directory. This file will contain the SQL statements needed to create the `users` table. ```Shell » cargo generate migration create-users ``` -------------------------------- ### Validating Changeset and Creating User (Rust) Source: https://github.com/mainmatter/gerust/blob/main/blueprint/db/README.md Defines `UserChangeset` for validating user input before creation or update, using the `validate` crate. Includes the `create` function which validates the changeset and then inserts a new user record into the database using `sqlx::query!`, returning the newly created `User`. ```Rust #[derive(Deserialize, Validate, Clone)] pub struct UserChangeset { #[validate(length(min = 1))] pub name: String, } pub async fn create( user: UserChangeset, executor: impl sqlx::Executor<'_, Database = Postgres>, ) -> Result { user.validate()?; let record = sqlx::query!( "INSERT INTO users (name) VALUES ($1) RETURNING id", user.name ) .fetch_one(executor) .await .map_err(|e| crate::Error::DbError(e.into()))?; Ok(User { id: record.id, description: user.name, }) } ``` -------------------------------- ### Defining Rust User Entity Test Helper Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/auth-middleware.md Rust code defining the `UserChangeset` struct for generating fake user data and an asynchronous `create` function that inserts a new user record into the database using `sqlx`, returning the created `User` entity. This code is intended for use only in tests. ```Rust use crate::entities::users::User; use fake::{faker::name::en::*, Dummy}; use sqlx::postgres::PgPool; #[derive(Debug, Clone, Dummy)] pub struct UserChangeset { #[dummy(faker = "Name()")] pub name: String, // The user's auth token, fake data will be a 100 characters long number #[dummy(faker = "100..101")] pub token: String, } pub async fn create(user: UserChangeset, db: &PgPool) -> Result { let record = sqlx::query!( "INSERT INTO users (name, token) VALUES ($1, $2) RETURNING id", user.name, user.token ) .fetch_one(db) .await?; Ok(User { id: record.id, name: user.name }) } ``` -------------------------------- ### Generating User Entity Test Helper with Cargo Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/auth-middleware.md Command line instruction using `cargo generate` to create a new test helper module specifically for the `User` entity within the database crate (`db`). This helper will contain test-specific code for user management. ```Shell » cargo generate entity-test-helper user ``` -------------------------------- ### Opening Sandbox App in Editor (Shell) Source: https://github.com/mainmatter/gerust/blob/main/README.md Command to open the generated sandbox application directory (`my-app`) using the default system editor specified by the `${EDITOR}` environment variable. ```Shell ${EDITOR} my-app ``` -------------------------------- ### Defining Application State in Rust Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/reading-endpoints.md Define the `AppState` struct to hold shared application resources like the database connection pool (`DbPool`). The `init_app_state` function is responsible for creating and initializing this state based on the application configuration, making the database pool available to handlers via Axum's `State` extractor. ```Rust use my_app_config::Config; use my_app_db::{connect_pool, DbPool}; use std::sync::Arc; /// The application's state that is available in [`crate::controllers`] and [`crate::middlewares`]. pub struct AppState { /// The database pool that's used to get a connection to the application's database (see [`my_app_db::DbPool`]). pub db_pool: DbPool, } /// The application's state as it is shared across the application, e.g. in controllers and middlewares. /// /// This is the [`AppState`] struct wrappend in an [`std::sync::Arc`]. pub type SharedAppState = Arc; /// Initializes the application state. /// /// This function creates an [`AppState`] based on the current [`my_app_config::Config`]. pub async fn init_app_state(config: Config) -> AppState { let db_pool = connect_pool(config.database) .await .expect("Could not connect to database!"); AppState { db_pool } } ``` -------------------------------- ### Generating Gerust Migration via CLI Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/the-entity.md Command to generate a new Gerust database migration file named `create_notes`. This creates an empty SQL file in the migrations directory, prefixed with a timestamp. ```Shell cargo generate migration create_notes ``` -------------------------------- ### Generating User Entity Blueprint (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/auth-middleware.md Uses the `cargo generate` command to create the initial file structure and basic code for a new entity named `user` with a string field named `name`. This command generates a blueprint that will be customized. ```Shell » cargo generate entity user name:string ``` -------------------------------- ### Defining Users Table Schema (SQL) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/auth-middleware.md Provides the SQL `CREATE TABLE` statement to define the structure of the `users` table in the database. It specifies the columns, data types, constraints, and sets a default value for the `id`. ```SQL CREATE TABLE users ( id uuid PRIMARY KEY default gen_random_uuid(), name varchar(255) NOT NULL, token varchar(100) NOT NULL ); ``` -------------------------------- ### Testing Notes API Create Success in Rust Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/reading-endpoints.md Tests the POST /notes endpoint with a valid payload generated by `fake` to ensure a 201 Created status code is returned and that the note is successfully created in the database with the correct text property. Requires a `DbTestContext`. ```Rust #[ignore = "not yet implemented"] #[db_test] async fn test_create_success(context: &DbTestContext) { let changeset: entities::notes::NoteChangeset = Faker.fake(); let payload = json!(changeset); let response = context .app .request("/notes") .method(Method::POST) .body(Body::from(payload.to_string())) .header(http::header::CONTENT_TYPE, "application/json") .send() .await; assert_that!(response.status(), eq(StatusCode::CREATED)); let notes = entities::notes::load_all(&context.db_pool).await.unwrap(); assert_that!(notes, len(eq(1))); assert_that!(notes.first().unwrap().text, eq(&changeset.text)); } ``` -------------------------------- ### Implementing Initial Axum Controller Function (Rust) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/new-endpoint.md Adds the basic `hello_person` async function using `axum`'s `State` extractor to access application state and return a `Greeting` struct as JSON. This version uses a placeholder name. ```Rust ... // diff-add +#[axum::debug_handler] // diff-add +pub async fn hello_person(State(app_state): State) -> Json { // diff-add + app_state.count_visit(); // diff-add + Json(Greeting { // diff-add + hello: String::from(""), // diff-add + visit: app_state.get_visit_count(), // diff-add + }) // diff-add +} ... ``` -------------------------------- ### Adding New Endpoint to Axum Router (Rust) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/new-endpoint.md Updates the `init_routes` function to register the `/greet_me` path with the `POST` HTTP method, routing requests to the `greeting::hello_person` controller function using `axum`'s `Router`. ```Rust use crate::controllers::greeting; use crate::state::AppState; // diff-add +use axum::{routing::{get, post}, Router}; // diff-remove -use axum::{routing::get, Router}; use std::sync::Arc; /// Initializes the application's routes. /// /// This function maps paths (e.g. "/greet") and HTTP methods (e.g. "GET") to functions in [`crate::controllers`] as well as includes middlewares defined in [`crate::middlewares`] into the routing layer (see [`axum::Router`]). pub fn init_routes(app_state: AppState) -> Router { let shared_app_state = Arc::new(app_state); Router::new() .route("/greet", get(greeting::hello)) // diff-add + .route("/greet_me", post(greeting::hello_person)) .with_state(shared_app_state) } ``` -------------------------------- ### Generated Axum Rate Limiter Middleware Placeholder (Rust) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/middleware.md The initial Rust code generated for the rate limiter middleware. It includes necessary Axum imports and the function signature but contains a 'todo!' macro, indicating where the actual rate limiting logic needs to be implemented. ```Rust use crate::state::SharedAppState; use axum::body::Body; use axum::{ extract::{Request, State}, http::StatusCode, middleware::Next, response::Response, }; #[tracing::instrument(skip_all, fields(rejection_reason = tracing::field::Empty))] pub async fn rate_limiter( State(app_state): State, mut req: Request, next: Next, ) -> Result { todo!("Implement this (return `next.run(req).await` to continue processing the request or Err(StatusCode) to error out).") } ``` -------------------------------- ### Make HTTP Request in Test - Rust Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/reading-endpoints.md Shows how to make an HTTP request to the application instance (`context.app`) within a `#[db_test]`. It constructs a request with a path, method, body, and headers, then sends it and awaits the response. ```Rust let response = context .app .request(&format!("/notes/{}", note_id)) .send() .await; ``` -------------------------------- ### Initial Axum Authentication Middleware Scaffolding (Rust) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/auth-middleware.md This Rust function `auth` serves as the initial template for an Axum middleware. It takes the application state, the request, and the `Next` middleware handler as input and is expected to return a `Result` indicating success (`Response`) or failure (`StatusCode`). It currently contains a `todo!` placeholder. ```Rust use crate::state::SharedAppState; use axum::body::Body; use axum::{ extract::State, http::{self, Request, StatusCode}, middleware::Next, response::Response, }; #[tracing::instrument(skip_all, fields(rejection_reason = tracing::field::Empty))] pub async fn auth( State(app_state): State, mut req: Request, next: Next, ) -> Result { todo!("Implement this (return `next.run(req).await` to continue processing the request or Err(StatusCode) to error out).") } ``` -------------------------------- ### Migrate Test Database using Cargo Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/auth-middleware.md Executes the database migration command for the test environment using `cargo db migrate`. This command applies pending database schema changes to the test database, ensuring it is up-to-date for running tests. ```Shell cargo db migrate -e test ``` -------------------------------- ### Implementing Read Endpoints in Rust Controller Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/reading-endpoints.md Implement the `read_all` and `read_one` functions in the notes controller. These functions use Axum's `State` and `Path` extractors to access the application state (for the database pool) and URL parameters (for the note ID), calling data access functions from the `my_app_db` crate and returning the results as JSON. ```Rust use crate::{error::Error, state::SharedAppState}; use axum::{extract::Path, extract::State, http::StatusCode, Json}; use my_app_db::entities; use tracing::info; use uuid::Uuid; … #[axum::debug_handler] pub async fn read_all( State(app_state): State, ) -> Result>, Error> { let notes = entities::notes::load_all(&app_state.db_pool) .await?; info!("responding with {:?}", notes); Ok(Json(notes)) } #[axum::debug_handler] pub async fn read_one( State(app_state): State, Path(id): Path, ) -> Result, Error> { let note = entities::notes::load(id, &app_state.db_pool).await?; Ok(Json(note)) } … ``` -------------------------------- ### Loading User Record with sqlx (Rust) Source: https://github.com/mainmatter/gerust/blob/main/blueprint/db/README.md Asynchronously loads a `User` record from the database based on its ID. It uses `sqlx::query_as!` for compile-time checked queries and requires an `sqlx::Executor` (pool or transaction). Returns a `Result` containing the `User` or a custom error if not found or a database issue occurs. ```Rust pub async fn load( id: Uuid, executor: impl sqlx::Executor<'_, Database = Postgres>, ) -> Result { match sqlx::query_as!(Task, "SELECT id, name FROM users WHERE id = $1", id) .fetch_optional(executor) .await .map_err(|e| crate::Error::DbError(e.into()))? { Some(user) => Ok(user), None => Err(crate::Error::NoRecordFound), } } ``` -------------------------------- ### Adding Integration Test for Personal Greeting Endpoint (Rust) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/new-endpoint.md Adds a new integration test case using `googletest` and custom test helpers. It constructs a `POST` request with a JSON body, sends it to `/greet_me`, and asserts that the returned `Greeting` struct contains the correct personalized name. ```Rust // diff-add +use axum::{ // diff-add + body::Body, // diff-add + http::{self, Method}, // diff-add +}; use googletest::prelude::*; use my_app_macros::test; // diff-add +use my_app_web::controllers::greeting::{Greeting, PersonalData}; // diff-remove -use my_app_web::controllers::greeting::Greeting; use my_app_web::test_helpers::{BodyExt, RouterExt, TestContext}; // diff-add +use serde_json::json; ... // diff-add +#[test] // diff-add +async fn test_personal_greeting(context: &TestContext) { // diff-add + let payload = json!(PersonalData { // diff-add + name: String::from("Ferris"), // diff-add + }); // diff-add + let response = context // diff-add + .app // diff-add + .request("/greet_me") // diff-add + .method(Method::POST) // diff-add + .body(Body::from(payload.to_string())) // diff-add + .header(http::header::CONTENT_TYPE, "application/json") // diff-add + .send() // diff-add + .await; // diff-add + // diff-add + let greeting: Greeting = response.into_body().into_json().await; // diff-add + assert_that!(greeting.hello, eq(&String::from("Ferris"))); // diff-add +} ``` -------------------------------- ### Inserting Test User into PostgreSQL Database (SQL) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/auth-middleware.md This `psql` command connects to the PostgreSQL database `my_app` using the specified connection string and executes an SQL `INSERT` statement. It adds a new row to the `users` table with a name 'admin' and a specific token value, which will be used to authenticate requests in subsequent tests. ```SQL psql -Atx "postgresql://my_app:my_app@localhost:5432/my_app" -c "INSERT INTO users (name, token) VALUES ('admin', '2c1b1ca9b5cf201368cc68f81ab75a5155091edf5aac5a2ada5633d617363c9dd363a0f2b10633d3cca5958fb2053e16c922')" ``` -------------------------------- ### Applying Rate Limiter Middleware to Routes (Rust) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-minimal/middleware.md Configures the Axum router to apply the implemented `rate_limiter` middleware to the `/greet` and `/greet_me` routes. It uses `route_layer` and `middleware::from_fn_with_state` to attach the middleware with access to the shared application state. ```Rust use crate::controllers::greeting; // diff-add +use crate::middlewares::rate_limiter::rate_limiter; … Router::new() .route("/greet", get(greeting::hello)) .route("/greet_me", post(greeting::hello_person)) // diff-add +.route_layer(middleware::from_fn_with_state( // diff-add + shared_app_state.clone(), // diff-add + rate_limiter, // diff-add +)) .with_state(shared_app_state) … ``` -------------------------------- ### Testing Authorized Access to Authenticated Endpoint (Shell) Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/auth-middleware.md This `curl` command sends a POST request to the `/notes` endpoint, including the `Authorization` header with the token previously inserted into the database. This test verifies that the authentication middleware correctly identifies the user and allows the request to proceed, expecting a 201 Created response. ```Shell curl -i -X POST 127.0.0.1:3000/notes -H 'Authorization: 2c1b1ca9b5cf201368cc68f81ab75a5155091edf5aac5a2ada5633d617363c9dd363a0f2b10633d3cca5958fb2053e16c922' -H 'Content-Type: application/json' -d '{"text": "do something"}' ``` -------------------------------- ### Defining Application Configuration Structure in Rust Source: https://github.com/mainmatter/gerust/blob/main/README.md This Rust snippet defines the main `Config` struct, which serves as a container for application configuration settings. It includes fields for server and database configurations and is designed to be extended for project-specific settings, with values loaded from configuration files and environment variables. ```Rust #[derive(Deserialize, Clone, Debug)] pub struct Config { pub server: ServerConfig, pub database: DatabaseConfig, // The database configuration only exists for projects that use a database // add your config settings here… } ``` -------------------------------- ### Generating Axum Middleware with Cargo Source: https://github.com/mainmatter/gerust/blob/main/site/docs/tutorial-standard/auth-middleware.md This command uses `cargo generate` to create a new middleware module named `auth` within the `web/src/middlewares` directory, providing a basic code structure for implementation. ```Shell cargo generate middleware auth ```