How to send multiple headers with reqwest?

I'm creating an application to get data from an API. Then I used reqwest. In this case, I need to send headers like below.

route.rs

#[get("/token")]
async fn get_token() -> String {
    let set_token = common::auth_test(); 
    return set_token;
}

comm.rs

extern crate reqwest;
use reqwest::header::Authorization;
use reqwest::header::ContentType;

pub fn auth_test() -> String {

let client = reqwest::Client::new();
let resz = client.post("https://api.have.test.com/auth/token")
    .header(Authorization, "Basic abc456hghtyhg==")
    .header(ContentType, "application/x-www-form-urlencoded")
    .header(grant_type, "client_credentials")
    .send();

return resz;
}

But, when I run the application, I got these below errors.

this comes under the header.

this function takes 1 parameter but 2 parameters were supplied
expected 1 parameterrustc(E0061)

This comes under the grant_type.

cannot find value grant_type in this scope
not found in this scoperustc(E0425)

How can I solve them and get the response ??

I think you never defined grant_type.

Anyway, it should not be on the http header, instead is part of the query and, as it is a post request, should be placed in the body of the request.

Found this example:

1 Like

@alexmario74 But, I dont understand how can I define it in rust ?? I read that doc, but still I have no idea.. How can I do it ??

As far as I can understand, it is just a string.

In your code:

pub fn auth_test() -> String {

    let client = reqwest::Client::new();
    let resz = client.post("https://api.have.test.com/auth/token")
        .header(Authorization, "Basic abc456hghtyhg==")
        .header(ContentType, "application/x-www-form-urlencoded")
        .header(grant_type, "client_credentials")
        .send();

    return resz;
}

you passed grant_type as a variable, and that variable is never defined.

That's the root case of your error.

But, even if you define a variable:

let grant_type = "grant_type";

That is not a valid http header field.

According to the page I posted, you should pass that value in the body of the post request.

let resz = client.post("https://api.have.test.com/auth/token")
    .header(Authorization, "Basic abc456hghtyhg==")
    .header(ContentType, "application/x-www-form-urlencoded")
    .body("grant_type=client_credentials")
    .send();

As you can see here I used the method body() instead of the header().

I'm not so familiar with reqwest, but it looks like you should handle the future returned from send().

UPDATE

I saw in another post from you, that you are actually using a different version
of reqwest (v 0.8.8), that has a different API.
In this version the send() return is a Result, not a future.
In this case you can ignore this part of the answer.

https://docs.rs/reqwest/0.10.4/reqwest/struct.RequestBuilder.html#method.send

That mean you have to change a bit more yor code to solve it:

let resz = async {
    let fut = client.post("https://api.have.test.com/auth/token")
        .header(Authorization, "Basic abc456hghtyhg==")
        .header(ContentType, "application/x-www-form-urlencoded")
        .body("grant_type=client_credentials")
        .send();

     fut.await?
 };

I'm not 100% sure about that code, but the point is that you have to get the value through a future, and so you have to work with async/.await or use the function block_on from the futures crate.

You can even decide to return the future from the function and let the caller deal with that.

1 Like

@alexmario74 - Thank u for your response. But, still I get this below error under the .header.

this function takes 1 parameter but 2 parameters were supplied
expected 1 parameterrustc(E0061)

How can I solve this ??

I didnt understand this. Please can u explain this or can u give a link to read about this..

When you build the request calling send() the value you get back is a future, not the response of your request.

To get the response, you have to wait the future is resolved.

Sorry, have no idea about this.

1 Like

@alexmario74 - Now I have changed my code like below. And I am using version 0.10 of reqwest.

extern crate reqwest;
use hyper::header::{Headers, Authorization, Basic, ContentType};

pub fn authenticate() -> Result<(), reqwest::Error> {

return get_page();
}

async fn get_page() -> Result<(), reqwest::Error> {

    fn construct_headers() -> Headers {
        let mut headers = Headers::new();
        headers.set(
            Authorization(
                Basic {
                    username: "GT:GTHYN".to_owned(),
                    password: Some("ABGHT".to_owned())
                }
            )
         );
        headers.set(ContentType::form_url_encoded());
        headers
    }

    let client = reqwest::Client::new();
    let reszr = client.post("https://api.test.com/auth/token")
    .headers(construct_headers())
    .body("grant_type=client_credentials")
        .send()
        .await?
        .text()
        .await?;
        
return reszr;
}

And it gives me these errors.

error[E0308]: mismatched types
  --> src\search\routes\common.rs:27:14
   |
27 |     .headers(construct_headers())
   |              ^^^^^^^^^^^^^^^^^^^ expected struct `search::routes::reqwest::header::HeaderMap`, found struct `hyper::header::Headers`
   |
   = note: expected struct `search::routes::reqwest::header::HeaderMap`
              found struct `hyper::header::Headers`

error[E0308]: mismatched types
  --> src\search\routes\common.rs:34:12
   |
34 |     return reszr;
   |            ^^^^^ expected enum `std::result::Result`, found struct `std::string::String`
   |
   = note: expected type `std::result::Result<(), search::routes::reqwest::Error>`
            found struct `std::string::String`

To fix the error of the return statemente, just leave it so:

client.post("https://api.test.com/auth/token")
    .headers(construct_headers())
    .body("grant_type=client_credentials")
        .send()
        .await?
        .text()
        .await

This already send back a Result, if you use the ? operator you're getting the actual value, and on error case it just return the error from the function.

So you need to remove the last ? so you get the result, and return it.

About the Headers, you are supposed to pass the reqwest HeaderMap, not the hyper type as you are doing.

If you look on the documentation of the RequestBuilder has the method bearer_auth() that get a token as an argument. So you can avoid to set it on the headers.

1 Like

I have updated the code like below.

extern crate reqwest;
use hyper::header::{Headers, Authorization, Basic, ContentType};

pub fn authenticate() -> Result<(), reqwest::Error> {

return get_page();
}

async fn get_page() -> Result<(), reqwest::Error> {

    fn construct_headers() -> Headers {
        let mut headers = Headers::new();
        headers.set(
            Authorization(
                Basic {
                    username: "HI:JHYU".to_owned(),
                    password: Some("GHYRYH".to_owned())
                }
            )
         );
        headers.set(ContentType::form_url_encoded());
        headers
    }

    let client = reqwest::Client::new();

    let reszr = client.post("https://api.test.com/auth/token")
    .headers(construct_headers())
    .body("grant_type=client_credentials")
        .send()
        .await?
        .text()
        .await;

        return reszr;
}

And it gives me these errors.

error[E0308]: mismatched types
  --> src\search\routes\common.rs:28:14
   |
28 |     .headers(construct_headers())
   |              ^^^^^^^^^^^^^^^^^^^ expected struct `search::routes::reqwest::header::HeaderMap`, found struct `hyper::header::Headers`
   |
   = note: expected struct `search::routes::reqwest::header::HeaderMap`
              found struct `hyper::header::Headers`

error[E0308]: mismatched types
  --> src\search\routes\common.rs:35:16
   |
35 |         return reszr;
   |                ^^^^^ expected `()`, found struct `std::string::String`
   |
   = note: expected enum `std::result::Result<(), _>`
              found enum `std::result::Result<std::string::String, _>`

And I tried to find bearer_auth(). But, I couldnt find anything.

Ok, sorry you have to change the return type.

That error is because you have Result<(), reqwest::Error>, it should be Result<String, reqwest::Error>, as if succede you have a String back.

In route.rs file, i gives me this error.

the trait bound `fn() -> impl std::future::Future {<search::routes::get_token as actix_web::service::HttpServiceFactory>::register::get_token}: actix_web::handler::Factory<_, _, _>` is not satisfied
the trait `actix_web::handler::Factory<_, _, _>` is not implemented for `fn() -> impl std::future::Future {<search::routes::get_token as actix_web::service::HttpServiceFactory>::register::get_token}`rustc(E0277)

route.rs

#[get("/token")]
async fn get_token() -> Result<std::string::String, reqwest::Error> {
    let set_token = common::authenticate(); 
    return set_token;
}

And still I have an error with headers.

mismatched types
expected struct `search::routes::reqwest::header::HeaderMap`, found struct `hyper::header::Headers`
note: expected struct `search::routes::reqwest::header::HeaderMap`
         found struct `hyper::header::Headers`rustc(E0308)

I already answer about the headers:

yh , I saw it. But, I couldnt find it..

I'm sorry, what you couldn't find?

You can fix the Headers issue by using the proper type: the reqwest HeaderMap or by using the RequestBuilder method on authentication.

Of course you cannot use the types from hyper crate.

Link to HeaderMap doc:
https://docs.rs/reqwest/0.10.4/reqwest/header/struct.HeaderMap.html

Link to RequestBuilder doc: https://docs.rs/reqwest/0.10.4/reqwest/struct.RequestBuilder.html

I used HeaderMap like below.

extern crate reqwest;
use reqwest::header::HeaderMap;
use reqwest::header::AUTHORIZATION;
use reqwest::header::CONTENT_TYPE;

pub async fn authenticate() -> Result<String, reqwest::Error> {

    fn construct_headers() -> HeaderMap {
        let mut headers = HeaderMap::new();

        headers.insert(AUTHORIZATION, "Basic bghythjuikyt==".parse().unwrap());
        headers.insert(CONTENT_TYPE, "application/x-www-form-urlencoded".parse().unwrap());

        assert!(headers.contains_key(AUTHORIZATION));
        assert!(!headers.contains_key(CONTENT_TYPE));

        headers
    }

    let client = reqwest::Client::new();

    let reszr = client.post("https://api.test.com/auth/token")
    .headers(construct_headers())
    .body("grant_type=client_credentials")
        .send()
        .await?
        .text()
        .await;

        return reszr;
}

And like before again errors.

error[E0277]: the trait bound `fn() -> impl std::future::Future {<search::routes::get_token as actix_web::service::HttpServiceFactory>::register::get_token}: actix_web::handler::Factory<_, _, _>` is not satisfied
  --> src\search\routes.rs:20:10
   |
20 | async fn get_token() -> Result<std::string::String, reqwest::Error> {
   |          ^^^^^^^^^ the trait `actix_web::handler::Factory<_, _, _>` is not implemented for `fn() -> impl std::future::Future {<search::routes::get_token as actix_web::service::HttpServiceFactory>::register::get_token}`