A "proxy" with axum v0.7 and hyper v1?

Currently using axum v0.6.20 and hyper v0.14.28 I have the following code that is work amazingly:

#[tokio::main]
async fn main() {
  let app = Router::new()
    .route("/", get(handler))
    .route("/custom/*key", get(proxy).post(proxy));

  // ...
}

pub async fn proxy(mut req: Request<Body>) -> Result<Response<Body>, StatusCode> {
  let path_query = req
    .uri()
    .path_and_query()
    .map_or_else(|| req.uri().path(), |v| v.as_str());

  let uri = format!("http://localhost:9000/{}", path_query);

  *req.uri_mut() = Uri::try_from(uri).unwrap();

  // This comes from State in real code
  let hyper_client = HyperClient::new();

  let res = hyper_client.request(req).await.unwrap();

  if res.status().is_server_error() {
    return Err(StatusCode::INTERNAL_SERVER_ERROR);
  }

  Ok(res)
}

Now with axum v0.7 (and hyper v1) I don't understand anymore if this can continue to work:

  1. If I use the new hyper v1 the Client is gone and I don't understand how to make it work with reqwest nor ureq

  2. If I use the hyper now "legacy" Client with this code:

    let client = Client::builder(TokioExecutor::new()).build_http();
    
    let res = client.request(req).await.unwrap();
    

    I have the following error:

    error[E0308]: mismatched types
        |
    138 |     Ok(res)
        |     -- ^^^ expected `Response<Body>`, found `Response<Incoming>`
        |     |
        |     arguments to this enum variant are incorrect
        |
        = note: expected struct `hyper::Response<axum::body::Body>`
                  found struct `hyper::Response<hyper::body::Incoming>`
    help: the type constructed contains `hyper::Response<hyper::body::Incoming>` due to the type of the argument passed
    

What can I do?

As far as I can gather from comparing the docs for hyper v0.14 with hyper v1, the Body type doesn't exist any more. To me it looks very much like you can just replace Body with Incoming. Indeed, according to the changelog, Body just got renamed to Incoming (plus a few cosmetic changes that should be more implementation detail and less API changes in user code).

1 Like

Thanks. What I don't understand is how.

- pub async fn proxy(mut req: Request<Body>) -> Result<Response<Body>, StatusCode> {
+ pub async fn proxy(mut req: Request<Incoming>) -> Result<Response<Incoming>, StatusCode> {

doesn't work?

1 Like

Wow!

It works, but using this:

use axum::body::Body;
use hyper::body::Incoming;

- pub async fn proxy(mut req: Request<Body>) -> Result<Response<Body>, StatusCode> {
- pub async fn proxy(mut req: Request<Incoming>) -> Result<Response<Incoming>, StatusCode> {
+ pub async fn proxy(mut req: Request<Body>) -> Result<Response<Incoming>, StatusCode> {

because if I use:

pub async fn proxy(mut req: Request<Incoming>) -> Result<Response<Incoming>, StatusCode> {}

axum throws with:

error[E0277]: the trait bound `fn(hyper::Request<hyper::body::Incoming>) -> impl futures::Future<Output = std::result::Result<hyper::Response<hyper::body::Incoming>, hyper::StatusCode>> {routes::proxy}: axum::handler::Handler<_, _>` is not satisfied
    |
104 |         get(proxy).post(proxy),
    |         --- ^^^^^^^^^^^^^^^^^^^^^ the trait `axum::handler::Handler<_, _>` is not implemented for fn item `fn(hyper::Request<hyper::body::Incoming>) -> impl futures::Future<Output = std::result::Result<hyper::Response<hyper::body::Incoming>, hyper::StatusCode>> {routes::proxy}`
    |         |
              required by a bound introduced by this call

Thank you very much!

But what if I wanna use reqwest?

Can you suggest a way?

The best way would be if you could convert axum's Request—which is just a reëxport of http::Request—to reqwest::Request. Then you could call reqwest::Client::execute with that. Unfortunately, while reqwest does implement TryFrom<http::Request<B>> for reqwest::Request, it uses an incompatible version of http; axum works with http v1 while reqwest is still using http v0.2. So AFAICT you have to manually do the conversion. You could have a look at how the conversion for the http v0.2 Request is implemented in reqwest and write a function or trait that allows you to do something similar for the http v1 version on Request.


Or just wait till the new version of reqwest is released that will depend on hyper v1 and therefore on http v1 as well.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.