Schema & OpenAPI Generation

Vespera generates a complete OpenAPI 3.1 spec from your Rust types at compile time. Derive Schema on any type used in a handler's input or output and it appears in the spec automatically.

Deriving Schema

#[derive(Serialize, Deserialize, vespera::Schema)]
pub struct User {
    pub id: u32,
    pub name: String,
    pub email: String,
    pub bio: Option<String>, // optional — not in `required` array
}

Vespera respects all standard serde attributes:

#[derive(Serialize, Deserialize, vespera::Schema)]
#[serde(rename_all = "camelCase")]
pub struct CreateUserRequest {
    pub user_name: String,          // → "userName" in OpenAPI
    pub email: String,
 
    #[serde(rename = "fullName")]
    pub name: String,               // → "fullName" in OpenAPI
 
    #[serde(skip)]
    pub internal_id: u64,           // excluded from schema
 
    pub bio: Option<String>,        // optional field
}

Type Mapping

Rust TypeOpenAPI Schema
String, &strstring
i8i128, u8u128integer
f32, f64number
boolboolean
Vec<T>array with items
Option<T>T (parent marks field as optional)
HashMap<K, V>object with additionalProperties
BTreeSet<T>, HashSet<T>array with uniqueItems: true
Uuidstring with format: uuid
Decimalstring with format: decimal
NaiveDatestring with format: date
NaiveTimestring with format: time
DateTime, DateTimeWithTimeZonestring with format: date-time
FieldData<NamedTempFile>string with format: binary
()empty response (204 No Content)
Custom struct$ref to components/schemas

Generic Types

All type parameters must also derive Schema:

#[derive(Schema)]
struct Paginated<T: Schema> {
    items: Vec<T>,
    total: u32,
    page: u32,
}

SeaORM Integration

schema_type! has first-class support for SeaORM models. Relation fields are converted automatically:

#[derive(Clone, Debug, DeriveEntityModel)]
#[sea_orm(table_name = "memos")]
pub struct Model {
    #[sea_orm(primary_key)]
    pub id: i32,
    pub title: String,
    pub user_id: i32,
    pub user: BelongsTo<super::user::Entity>,      // → Option<Box<UserSchema>>
    pub comments: HasMany<super::comment::Entity>,  // → Vec<CommentSchema>
    pub created_at: DateTimeWithTimeZone,           // → chrono::DateTime<FixedOffset>
}
 
vespera::schema_type!(Schema from Model, name = "MemoSchema");
SeaORM TypeGenerated Schema Type
HasOne<Entity>Box<Schema> or Option<Box<Schema>>
BelongsTo<Entity>Option<Box<Schema>>
HasMany<Entity>Vec<Schema>
DateTimeWithTimeZonechrono::DateTime<FixedOffset>

Circular references (e.g. User ↔ Memo) are detected automatically and handled by inlining fields to prevent infinite recursion.

Database Defaults in OpenAPI

Fields with SeaORM database defaults get default values in the generated schema:

SeaORM AttributeOpenAPI Default
primary_key (Uuid)"00000000-0000-0000-0000-000000000000"
primary_key (i32/i64)0
default_value = "NOW()""1970-01-01T00:00:00+00:00"
default_value = "gen_random_uuid()""00000000-0000-0000-0000-000000000000"
default_value = "true"true

required is determined solely by nullability (Option<T>). Fields with defaults are still required unless they are Option<T>.

Configuring the OpenAPI Output

Pass parameters to vespera!() to control the spec:

let app = vespera!(
    openapi = "openapi.json",   // write spec to this file at compile time
    title = "My API",
    version = "1.0.0",
    docs_url = "/docs",         // Swagger UI
    redoc_url = "/redoc",       // ReDoc
    servers = [
        { url = "https://api.example.com", description = "Production" },
        { url = "http://localhost:3000",   description = "Development" }
    ]
);

See vespera! Macro for the full parameter reference.

Contents
Edit this page
문의 및 의견 제출
contact@devfive.kr
Copyright © DEVFIVE. All Rights Reserved.
DEVFIVE