How can I make the spec for OpenAPI show that my endpoint can return 400 as well? #676
-
I have the following OpenAPI structure: #[derive(Object)]
struct PostResponse {
key: Uuid,
}
#[derive(ApiResponse)]
enum PostApiResponse {
#[oai(status = 200)]
Ok(Json<PostResponse>),
}
struct Api;
#[OpenApi]
impl Api {
/// Store new encrypted secret
///
/// # Parameters
///
/// - `secret` - Encrypted secret to store
///
/// # Responses
///
/// - `200` - Encrypted secret stored
/// - `400` - Submitted encrypted secret is not in valid format
#[oai(path = "/secret", method = "post", tag = ApiTags::Secret)]
async fn post(
&self,
Json(encrypted_secret): Json<EncryptedSecret>,
) -> Result<PostApiResponse> {
let key: Uuid = Uuid::new_v4();
Ok(PostApiResponse::Ok(Json(PostResponse { key })))
} If the submitted JSON fails to be parsed I get a 400 response, which is fine. But how can I document this in my OpenAPI spec? As parsing happens automatically before it gets to my handler. And if I add this #[oai(status = 400)]
BadRequest, to my PostApiResponse rust compiles complains that it's unused since the validation is done before it gets to my handler and I don't get to return it myself so it can be used. And second question, how can I customize the output of the 400 error? Now it returns a string and I'd like to return the error as JSON for all my API handlers. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
Here are two options for handling the bad request errors Option 1:The easiest one is probably doing this on you're enum: #[derive(ApiResponse)]
#[oai(bad_request_handler = "bad_request_handler")]
enum CreateUserResponse {
/// Returns when the user is successfully created.
#[oai(status = 200)]
Ok,
/// Returns when the user already exists.
#[oai(status = 409)]
UserAlreadyExists,
/// Returns when the request parameters is incorrect.
#[oai(status = 400)]
BadRequest(PlainText<String>),
}
// Convert error to `CreateUserResponse::BadRequest`.
fn bad_request_handler(err: Error) -> CreateUserResponse {
CreateUserResponse::BadRequest(PlainText(format!("error: {}", err.to_string())))
} The macro Option 2:You could also handle all Parse Errors using middleware if you want a global solution as such: pub async fn handle_errors(error: Error) -> impl IntoResponse {
if let Some(err) = error.downcast_ref::<ParseRequestPayloadError>() {
handle_parse_payload(err) // Pass to a function or handle here with the poem_openapi::error::ParseRequestPayloadError
} else {
trace!("Returned an error into a response directly");
error
}
.into_response()
}
//...
pub fn setup_routes() -> impl Endpoint + EndpointExt {
info!("✨| Creating Service APIs");
Route::new()
.catch_all_error(handle_errors)
// .. your setup
} I dont use the first approach but if you find that 400 isn't being documented you can get rid of the warning when you add it yourself like so #[derive(ApiResponse)]
pub enum Response {
#[allow(dead_code)] // Reason: I like to comment why :)
#[oai(status = 400)]
BadRequest,
} |
Beta Was this translation helpful? Give feedback.
Here are two options for handling the bad request errors
Option 1:
The easiest one is probably doing this on you're enum: