Agent skill
utoipa-axum
OpenAPI documentation skill for Rust APIs using utoipa with Axum framework. Use when building REST APIs with automatic OpenAPI spec generation and Scalar UI. Covers: (1) ToSchema derive for request/response types, (2) #[utoipa::path] for endpoint documentation, (3) OpenApi derive for combining specs, (4) Security schemes (JWT, API keys), (5) IntoParams for query/path params, (6) Scalar UI integration, (7) Response and error handling patterns. Triggers: utoipa, openapi, scalar, axum api, ToSchema, IntoParams, rust api docs.
Install this agent skill to your Project
npx add-skill https://github.com/suryavirkapur/skills/tree/main/skills/utoipa-axum
SKILL.md
OpenAPI with utoipa + Axum
utoipa provides compile-time OpenAPI documentation for Rust REST APIs. Code-first approach: annotate handlers and types, get OpenAPI 3.1 spec automatically.
Core Concepts
- ToSchema — Derive for request/response body types
- #[utoipa::path] — Annotate handlers with path, method, params, responses
- OpenApi — Combine all paths and schemas into spec
- Scalar — Serve interactive API documentation
Cargo.toml Setup
[dependencies]
axum = "0.8"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
uuid = { version = "1", features = ["serde", "v4"] }
chrono = { version = "0.4", features = ["serde"] }
# utoipa with axum integration
utoipa = { version = "5", features = ["axum_extras", "uuid", "chrono"] }
utoipa-scalar = { version = "0.3", features = ["axum"] }
ToSchema — Request/Response Types
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use uuid::Uuid;
#[derive(Debug, Deserialize, ToSchema)]
pub struct CreateUserRequest {
/// User's email address
pub email: String,
/// Password (min 8 characters)
#[schema(min_length = 8)]
pub password: String,
}
#[derive(Debug, Serialize, ToSchema)]
pub struct UserResponse {
pub id: Uuid,
pub email: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
}
#[derive(Debug, Serialize, ToSchema)]
pub struct ErrorResponse {
pub error: String,
}
#[utoipa::path] — Documenting Handlers
use axum::{extract::{Path, State}, http::StatusCode, Json};
#[utoipa::path(
get,
path = "/api/users/{id}",
tag = "users",
params(("id" = Uuid, Path, description = "User ID")),
responses(
(status = 200, description = "User found", body = UserResponse),
(status = 404, description = "Not found", body = ErrorResponse)
),
security(("bearer" = []))
)]
pub async fn get_user(
State(state): State<AppState>,
Path(id): Path<Uuid>,
) -> Result<Json<UserResponse>, (StatusCode, Json<ErrorResponse>)> {
// handler logic
}
#[utoipa::path(
post,
path = "/api/users",
tag = "users",
request_body = CreateUserRequest,
responses(
(status = 201, description = "Created", body = UserResponse),
(status = 400, description = "Bad request", body = ErrorResponse)
)
)]
pub async fn create_user(
State(state): State<AppState>,
Json(req): Json<CreateUserRequest>,
) -> Result<(StatusCode, Json<UserResponse>), (StatusCode, Json<ErrorResponse>)> {
// handler logic
}
OpenApi — Combining Everything
use utoipa::openapi::security::{Http, HttpAuthScheme, SecurityScheme};
use utoipa::{Modify, OpenApi};
#[derive(OpenApi)]
#[openapi(
info(
title = "My API",
version = "1.0.0",
description = "API description"
),
tags(
(name = "users", description = "User management"),
(name = "health", description = "Health checks")
),
paths(
get_user,
create_user,
health_check
),
components(
schemas(
CreateUserRequest,
UserResponse,
ErrorResponse
)
),
modifiers(&SecurityAddon)
)]
pub struct ApiDoc;
struct SecurityAddon;
impl Modify for SecurityAddon {
fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
if let Some(components) = openapi.components.as_mut() {
components.add_security_scheme(
"bearer",
SecurityScheme::Http(Http::new(HttpAuthScheme::Bearer)),
);
}
}
}
Serving Scalar UI
use axum::{routing::get, Router};
use utoipa::OpenApi;
use utoipa_scalar::{Scalar, Servable};
pub fn create_router(state: AppState) -> Router {
Router::new()
.route("/health", get(health_check))
.route("/api/users", get(list_users).post(create_user))
.route("/api/users/{id}", get(get_user).put(update_user).delete(delete_user))
// Scalar UI at /api/docs
.merge(Scalar::with_url("/api/docs", ApiDoc::openapi()))
.with_state(state)
}
IntoParams — Query Parameters
use utoipa::IntoParams;
#[derive(Debug, Deserialize, IntoParams)]
pub struct PaginationParams {
/// Page number (1-indexed)
#[param(minimum = 1, default = 1)]
pub page: Option<u32>,
/// Items per page
#[param(minimum = 1, maximum = 100, default = 20)]
pub per_page: Option<u32>,
}
#[derive(Debug, Deserialize, IntoParams)]
pub struct UserFilters {
/// Filter by email contains
pub email: Option<String>,
/// Filter by status
pub status: Option<UserStatus>,
}
#[utoipa::path(
get,
path = "/api/users",
tag = "users",
params(PaginationParams, UserFilters),
responses((status = 200, body = Vec<UserResponse>))
)]
pub async fn list_users(
Query(pagination): Query<PaginationParams>,
Query(filters): Query<UserFilters>,
) -> Json<Vec<UserResponse>> {
// handler logic
}
Enums in Schema
#[derive(Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum UserStatus {
Active,
Inactive,
Pending,
}
#[derive(Debug, Serialize, Deserialize, ToSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum Event {
UserCreated { user_id: Uuid },
UserDeleted { user_id: Uuid, reason: String },
}
Common Patterns
See references/patterns.md for error handling, authentication middleware, and response types.
API Reference
See references/api_reference.md for complete ToSchema and path attribute options.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
solidjs
SolidJS framework development skill for building reactive web applications with fine-grained reactivity. Use when working with SolidJS projects including: (1) Creating components with signals, stores, and effects, (2) Implementing reactive state management, (3) Using control flow components (Show, For, Switch/Match), (4) Setting up routing with Solid Router, (5) Building full-stack apps with SolidStart, (6) Data fetching with createResource, (7) Context API for shared state, (8) SSR/SSG configuration. Triggers: solid, solidjs, solid-js, solid start, solidstart, createSignal, createStore, createEffect.
handoff
Compact the current conversation into a handoff document for another agent to pick up.
git-guardrails-claude-code
Set up Claude Code hooks to block dangerous git commands (push, reset --hard, clean, branch -D, etc.) before they execute. Use when user wants to prevent destructive git operations, add git safety hooks, or block git push/reset in Claude Code.
scaffold-exercises
Create exercise directory structures with sections, problems, solutions, and explainers that pass linting. Use when user wants to scaffold exercises, create exercise stubs, or set up a new course section.
obsidian-vault
Search, create, and manage notes in the Obsidian vault with wikilinks and index notes. Use when user wants to find, create, or organize notes in Obsidian.
edit-article
Edit and improve articles by restructuring sections, improving clarity, and tightening prose. Use when user wants to edit, revise, or improve an article draft.
Didn't find tool you were looking for?