All skills
lukemurraynz avatar

/rust-patterns

@2cc2455

USE FOR: Rust implementation recipes for new Rust 2024 services, libraries, CLIs, and workspace scaffolds - Cargo setup, error types, async patterns, serde/config, gRPC/Protobuf, HTTP/axum, OpenTelemetry/tracing, testing, quality gates, API design, production readiness, and security/supply-chain checks. Pairs with `rust.instructions.md` and `rust-tests.instructions.md`. Load this skill when Copilot needs working Rust code patterns or configuration guidance.

Use this Skill: https://skilld.dev/gh/lukemurraynz/hve-agent-skills/rust-patterns

This session only. Nothing lands on disk.

recipeshttp-axum.md

≈1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

HTTP Service Patterns with axum

Use this recipe when generating an HTTP API service. Prefer this for general-purpose Rust HTTP APIs when the user has not specified another framework.

Dependencies

Verify current versions before generating. Current known pattern (verified 2026-08-26; TimeoutLayer::with_status_code requires tower-http ≥ 0.6.7 — new(duration) is deprecated):

[dependencies]
axum = "0.8"
tokio = { version = "1", features = ["rt-multi-thread", "macros", "signal", "sync", "time"] }
tower-http = { version = "0.7", features = ["trace", "timeout", "cors", "request-id", "util"] }
tracing = "0.1"
serde = { version = "1", features = ["derive"] }

Do not enable broad feature sets unless the endpoint needs them.

Path Syntax (axum 0.8+)

Path parameters use {id} and wildcards use {*rest}. The older /:id and /*rest syntax panics at router build time (startup failure, not a silent mismatch). Note that Option<T> extractors now require the OptionalFromRequestParts trait — rejections are no longer silently swallowed into None.

Router Shape

use axum::{
    extract::State,
    http::StatusCode,
    response::IntoResponse,
    routing::{get, post},
    Json, Router,
};
use std::{net::SocketAddr, sync::Arc, time::Duration};
use tower_http::{timeout::TimeoutLayer, trace::TraceLayer};

#[derive(Clone)]
pub struct AppState {
    service: Arc<UserService>,
}

pub fn router(state: AppState) -> Router {
    Router::new()
        .route("/healthz", get(health))
        .route("/readyz", get(readiness))
        .route("/users", post(create_user))
        .with_state(state)
        .layer(TraceLayer::new_for_http())
        .layer(TimeoutLayer::with_status_code(
            StatusCode::REQUEST_TIMEOUT,
            Duration::from_secs(30),
        ))
}

async fn health() -> &'static str {
    "ok"
}

async fn readiness(State(_state): State<AppState>) -> Result<&'static str, ApiError> {
    Ok("ready")
}

async fn create_user(
    State(state): State<AppState>,
    Json(request): Json<CreateUserRequest>,
) -> Result<impl IntoResponse, ApiError> {
    let user = state.service.create_user(request).await?;
    Ok((StatusCode::CREATED, Json(user)))
}

pub async fn serve(address: SocketAddr, state: AppState) -> Result<()> {
    let listener = tokio::net::TcpListener::bind(address)
        .await
        .map_err(|error| ServiceError::invalid_input(format!("failed to bind {address}: {error}")))?;

    axum::serve(listener, router(state))
        .with_graceful_shutdown(shutdown_signal())
        .await
        .map_err(|error| ServiceError::invalid_input(format!("HTTP server failed: {error}")))?;

    Ok(())
}

async fn shutdown_signal() {
    if let Err(error) = tokio::signal::ctrl_c().await {
        tracing::warn!(?error, "failed to listen for shutdown signal");
    }
}

Error Response Boundary

#[derive(Debug)]
pub struct ApiError(ServiceError);

impl From<ServiceError> for ApiError {
    fn from(error: ServiceError) -> Self {
        Self(error)
    }
}

impl IntoResponse for ApiError {
    fn into_response(self) -> axum::response::Response {
        let (status, message) = match self.0 {
            ServiceError::NotFound { .. } => (StatusCode::NOT_FOUND, "resource not found"),
            ServiceError::InvalidInput { .. } => (StatusCode::BAD_REQUEST, "invalid request"),
            _ => (StatusCode::INTERNAL_SERVER_ERROR, "internal server error"),
        };

        (status, Json(ErrorBody { message })).into_response()
    }
}

#[derive(serde::Serialize)]
struct ErrorBody {
    message: &'static str,
}

Rules:

  • Map domain errors to HTTP responses at the API boundary.
  • Do not leak internal error details to callers.
  • Add request tracing and timeouts.
  • Keep health checks fast and dependency-light.
  • Keep readiness checks bounded by short timeouts.
  • Put shared state in a typed AppState; avoid global mutable state.
  • Use graceful shutdown for container and orchestrator compatibility.

Source: SKILL.md on GitHub

No alerts8d3 checks · Risk SAFE
  • Gen Agent Trust Hub8d

    The skill provides a comprehensive library of Rust implementation recipes and configuration baselines, emphasizing modern standards (Rust 2024) and security best practices such as secret redaction, dependency hygiene, and structured observability.

  • Socket8d

    No alerts

  • Snyk8d

    Risk: LOW · No issues

Signed by skilld at 2cc2455. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated last month
Other metadata
metadata
{
  "last_verified": "2026-08-26",
  "layer": "scoped",
  "owner": "engineering"
}

README badge

README badge for lukemurraynz/hve-agent-skills/rust-patterns