Impl Trait argument for surf client

Hi all

I have the following below

/// Slack WEB API Client.
#[cfg_attr(test, automock)]
#[async_trait]
pub trait SlackWebAPIClient: Sync + Send {
    async fn post_json(&self, url: &str, body: &str, token: &str) -> Result<String, Error>;
    async fn post(&self, url: &str, token: &str) -> Result<String, Error>;
    async fn get(&self, url: &str, query: &str, token: &str) -> Result<String, Error>;
}

/// HTTP Client(surf::Client).
pub type Client = surf::Client;

#[async_trait]
impl SlackWebAPIClient for Client {
    /// Send a post request including the body to the slack web api.
    async fn post_json(&self, url: &str, body: &str, token: &str) -> Result<String, Error> {
        let check_url = url::Url::parse(url)?;

        Ok(self
            .post(check_url)
            .header("Authorization", format!("Bearer {}", token))
            .header("Content-type", "application/json; charset=utf-8")
            .body(body)
            .await?
            .body_string()
            .await?)
    }
    /// Send a post request to the slack web api.
    async fn post(&self, url: &str, token: &str) -> Result<String, Error> {
        let check_url = url::Url::parse(url)?;

        Ok(self
            .post(check_url)
            .header("Authorization", format!("Bearer {}", token))
            .await?
            .body_string()
            .await?)
    }
    /// Send a get request to the slack web api.
    async fn get(&self, url: &str, query: &str, token: &str) -> Result<String, Error> {
        let check_url = url::Url::parse(url)?;

        Ok(self
            .get(check_url)
            .header("Authorization", format!("Bearer {}", token))
            .query(&query)?
            .await?
            .body_string()
            .await?)
    }
}

where I like to change the definition of the query parameter to exactly like in the surf library

    pub fn query(mut self, query: &impl Serialize) -> std::result::Result<Self, Error> {
        self.req.as_mut().unwrap().set_query(query)?;

        Ok(self)
    }

But it looks like I cant add a trait within a trait

hope to get some help on this

thanks

I am not entirely sure what you are trying to do. If you want to add a function to the impl SlackWebAPIClient for Client then you need to also add the function to the SlackWebAPIClient trait.

However, the client type from the surf library probably creates and returns a request-building object which can be modified before making the actual request. Your trait implementation would mix the client and request-building objects into 1 thing making your client stateful.

If you can explain what you're trying to do and why, we might be able to help you better.

@mickvangelderen
The current implementation is
as you can see parameter query is of type &str

async fn get(&self, url: &str, query: &str, token: &str) -> Result<String, Error>;

I want to convert it to

async fn get(&self, url: &str, query: &impl Serialize, token: &str) -> Result<String, Error>;

just like the definition in surf

    pub fn query(mut self, query: &impl Serialize) -> std::result::Result<Self, Error> {
        self.req.as_mut().unwrap().set_query(query)?;

        Ok(self)
    }

but I cant do that because its trait in trait

There's nothing wrong with that. It might be that async_trait doesn't support argument-position impl Trait. Did you try using an explicit generic parameter instead?

Hi @H2CO3

yes I did tried it but got this error from my diagnostic

Diagnostics:
1. future cannot be sent between threads safely
   required for the cast from `[async block@slack/src/http_client.rs:49:99: 59:6]` to the object type `dyn futures_util::Future<Output = Result<std::string::String, error::Error>> + std::marker::Send`
2. consider further restricting this bound: ` + std::marker::Sync`

Updated code

#[cfg_attr(test, automock)]
#[async_trait]
pub trait SlackWebAPIClient: Sync + Send {
    async fn post_json(&self, url: &str, body: &str, token: &str) -> Result<String, Error>;
    async fn post(&self, url: &str, token: &str) -> Result<String, Error>;
    async fn get<T: Serialize>(&self, url: &str, query: &T, token: &str) -> Result<String, Error>;
}

/// HTTP Client(surf::Client).
pub type Client = surf::Client;

#[async_trait]
impl SlackWebAPIClient for Client {
    /// Send a post request including the body to the slack web api.
    async fn post_json(&self, url: &str, body: &str, token: &str) -> Result<String, Error> {
        let check_url = url::Url::parse(url)?;

        Ok(self
            .post(check_url)
            .header("Authorization", format!("Bearer {}", token))
            .header("Content-type", "application/json; charset=utf-8")
            .body(body)
            .await?
            .body_string()
            .await?)
    }
    /// Send a post request to the slack web api.
    async fn post(&self, url: &str, token: &str) -> Result<String, Error> {
        let check_url = url::Url::parse(url)?;

        Ok(self
            .post(check_url)
            .header("Authorization", format!("Bearer {}", token))
            .await?
            .body_string()
            .await?)
    }
    /// Send a get request to the slack web api.
    async fn get<T: Serialize>(&self, url: &str, query: &T, token: &str) -> Result<String, Error> {
        let check_url = url::Url::parse(url)?;

        Ok(self
            .get(check_url)
            .header("Authorization", format!("Bearer {}", token))
            .query(&query)?
            .await?
            .body_string()
            .await?)
    }
}

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.