I'm currently generating the Swagger docs HTTP error responses by adding them to each URI function like this:
#[utoipa::path(
context_path = "/user",
tag = "user",
responses(
(status = 200, description = "Endpoint to get all data from a user.",
body = Value,
example = json!({
"id": 12,
"user_id": "TestUser42",
"class": "8a",
"created_at": "07-04-2004",
"user_data": {
"traffic": [],
"modules": []
}
})
),
(status = 401, description = "Access token is missing or invalid",
body = HttpError,
example = json!({
"time": "07-05-2024 08:17:33",
"status_code": "401",
"error_type": "Unauthorized",
"reason": "Access token is missing or invalid"
})
),
(status = 404, description = "ID not found", body = HttpError,
example = json!({
"time": "07-05-2024 08:17:33",
"status_code": "404",
"error_type": "NotFound",
"reason": "ID not found"
})
),
(status = 403, description = "Not allowed to call this endpoint with the current permission", body = HttpError,
example = json!({
"time": "07-05-2024 08:17:33",
"status_code": "403",
"error_type": "AccessForbidden",
"reason": "Wrong or missing permissions"
})
)
),
security(
("bearerAuth" = [])
)
)]
#[get("/get")]
#[protect(any("STUDENT", "ADMIN", "TEACHER", "MAKERSPACE"), error = "access_denied")]
pub async fn get_user(
claims: Option<web::ReqData<Claims>>
) -> impl Responder {
if let Some(claims) = claims {
match user_service::get_user(claims.sub.as_str()).await {
Ok(u) => HttpResponse::Ok().json(u),
Err(_) => HttpError::not_found("User does not exist").error_response()
}
} else {
HttpError::bad_gateway("Unable to get user").error_response()
}
}
How can refactor this by putting the HTTP error tuples into a JSON file or a different Rust file?
Because the 401, 403, and 404
are always the same code snippets.
After some help from the Rust forum I found a solution!
I had to use IntoResponses
as @kmdreko mentioned before and I didn't know that I can use ContentBuilder
which allows me to create an example and return Content
afterwards with build()
.
You can find my solution here if you want to implement it too.
impl IntoResponses for HttpError {
fn responses() -> BTreeMap<String, RefOr<Response>> {
ResponsesBuilder::new()
.response("401", ResponseBuilder::new()
.description("JWT invalid or missing")
.content(
"application/json",
ContentBuilder::new()
.example(Some(json!({
"time": "07-05-2024 08:17:33".to_string(),
"status_code": "401".to_string(),
"error_type": ErrorResponse::Unauthorized,
"reason": Some("JWT missing or invalid".to_string()),
}))
).build()
)
)
.response("403", ResponseBuilder::new()
.description("Not allowed to call this endpoint with the current permission")
.content(
"application/json",
ContentBuilder::new()
.example(Some(json!( {
"time": "07-05-2024 08:17:33".to_string(),
"status_code": "403".to_string(),
"error_type": ErrorResponse::Forbidden,
"reason": Some("Access Forbidden".to_string()),
}))
).build()
)
)
.build()
.into()
}
}
HttpError
is my struct to handle HTTP Error responses.