GREsau / okapi

OpenAPI (AKA Swagger) document generation for Rust projects
MIT License
578 stars 103 forks source link

OpenAPI support for FromForm for MsgPack and TempFile #131

Open crunchy234 opened 8 months ago

crunchy234 commented 8 months ago

The package versions I am using:

rocket = { version = "0.5.0-rc.3", features = ["msgpack"] }
rocket_okapi = { version = "0.8.0-rc.3", features = ["swagger", "msgpack"] }
schemars = "0.8.15"

The form input structs and endpoint function I am using is as follows:

#[derive(FromForm)]
pub struct DataInput<'r> {
    pub data_a: MsgPack<DataA>,
    pub data_b: TempFile<'r>,
}

#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct ResponseData {
    pub values: Vec<f64>,
}

#[openapi(tag = "Data")]
#[post("/process_data", data = "<data_input>")]
pub fn process_data(
    data_input: Form<DataInput<'_>>,
) -> Result<Json<ResponseData>, Status> { ... }

I am trying to work out if it is better to try implement JsonSchema or use #[openapi(skip)] and do a merge on a custom OpenApi struct with just this definition.

I was initially trying an OpenApi struct which is as follows.

pub fn process_data_openapi(schema_generator: &mut SchemaGenerator) -> OpenApi {
    use indexmap::indexmap;
    use rocket_okapi::okapi::openapi3::*;
    OpenApi {
        openapi: OpenApi::default_version(),
        info: Default::default(),
        servers: vec![],
        paths: indexmap! {
            "/process_data".to_owned() => PathItem {
                post: Some(
                    Operation {
                        tags: vec!["Data".to_owned()],
                        summary: Some("Gets the data result from the given files.".to_owned()),
                        request_body: Some(RefOr::Object(
                            RequestBody {
                                description: Some("The data definition.".to_string()),
                                content: indexmap! {
                                    "form-data".to_owned() => MediaType {
                                            schema: Some(SchemaObject {
                                                instance_type: Some(SingleOrVec::Vec(vec![
                                                    // TODO: Put definition here
                                                ])),
                                                ..Default::default()
                                            }),
                                            ..Default::default()
                                        }
                                },
                                ..Default::default()
                            }
                        )),
                        responses: Responses {
                            responses: indexmap! {
                                "200".to_owned() => RefOr::Object(
                                    Response {
                                        description: "The response data".to_owned(),
                                        content: indexmap! {
                                            "application/json".to_owned() => MediaType {
                                                schema: Some(ResponseData::json_schema(schema_generator).into()),
                                                ..Default::default()
                                            }
                                        },
                                        ..Default::default()
                                    }
                                )
                            },
                            ..Default::default()
                        },
                        ..Default::default()
                    }
                ),
                ..Default::default()
            },
        },
        ..Default::default()
    }
}

As you can see I'm not sure how to define the MediaType SchemaObject for the form-data

Are there any existing proc_macros that could help me or traits that I could implement?

Any help would be greatly appreciated.