Browse documentation
Documentation

Router: Route

Edit this guide on GitHub

Declares an API route handler.

A route always declares its HTTP methods as the first argument:

Use #[route(GET)] without a path string with module routing. The enclosing module determines the URL. A path starting with ./ extends the module path. An absolute path, such as #[route(GET "/api/health")], chooses the URL independently of the module tree and requires separate registration.

module_router! registers module-derived handlers. For explicit paths, pass the function name to RouterBuilder::route or use discover.

Handler signature

The function must be async and return Result<T>, where T implements AsyncIntoResponse. Every IntoResponse type meets this bound. The handler may take cx: &Cx and one body parameter implementing FromRequest. Both are optional and may appear in either order. The body parameter may use a pattern such as Json(input): Json<T>.

Response conversion

The macro converts the success value into a response. See IntoResponse for supported types and tuples. Wrap a value in Json<T> to serialize it as JSON.

Examples

Module-derived path (in src/app/api/health.rs under module_router!(), this serves GET /api/health):

#[route(GET)]
async fn health() -> Result<&'static str> {
    Ok("ok")
}

Explicit method and path, reading a JSON body and answering with one:

use serde::{Deserialize, Serialize};
use hearth::{
    Result,
    router::{content::Json, route},
};

#[derive(Deserialize, Serialize)]
struct CreateUser {
    name: String,
}

#[route(POST "/api/users")]
async fn create_user(Json(input): Json<CreateUser>) -> Result<Json<CreateUser>> {
    Ok(Json(CreateUser { name: input.name }))
}

Path below the module (in src/app/api.rs under module_router!(), this serves GET /api/health without a module for it):

#[route(GET "./health")]
async fn health() -> Result<&'static str> {
    Ok("ok")
}

A method list, and a * route answering every method (say, a webhook endpoint probed with both GET and POST):

mod form {
    use super::*;

    #[route([GET, POST])]
    async fn form() -> Result<&'static str> {
        Ok("form")
    }
}

mod webhook {
    use super::*;

    #[route(*)]
    async fn webhook() -> Result<&'static str> {
        Ok("received")
    }
}