Replies: 1 comment 2 replies
-
This is not yet fully there yet in #[derive(IntoResponses)]
pub enum LoginResponse {
/// Successful login
#[response(
status = OK,
headers(
("Authorization" = String, description = "Access token of successfull login")
)
)]
Ok((String, String)),
/// Unauthorized to access to the service
#[response(status = BAD_REQUEST)]
Unauthorized(String),
}
impl IntoResponse for LoginResponse {
fn into_response(self) -> axum::response::Response {
match self {
Self::Ok((token, id)) => (
StatusCode::OK,
[
(header::CONTENT_TYPE, "text/plain"),
(header::AUTHORIZATION, token.as_str()),
],
id,
)
.into_response(),
Self::Unauthorized(error) => (StatusCode::BAD_REQUEST, error).into_response(),
}
}
}
#[utoipa::path(
post,
context_path = "/user",
path = "/login",
request_body = LoginRequest,
responses(LoginResponse),
)]
#[axum::debug_handler]
async fn login(
State(user_service): State<UserService>,
Json(login_request): Json<LoginRequest>,
) -> LoginResponse {
user_repository
.find_user_by_name(&login_request.username)
.map_err(LoginError::UnexpectedSqlxError)
.and_then(|user| async {
if let Some(user) = user {
Ok(user.0)
} else {
Err(LoginError::NotFound(login_request.username.to_string()))
}
})
.and_then(|user| async move {
match futures::try_join!(
verify_password(login_request.password.as_bytes(), &user.password_hash),
validate_secret_key(
mem::take(&mut user.secret_key.into_inner()),
login_request.secret_key.as_str()
)
) {
Ok(_) => Ok(user.id),
Err(error) => Err(error),
}
})
.and_then(|id| async {
token_service
.generate_token(login_request.username.clone(), SECRET_KEY.as_bytes())
.await
.map_err(Into::into)
.map(|token| (token, id))
})
.await
.map_or_else(
|error| {
tracing::error!("Failed to login {error}");
LoginResponse::Unauthorized(LoginError::Unauthorized.to_string())
},
LoginResponse::Ok,
)
} Hope this helps. @leebenson |
Beta Was this translation helpful? Give feedback.
2 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Hey! Hoping someone can guide me please.
I'm trying to get something as closely resembling Poem's OpenAPI implementation as I can, using Axum + Utoipa.
i.e. I want to avoid writing both Axum
IntoResponse
blocks and manual Utoiparesponses = (...)
that basically repeat the same thing. It's so easy for them to fall out of sync.My first thought was: I'll write a proc macro that annotates success/error enums like this:
And then my Axum handlers would be something like this...
This would generate both:
IntoResponse
impl, using the response codes and JSON bodis (where applicable).... but then I discovered #433 and related work, which seems to do almost exactly this, at least for the Utoipa part.
The part I haven't figure out yet is the interplay with Axum.
I wondered if you have any guidance on how to approach this? It seems like a lot of the macro machinery is there already, but I can't seem to figure out how to put it all together into a single handler example.
My goal is to stop having to have compile-time verification of handler params + responses that is guaranteed to remain in sync between what Axum expects and what OpenAPI definitions advertise!
Thanks!
Beta Was this translation helpful? Give feedback.
All reactions