GREsau/okapi

how to make okapi comment rocket return Object

Closed this issue · 1 comments

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.

The easiest way to return JSON is to use Json<...> with a struct.
For example:

/// # Create post using query params
///
/// Returns the created post.
#[openapi(tag = "Posts")]
#[get("/post_by_query?<post..>")]
fn create_post_by_query(post: Post) -> Option<Json<Post>> {
Some(Json(post))
}

Then you can add the structure and documentation like this:
#[derive(Serialize, Deserialize, JsonSchema, FromForm)]
struct Post {
/// The unique identifier for the post.
post_id: u64,
/// The title of the post.
title: String,
/// A short summary of the post.
summary: Option<String>,
}

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