Rapina 0.6.0 shipped on February 22, 2026. The headline feature was route auto-discovery: handlers annotated with #[get], #[post], #[put], or #[delete] registered themselves at link time via inventory, removing the need to wire routes manually in main.rs. The release also added a Prometheus metrics endpoint and a round of security and CI hardening.
Route auto-discovery
Before 0.6.0, every route had to be registered explicitly:
let router = Router::new()
.get("/users", list_users)
.post("/users", create_user)
.get("/users/:id", get_user);
Rapina::new().router(router).listen("127.0.0.1:3000").awaitWith auto-discovery, calling .discover() was enough. The handler macros emitted an inventory::submit! at link time, and Rapina collected them automatically at startup:
use rapina::prelude::*;
#[get("/users")]
async fn list_users() -> &'static str { "[]" }
#[post("/users")]
async fn create_user() -> StatusCode { StatusCode::CREATED }
#[tokio::main]
async fn main() -> std::io::Result<()> {
Rapina::new()
.discover()
.listen("127.0.0.1:3000")
.await
}Discovery was additive — .router() and .discover() worked together. Routes registered manually co-existed with discovered ones.
Public routes
The #[public] attribute worked in both orderings with discovery enabled. Placing it above or below the route macro both marked the route as accessible without authentication, with no extra configuration:
// Both orderings are equivalent
#[public]
#[get("/health")]
async fn health() -> &'static str { "ok" }
#[get("/ping")]
#[public]
async fn ping() -> &'static str { "pong" }At startup, Rapina logged the number of discovered routes and how many were public.
Prometheus metrics
A /metrics endpoint was added as an optional feature. It was enabled with the metrics feature flag and a single builder call:
[dependencies]
rapina = { version = "0.6.0", features = ["metrics"] }Rapina::new()
.with_metrics(true)
.router(router)
.listen("127.0.0.1:3000")
.awaitThe endpoint returned metrics in Prometheus text format. Three metrics were collected automatically:
| Metric | Type | Labels | Description |
|---|---|---|---|
http_requests_total | Counter | method, path, status | Total completed HTTP requests |
http_request_duration_seconds | Histogram | method, path | Request duration in seconds |
http_requests_in_flight | Gauge | — | Requests currently being processed |
Path normalisation
To prevent label cardinality explosion, pure-numeric path segments were replaced with :id in metric labels:
| Raw request | Label |
|---|---|
/users/42 | /users/:id |
/users/123/posts/456 | /users/:id/posts/:id |
/users/profile | /users/profile |
Requests to /users/1, /users/2, and /users/999 all mapped to the same label set.
Security hardening
The repository received a set of security and supply-chain hardening changes:
SECURITY.md— a security policy was added with a contact address for responsible disclosure.deny.toml—cargo-denywas added with rules for license compliance, duplicate dependencies, and known advisories.audit.yml— a new CI workflow rancargo auditon every push to check for security advisories.scorecard.yml— OpenSSF Scorecard was added to track supply-chain security practices.CODEOWNERS— aCODEOWNERSfile established code review ownership.dependabot.yml— Dependabot was configured for both Cargo and GitHub Actions dependencies.
The CI workflow was also hardened: steps gained pinned permissions, and the release workflow was updated to separate build and publish steps.
Community tooling
Three GitHub Actions workflows were added to improve the contributor experience:
- Auto-labeler — pull requests were automatically labelled by path using
labeler.yml. Changes underdocs/received adocslabel, changes under.github/acilabel, and so on. - Welcome bot — first-time contributors received a welcome comment when their first issue or pull request was opened.
/releasecommand — maintainers could trigger the release workflow with a/releasecomment on a pull request.
Dependency updates
tomlwas bumped to1.0.0+spec-1.1.0, bringing TOML spec 1.1 support. TOML 1.1 adds Unicode escape sequences and allows more characters in bare keys.
Upgrade by bumping the version in your Cargo.toml:
rapina = "0.6.0"