GREsau / okapi

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

how to make okapi comment rocket return Object #102

Closed jiangxiaoqiang closed 2 years ago

jiangxiaoqiang commented 2 years ago

I am using rust rocket as my web server, this is the code looks like:

/// # search the template list
///
/// return different type of template
#[openapi(tag = "template")]
#[get("/v1/list?<query..>")]
pub fn list(query: TemplateRequest) -> content::RawJson<String> {
    let contents = get_template_list(query.template_type, query.name);
    return box_rest_response(contents);
}

this code works fine. Now I facing a problem is that the rust rocket return raw json, the client side could not know the return content structure. it only show a json string in swagger:

enter image description here

the client did not know what the response content is. I have read the the rust rocket official document still did not figure out what should I do to return the entity structure. I have tried like this:

pub fn list(query: TemplateRequest) -> Result<Vec<TemplateResponse>, String> {
    let contents = get_template_list(query.template_type, query.name);
    return Ok(contents);
}

the compiler shows:

error[E0277]: the trait bound `std::vec::Vec<TemplateResponse>: Responder<'_, '_>` is not satisfied
  --> src/biz/template/bill_book_template_controller.rs:28:1
   |
28 | #[openapi(tag = "账本模版")]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Responder<'_, '_>` is not implemented for `std::vec::Vec<TemplateResponse>`
   |
   = help: the following implementations were found:
             <std::vec::Vec<u8> as Responder<'r, 'static>>
   = note: required because of the requirements on the impl of `Responder<'_, '_>` for `Result<std::vec::Vec<TemplateResponse>, std::string::String>`
note: required by a bound in `rocket_okapi::response::OpenApiResponder::responses`
  --> /Users/xiaoqiangjiang/.cargo/git/checkouts/okapi-727e9b4b9c217cbb/65244f0/rocket-okapi/src/response/mod.rs:10:41
   |
10 | pub trait OpenApiResponder<'a, 'r: 'a>: rocket::response::Responder<'a, 'r> {
   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `rocket_okapi::response::OpenApiResponder::responses`
   = note: this error originates in the attribute macro `openapi` (in Nightly builds, run with -Z macro-backtrace for more info)

I also tried to implement like this:

impl<'r> Responder<'r, 'static> for Vec<TemplateResponse> {
    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
        // Convert object to json
        let body = serde_json::to_string(&self).unwrap();
        Response::build()
            .sized_body(body.len(), std::io::Cursor::new(body))
            .header(rocket::http::ContentType::JSON)
            .status(rocket::http::Status::new(self.http_status_code))
            .ok()
    }
}

seems did not work. I have tried this:

pub fn list(query: TemplateRequest) -> Result<content::RawJson<String>, String> {
    let contents = get_template_list(query.template_type, query.name);
    return Ok(box_rest_response(contents));
}

it works but still could not show the response structure at client side.

ralpha commented 2 years ago

The easiest way to return JSON is to use Json<...> with a struct. For example: https://github.com/GREsau/okapi/blob/65244f0037a4625f22a64cc45ef8179cdb984745/examples/json-web-api/src/main.rs#L84-L91 Then you can add the structure and documentation like this: https://github.com/GREsau/okapi/blob/65244f0037a4625f22a64cc45ef8179cdb984745/examples/json-web-api/src/main.rs#L74-L82

With RawJson you can return any JSON, so there is no way to know what the structure is of the JSON at compile time.