You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I don't think this is a bug or issue per se, but I would still love some help and the documentation around Handler is very sparse. It says "it should just work if you have the correct type", which is true for most free functions, but not for my use case. And the recommended #[debug_handler] macro also doesn't work for my use case.
Like #1052, I was inspired by https://www.fpcomplete.com/blog/axum-hyper-tonic-tower-part4/ to create a combined Tonic/Axum server. However I want to take it a step further by just having a single implementation for each RPC (the GRPC handler) and having Axum endpoints be wrappers around the GRPC handlers. For the Axum endpoint, this involves accepting JSON, deserializing into the GRPC type, calling the Tonic handler, then re-serializing the result back to JSON. This works fine with a manually crafted wrapper function like this:
structMyHandler;#[async_trait]implEchoforMyGrpcHandler{asyncfnecho(&self,request: tonic::Request<EchoRequest>,) -> Result<tonic::Response<EchoReply>, tonic::Status>{Ok(tonic::Response::new(EchoReply{message:format!("Echoing back: {}", request.get_ref().message),}))}}asyncfnEchoHandlerWrapper(Json(body):Json<EchoRequest>) -> Result<Json<EchoReply>,HybridError>{let handler = MyGrpcHandler{};let r = handler.echo(tonic::Request::new(body)).await;match r {Ok(r) => Ok(Json(r.into_inner())),Err(e) => Err(HybridError(e))// wrap GRPC errors into HTTP errors, not relevant to this issue}}#[tokio::main]asyncfnmain(){let addr = SocketAddr::from(([0,0,0,0],3000));let axum_make_service = axum::Router::new().route("/Echo", axum::handler::any(EchoHandlerWrapper)).into_make_service();let grpc_service = tonic::transport::Server::builder().add_service(EchoServer::from_arc(arcHandler)).into_service();let hybrid_make_service = hybrid(axum_make_service, grpc_service);let server = hyper::Server::bind(&addr).serve(hybrid_make_service);ifletErr(e) = server.await{eprintln!("server error: {}", e);}}
However, I'd like to reduce the boilerplate associated with creating a new wrapper function for each new GRPC endpoint. So I attempted to create a generic wrapper function that takes a GRPC handler and transforms it into a closure that implements axum::Handler. Due to the structure of this function, I cannot apply the #[debug_handler] macro to it. Here's where I'm at now:
// This compiles. The input func is supposed to be a GRPC handler func. The output should be compatible with axum::Handler.fnWrapGrpcHandler<'a,ReqT,ResT,FIn,FOut>(func:fn(&MyHandler, tonic::Request<ReqT>) -> Pin<Box<dynFuture<Output = Result<tonic::Response<ResT>, tonic::Status>> + Send + 'a>>)
-> implFn(Json<ReqT>) -> Pin<Box<dynFuture<Output = Result<Json<ResT>,HybridError>> + 'a>>where//,HandlerFnfor<'de>ReqT: serde::Deserialize<'de> + 'a,ResT: serde::Serialize + 'a{move |Json(req):Json<ReqT>| {Box::pin((|Json(req):Json<ReqT>| asyncmove{let handler = std::sync::Arc::new(MyHandler{});let r = asyncmove{func(handler.as_ref(), tonic::Request::new(req)).await}.await;match r {Ok(r) => Ok(Json(r.into_inner())),Err(e) => Err(HybridError(e))}})(Json(req)))}}
But when I try to call it with a concrete function I get very unhelpful errors, and despite my best efforts I'm not able to coerce the function pointer into the right type:
// Gives error: the trait bound `impl Fn(Json<_>)-> Pin<Box<dyn futures::Future<Output = Result<Json<_>, HybridError>>>>: Handler<_, _>` is not satisfied// the trait `Handler<ReqBody, T>` is implemented for `axum::handler::Layered<S, T>`rustcE0277// server-hybrid.rs(263, 25): required by a bound introduced by this call// mod.rs(52, 8): required by a bound in `axum::handler::any`// the trait bound `impl Fn(axum::Json<_>)-> Pin<Box<dyn futures::Future<Output = Result<axum::Json<_>, HybridError>>>>: Handler<_, _>` is not satisfied// the trait `Handler<ReqBody, T>` is implemented for `axum::handler::Layered<S, T>`rustcE0277// server-hybrid.rs(263, 25): required by a bound introduced by this call// mod.rs(52, 8): required by a bound in `axum::handler::any`let axum_make_service = axum::Router::new().route("/Echo", axum::handler::any(WrapGrpcHandler(MyGrpcHandler::echo))).into_make_service();// Gives error: mismatched types// expected fn pointer `for<'r> fn(&'r MyHandler, tonic::Request<_>) -> Pin<Box<dyn futures::Future<Output = Result<tonic::Response<_>, Status>> + std::marker::Send>>`// found fn item `fn(&MyHandler, tonic::Request<tonic_example::echo::EchoRequest>) -> Pin<Box<dyn futures::Future<Output = Result<tonic::Response<tonic_example::echo::EchoReply>, Status>> + std::marker::Send>> {<MyHandler as Echo>::echo::<'_, '_>}`rustcE0308let x = WrapGrpcHandler(MyHandler::echo);
Apologies in advance if this is not the right forum to ask this question. But perhaps this can still be of use to others who are trying to do this kind of thing.
The text was updated successfully, but these errors were encountered:
I don't think this is a bug or issue per se, but I would still love some help and the documentation around Handler is very sparse. It says "it should just work if you have the correct type", which is true for most free functions, but not for my use case. And the recommended #[debug_handler] macro also doesn't work for my use case.
Like #1052, I was inspired by https://www.fpcomplete.com/blog/axum-hyper-tonic-tower-part4/ to create a combined Tonic/Axum server. However I want to take it a step further by just having a single implementation for each RPC (the GRPC handler) and having Axum endpoints be wrappers around the GRPC handlers. For the Axum endpoint, this involves accepting JSON, deserializing into the GRPC type, calling the Tonic handler, then re-serializing the result back to JSON. This works fine with a manually crafted wrapper function like this:
However, I'd like to reduce the boilerplate associated with creating a new wrapper function for each new GRPC endpoint. So I attempted to create a generic wrapper function that takes a GRPC handler and transforms it into a closure that implements axum::Handler. Due to the structure of this function, I cannot apply the #[debug_handler] macro to it. Here's where I'm at now:
But when I try to call it with a concrete function I get very unhelpful errors, and despite my best efforts I'm not able to coerce the function pointer into the right type:
Apologies in advance if this is not the right forum to ask this question. But perhaps this can still be of use to others who are trying to do this kind of thing.
The text was updated successfully, but these errors were encountered: