tower-conneg 1.1.0

Tower middleware for HTTP content negotiation
//! `OpenAPI` example.

#![allow(clippy::expect_used)]
#![allow(clippy::print_stdout)]
#![allow(dead_code)]

use std::sync::Arc;

use serde::{Deserialize, Serialize};
use tower_conneg::{ErasedFormat, JsonFormat, MsgPackNamedFormat, ServerConfig};
use utoipa::openapi::{
    HttpMethod, OpenApi as OpenApiDocument, PathItem, PathsBuilder, path::OperationBuilder,
};
use utoipa::{OpenApi, ToSchema};

#[derive(OpenApi)]
#[openapi(components(schemas(CreateUserRequest, User, ApiError)))]
struct ApiDoc;

#[derive(Debug, Deserialize, ToSchema)]
struct CreateUserRequest {
    name: String,
    email: String,
}

#[derive(Debug, Serialize, ToSchema)]
struct User {
    id: u64,
    name: String,
    email: String,
}

#[derive(Debug, Serialize, ToSchema)]
struct ApiError {
    code: String,
    message: String,
}

fn config() -> ServerConfig {
    let json: Arc<dyn ErasedFormat> = Arc::new(JsonFormat);
    let msgpack: Arc<dyn ErasedFormat> = Arc::new(MsgPackNamedFormat);
    ServerConfig::builder()
        .formats([json.clone(), msgpack])
        .fallback_format(json)
        .build()
}

fn create_user_operation(config: &ServerConfig) -> PathItem {
    let docs = config.openapi_formats();
    let operation = OperationBuilder::new()
        .operation_id(Some("create_user"))
        .request_body(Some(docs.required_request_body::<CreateUserRequest>()))
        .response("201", docs.response::<User, _>("Created user."))
        .response("406", docs.not_acceptable_response_with_body::<ApiError>())
        .response(
            "415",
            docs.unsupported_media_type_post_response_with_body::<ApiError>(),
        )
        .build();

    PathItem::new(HttpMethod::Post, operation)
}

fn openapi(config: &ServerConfig) -> OpenApiDocument {
    let mut api = ApiDoc::openapi();
    api.paths = PathsBuilder::new()
        .path("/users", create_user_operation(config))
        .build();
    api
}

fn main() {
    println!(
        "{}",
        serde_json::to_string_pretty(&openapi(&config())).expect("OpenAPI should serialize")
    );
}