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
-
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