Closed ninjadev64 closed 1 month ago
Forgot to mention that I tried using axum_macros's debug_handler
like the example does, but it gives some pretty bad generic trait bound errors for both Path<String>
and Data<ArcDB>
.
I was using a version of axum_macros that was incompatible with my installed version of axum. I've solved the original problem like this:
#[debug_handler]
pub async fn http_get_user(_header_map: HeaderMap, Path(name): Path<String>, db: Data<ArcDB>) -> Result<impl IntoResponse, impl IntoResponse> {
let db_user: DbUser = match db.get_cf(&db.cf_handle("users").unwrap(), &name).unwrap() {
Some(bytes) => serde_json::from_slice(&bytes).unwrap(),
None => return Err((StatusCode::NOT_FOUND, format!("User {name} not found"))),
};
let json_user = db_user.into_json(&db).await.unwrap();
Ok(FederationJson(WithContext::new_default(json_user)).into_response())
}
However, when I try to check the content type of the request and return an HTML representation if it's not ActivityPub, I get this:
#[debug_handler]
pub async fn http_get_user(header_map: HeaderMap, Path(name): Path<String>, db: Data<ArcDB>) -> Result<Box<dyn IntoResponse>, impl IntoResponse> {
let db_user: DbUser = match db.get_cf(&db.cf_handle("users").unwrap(), &name).unwrap() {
Some(bytes) => serde_json::from_slice(&bytes).unwrap(),
None => return Err((StatusCode::NOT_FOUND, format!("User {name} not found"))),
};
let accept = header_map.get("accept").map(|v| v.to_str().unwrap());
if accept == Some(FEDERATION_CONTENT_TYPE) {
let json_user = db_user.into_json(&db).await.unwrap();
Ok(Box::new(FederationJson(WithContext::new_default(json_user)).into_response()))
} else {
Ok(Box::new((StatusCode::OK, format!("HTML repr of {}", db_user.display_name))))
}
}
error[E0277]: the trait bound `Box<dyn IntoResponse>: IntoResponse` is not satisfied
--> src/users.rs:138:97
|
138 | pub async fn http_get_user(header_map: HeaderMap, Path(name): Path<String>, db: Data<ArcDB>) -> Result<Box<dyn IntoResponse>, impl IntoResponse> {
| ^^^^^^ the trait `IntoResponse` is not implemented for `Box<dyn IntoResponse>`, which is required by `Result<Box<dyn IntoResponse>, impl IntoResponse>: IntoResponse`
|
= help: the following other types implement trait `IntoResponse`:
axum::body::Empty<axum::body::Bytes>
http_body::combinators::box_body::BoxBody<axum::body::Bytes, E>
http_body::combinators::box_body::UnsyncBoxBody<axum::body::Bytes, E>
axum::body::Bytes
axum::extract::rejection::FailedToBufferBody
axum::extract::rejection::LengthLimitError
axum::body::Full<axum::body::Bytes>
axum::extract::rejection::UnknownBodyError
and 126 others
= note: required for `Result<Box<dyn IntoResponse>, impl IntoResponse>` to implement `IntoResponse`
note: required by a bound in `__axum_macros_check_http_get_user_into_response::{closure#0}::check`
--> src/users.rs:138:97
|
138 | pub async fn http_get_user(header_map: HeaderMap, Path(name): Path<String>, db: Data<ArcDB>) -> Result<Box<dyn IntoResponse>, impl IntoResponse> {
| ^^^^^^ required by this bound in `check`
Hi! Perhaps you could wrap the different types in an enum. The following example code may help you.
enum Resp<T> where T: Serialize {
ActivityPub(FederationJson<T>),
Axum((StatusCode, String)),
}
impl<T> axum::response::IntoResponse for Resp<T> where T: Serialize {
fn into_response(self) -> axum::response::Response {
match self {
Self::ActivityPub(data) => data.into_response(),
Self::Axum(data) => data.into_response(),
}
}
}
async fn http_get_user() -> Result<Resp, impl IntoResponse> {
// snip
if accept == Some(FEDERATION_CONTENT_TYPE) {
let json_user = db_user.into_json(&db).await.unwrap();
Ok(Resp::ActivityPub(FederationJson(WithContext::new_default(json_user)))
} else {
Ok(Resp::Axum((StatusCode::OK, format!("HTML repr of {}", db_user.display_name))))
}
}
Oh, that's great, thank you!
You can use Result as the return type.
I've been following the docs.rs "tutorial" for this library (leaning extensively on the examples in this repo as the "tutorial" is quite incomplete) and I have no idea how to return a "not found" response from my http_get_user handler. I'm using rocksdb btw.
I can't seem to return my own
(StatusCode::NOT_FOUND, "not found")
-esque thing because it's a different type toFederationJson.into_response(self)
's return type.Neither can I find anything in this library to pass to
FederationJson()
orWithContext::new_default()
that would indicate a "not found" status.Could you give me some guidance on implementing this?