-
-
Notifications
You must be signed in to change notification settings - Fork 295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Return a custom error from an openapi endpoint #244
Comments
See #230 (comment) I have a function in my error struct to return the error as |
@Christoph-AK thanks, but I wonder if there's a more straightforward way of doing it. |
@sunli829 Would it be possible to allow an OpenApi endpoint to return whatever result with an Error that implements use poem::web::Json;
use poem_openapi::{OpenApi, ApiResponse};
use serde::Serialize;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum CustomError {
#[error("BadRequest")]
BadRequest,
#[error("Internal")]
Internal,
}
#[derive(ApiResponse)]
pub enum ApiErrorResponse {
#[oai(status = 400)]
BadRequest,
#[oai(status = 500)]
InternalServerError,
}
impl From<CustomError> for ApiErrorResponse {
fn from(err: CustomError) -> Self {
match err {
CustomError::BadRequest => ApiErrorResponse::BadRequest,
CustomError::Internal => ApiErrorResponse::InternalServerError,
}
}
}
#[derive(Serialize)]
struct MyJson {}
struct Api;
#[OpenApi]
impl Api {
// Here you can return a result
// If the result is Ok(), then the response status code is 200 and the type is Json<MyJson>
// If the result is Err(), then the response status code and type are defined by ApiErrorResponse
#[oai(path = "/json", method = "get")]
async fn get_json(&self) -> Result<Json<MyJson>, ApiErrorResponse> {
// You can now use the ? operator
Err(CustomError::BadRequest)?;
Ok(Json(MyJson{}))
}
} I think this would be very ergonomic to use. |
I think it's a good idea, will try it right now! |
Released in Here is the example: poem/poem-openapi/tests/response.rs Line 406 in aac6627
|
@sunli829 In fact, I expected to find also the 400 and 500 status codes and related data schemas. Here is the full code of my attempt: use poem::{http::StatusCode, error::ResponseError, Server, Route, listener::TcpListener};
use poem_openapi::{OpenApi, OpenApiService, ApiResponse, Object, payload::Json };
use serde::Serialize;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum CustomError {
#[error("BadRequest")]
BadRequest,
#[error("Internal")]
Internal,
}
impl ResponseError for CustomError {
fn status(&self) -> StatusCode {
match self {
CustomError::BadRequest => StatusCode::BAD_REQUEST,
CustomError::Internal => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}
#[derive(Serialize, Object)]
pub struct MyJson {
a: String
}
#[derive(Serialize, Object, Debug)]
pub struct InternalServerErrorPayload {
message: String
}
#[derive(ApiResponse)]
pub enum ApiJsonResponse {
#[oai(status = 200)]
Ok(Json<MyJson>),
}
#[derive(ApiResponse, Debug)]
pub enum ApiErrorResponse {
#[oai(status = 400)]
BadRequest,
#[oai(status = 500)]
InternalServerError(Json<InternalServerErrorPayload>),
}
impl From<CustomError> for ApiErrorResponse {
fn from(err: CustomError) -> Self {
match err {
CustomError::BadRequest => ApiErrorResponse::BadRequest,
CustomError::Internal => ApiErrorResponse::InternalServerError(Json(InternalServerErrorPayload{ message: "something bad".to_owned()})),
}
}
}
struct Api;
#[OpenApi]
impl Api {
#[oai(path = "/json", method = "get")]
async fn get_json(&self) -> Result<ApiJsonResponse, ApiErrorResponse> {
// You can now use the ? operator
Err(CustomError::BadRequest)?;
Ok(ApiJsonResponse::Ok(Json(MyJson{a: "hello".to_owned()})))
}
}
#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
if std::env::var_os("RUST_LOG").is_none() {
std::env::set_var("RUST_LOG", "poem=debug");
}
let api_service =
OpenApiService::new(Api, "Hello World", "1.0").server("http://localhost:3000/api");
let ui = api_service.swagger_ui();
Server::new(TcpListener::bind("localhost:3000"))
.run(Route::new().nest("/api", api_service).nest("/", ui))
.await
} |
Since Rust does not yet support specialization, this requires some macro changes. I'll add it tomorrow. |
Released in |
@sunli829 Amazing!! Thank you! |
I have some endpoints implemented in
poem
that I would like to migrate topoem-openapi
.All the endpoints return a
Result
with the same custom error implementingResponseError
.For example:
This works fine in
poem
; nevertheless, this does not compile withpoem-openapi
:I can make it compile with this workaround:
But, in this case, the response type and code are not mapped in the swagger UI.
Is there a way to share the same custom error between the two different types of endpoints and expose the expected types and code in the swagger UI?
The text was updated successfully, but these errors were encountered: