Axum post request

Hi,

Firstly I am very new to Rust so apologies for what is probably a simple question.

I am trying to set up a post route however am running into this error in main.rs:

the trait bound `fn(Json<Contact>) -> impl Future<Output = Json<Value>> {create_contact_in_address_book}: Handler<_, _>` is not satisfied
the following other types implement trait `Handler<T, S>`:
  <Layered<L, H, T, S> as Handler<T, S>>
  <MethodRouter<S> as Handler<(), S>>

This is the app.router set up in main.rs:

let app = Router::new()
    .route("/", get(fetch_data))
    .route("/dispense/products", get(get_products))
    .route("/dispense/barcodes", get(get_barcodes))
    .route("/dispense/products/inventory_pricing", get(get_products_inventory_pricing))
    .route("/edm/contacts", get(get_contacts_by_email_address))
    .route("/edm/contacts", post(create_contact_in_address_book))
    .layer(GovernorLayer {
      config: Box::leak(governor_config),
    });

  axum::serve(listener, app.into_make_service_with_connect_info::<SocketAddr>()).await.unwrap(); // create the server.

This is the async function sitting in handler.rs:

pub async fn create_contact_in_address_book(Json(body): Json<Contact>) -> Json<Value> {
  // println!("Body: {:?}", body);

  match dotdigital_client().await {
    Ok(client) => {

      let body_value = serde_json::to_value(&body).expect("failed to serialise contact into Value");
      println!("Body Value: {:?}", body_value);

      match client.contacts().create_contact_in_address_book(body.address_book_id, &body_value).await {
        Ok(contact) => {
          println!("Contact: {:?}", contact);
          Json(json!(contact));
        },
        Err(e) => {
          println!("Error: {:?}", e);
          Json(json!({"error": "Failed to create contact"}));
        }
      }
      return Json(json!({"message": "Client created"}))
    }
    Err(e) => {
      println!("Error: {:?}", e);
      return Json(json!({"error": "Failed to create client"}))
    }
  }
}

This is the post request inside the client in client.rs

 async fn post<T: serde::de::DeserializeOwned>(&self, url: &str, body: &Value) -> Result<T, Error> {
    let response = self.client.post(url)
      .basic_auth(&self.user, Some(&self.password)) // basic auth
      .json(body)
      .send()
      .await?;

    let result = response.json::<T>().await?;
    Ok(result)
  }

and this is the actual request function inside client.rs:

pub async fn create_contact_in_address_book(&self, address_book_id: String, body: &Value) -> Result<Value, Error> {
    let url = format!("{}/address-books/{}/contacts", self.client.base_url, address_book_id);
    self.client.post(&url, body).await
  }

I have narrowed this down to something to do with the function create_contact_in_address_book and simple do a json return of { hello: world } this will work as seen below:

I have another method on the client which is a get, using the same logic and this endpoint will successfully return data.

I am extremely lost on why this is causing the error in the main.rs other than the return type of the handler doesn't "match" what Axum wants. Any pointers would be great or pointers on where to look so I can further break this down and understand why.

Thanks for your help!

Axum has a guide to Debugging handler type errors that might help.

Legend! Thank you for that. Didn't see that part in the docs.

Found out what was causing it - the one thing I didn't screenshot / copy across. The client on build could return "Box dyn Error" which doesn't match Axum IntoResponse

Rust is no longer cranky.

Appreciate you taking the time to help!

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.