Skip to content

Routing

EdgeZero uses matchit 0.8+ for high-performance path matching with support for parameters and catch-all segments.

Defining Routes

Routes are typically defined in your edgezero.toml manifest and wired automatically via the app! macro:

toml
[[triggers.http]]
id = "hello"
path = "/hello"
methods = ["GET"]
handler = "my_app_core::handlers::hello"

[[triggers.http]]
id = "echo"
path = "/echo/{name}"
methods = ["GET", "POST"]
handler = "my_app_core::handlers::echo"

You can also build routes programmatically using convenience methods:

rust
use edgezero_core::router::RouterService;

let router = RouterService::builder()
    .get("/hello", hello_handler)
    .get("/echo/{name}", echo_handler)
    .post("/echo", echo_json_handler)
    .build();

Or with explicit method specification:

rust
use edgezero_core::router::RouterService;
use edgezero_core::http::Method;

let router = RouterService::builder()
    .route("/hello", Method::GET, hello_handler)
    .route("/echo/{name}", Method::GET, echo_handler)
    .route("/echo", Method::POST, echo_json_handler)
    .build();

Path Parameters

Define parameters with {name} segments:

rust
use edgezero_core::action;
use edgezero_core::extractor::Path;
use edgezero_core::response::Text;

#[action]
async fn greet(Path(name): Path<String>) -> Text<String> {
    Text::new(format!("Hello, {}!", name))
}

For routes like /users/{id}/posts/{post_id}, extract multiple parameters:

rust
#[derive(serde::Deserialize)]
struct PostParams {
    id: u64,
    post_id: u64,
}

#[action]
async fn get_post(Path(params): Path<PostParams>) -> Text<String> {
    Text::new(format!("User {} Post {}", params.id, params.post_id))
}

Catch-All Segments

Use {*rest} for catch-all routes that match any remaining path:

rust
// Route: /files/{*path}
// Matches: /files/docs/readme.md -> path = "docs/readme.md"

#[action]
async fn serve_file(Path(path): Path<String>) -> Text<String> {
    Text::new(format!("Serving: {}", path))
}

HTTP Methods

Specify allowed methods in your route definition:

toml
[[triggers.http]]
path = "/resource"
methods = ["GET", "POST", "PUT", "DELETE"]
handler = "my_app_core::handlers::resource"

Or programmatically:

rust
RouterService::builder()
    .get("/resource", get_resource)
    .post("/resource", create_resource)
    .put("/resource/{id}", update_resource)
    .delete("/resource/{id}", delete_resource)
    .build()

EdgeZero automatically returns 405 Method Not Allowed for requests that match a path but use an unsupported method.

Introspection Routes

EdgeZero provides three bindable handlers in edgezero_core::introspection for debugging and runtime inspection:

  • manifest: Returns the full manifest JSON with secret values redacted.
  • config: Returns the effective app config from the default config store, with secret fields appearing as unresolved key-name references (secret-safe).
  • routes: Returns the registered route table as [{method, path}].

Bind them in your manifest's [[triggers.http]] like any handler. By default, generated apps and app-demo mount them under /_<app-name>/{manifest,config,routes}:

toml
[[triggers.http]]
id = "manifest"
path = "/_my-app/manifest"
methods = ["GET"]
handler = "edgezero_core::introspection::manifest"

[[triggers.http]]
id = "config"
path = "/_my-app/config"
methods = ["GET"]
handler = "edgezero_core::introspection::config"

[[triggers.http]]
id = "routes"
path = "/_my-app/routes"
methods = ["GET"]
handler = "edgezero_core::introspection::routes"

Security

These endpoints are unauthenticated wherever they are bound — restrict access at the network or middleware layer before exposing them publicly. Note that /manifest emits environment.variables[].value verbatim; only environment.secrets values are redacted. Do not store secrets in [environment.variables].

The routes handler returns JSON like:

json
[
  { "method": "GET", "path": "/_my-app/manifest" },
  { "method": "GET", "path": "/_my-app/config" },
  { "method": "GET", "path": "/_my-app/routes" }
]

Path Syntax

EdgeZero uses matchit's path syntax:

PatternExampleMatches
/static/staticExact match only
/{param}/users/{id}Single segment: /users/123
/{*catch}/files/{*path}Rest of path: /files/a/b/c

Legacy Syntax

Axum-style :name parameters are not supported. Use {name} instead.

Route Priority

Routes are matched by specificity (static segments first, then parameters, then catch-alls). If two routes have the same specificity, the first registered wins. Avoid ambiguous patterns that share the same shape (for example, two routes that both look like /users/{id}).

Next Steps

Released under the Apache License 2.0.