#[conjure_client]Expand description
Creates a Conjure client type implementing the annotated trait.
For a trait named MyService, the macro will create a type named MyServiceClient which
implements the Conjure Service/AsyncService and MyService traits.
The attribute has several parameters:
name- The value of theservicefield in theEndpointextension. Defaults to the trait’s name.version- The value of theversionfield in theEndpointextension. Defaults toSome(env!("CARGO_PKG_VERSION")).local- For async clients, causes the generated struct to use theLocalAsyncClientAPIs that don’t have aSendbound.
§Parameters
The trait can optionally be declared generic over the request body and response writer types by
using the #[request_writer] and #[response_body] annotations on the type parameters.
§Endpoints
Each method corresponds to a separate HTTP endpoint, and is expected to take &self and return
Result<T, Error>. Each must be annotated with #[endpoint], which has several
parameters:
method- The HTTP method (e.g.GET). Required.path- The HTTP path template. Path parameters should be identified by{name}and must make up an entire path component. Required.name- The value of thenamefield in theEndpointextension. Defaults to the method’s name.accept- A type implementingDeserializeResponsewhich will be used to create the return value. Defaults to returning().
Each method argument must have an annotation describing the type of parameter. One of:
-
#[path]- A path parameter.Parameters:
name- The name of the path template parameter. Defaults to the argument name.encoder- A type implementingEncodeParamwhich will be used to encode the value into a string. Defaults toDisplayParamEncoder.
-
#[query]- A query parameter.Parameters:
name- The string used as the key in the encoded URI. Required.encoder- A type implementingEncodeParamwhich will be used to encode the value into a string. Defaults toDisplayParamEncoder.
-
#[auth]- ABearerTokenused to authenticate the request. A method may only have at most one auth parameter.Parameters:
cookie_name- The name of the cookie used if the token is to be passed via aCookieheader. If unset, it will be passed via anAuthorizationheader instead.
-
#[header]- A header.Parameters:
name- The header name. Required.encoder- A type implementingEncodeHeaderwhich will be used to encode the value into a header. Defaults toDisplayHeaderEncoder.
-
#[body]- The request body. A method may only have at most one body parameter.Parameters:
serializer- A type implementingSerializeRequestwhich will be used to serialize the value into a body. Defaults toConjureRequestSerializer.
§Async
Both blocking and async clients are supported. For technical reasons, async method definitions
will be rewritten by the macro to require the returned future be Send unless the local flag
is set in the attribute.
§Examples
use conjure_error::Error;
use conjure_http::{conjure_client, endpoint};
use conjure_http::client::{
AsyncClient, AsyncService, Client, ConjureResponseDeserializer, DeserializeResponse,
DisplaySeqEncoder, RequestBody, SerializeRequest, Service, WriteBody,
};
use conjure_object::BearerToken;
use http::Response;
use http::header::HeaderValue;
use std::io::Write;
#[conjure_client]
trait MyService {
#[endpoint(method = GET, path = "/yaks/{yak_id}", accept = ConjureResponseDeserializer)]
fn get_yak(&self, #[auth] auth: &BearerToken, #[path] yak_id: i32) -> Result<String, Error>;
#[endpoint(method = POST, path = "/yaks")]
fn create_yak(
&self,
#[auth] auth_token: &BearerToken,
#[query(name = "parentName", encoder = DisplaySeqEncoder)] parent_id: Option<&str>,
#[body] yak: &str,
) -> Result<(), Error>;
}
fn do_work(client: impl Client, auth: &BearerToken) -> Result<(), Error> {
let client = MyServiceClient::new(client);
client.create_yak(auth, None, "my cool yak")?;
Ok(())
}
#[conjure_client]
trait MyServiceAsync {
#[endpoint(method = GET, path = "/yaks/{yak_id}", accept = ConjureResponseDeserializer)]
async fn get_yak(
&self,
#[auth] auth: &BearerToken,
#[path] yak_id: i32,
) -> Result<String, Error>;
#[endpoint(method = POST, path = "/yaks")]
async fn create_yak(
&self,
#[auth] auth_token: &BearerToken,
#[query(name = "parentName", encoder = DisplaySeqEncoder)] parent_id: Option<&str>,
#[body] yak: &str,
) -> Result<(), Error>;
}
async fn do_work_async<C>(client: C, auth: &BearerToken) -> Result<(), Error>
where
C: AsyncClient + Sync + Send,
C::ResponseBody: 'static + Send,
{
let client = MyServiceAsyncClient::new(client);
client.create_yak(auth, None, "my cool yak").await?;
Ok(())
}
#[conjure_client]
trait MyStreamingService<#[response_body] I, #[request_writer] O>
where
O: Write,
{
#[endpoint(method = POST, path = "/streamData")]
fn upload_stream(
&self,
#[body(serializer = StreamingRequestSerializer)] body: StreamingRequest,
) -> Result<(), Error>;
#[endpoint(method = GET, path = "/streamData", accept = StreamingResponseDeserializer)]
fn download_stream(&self) -> Result<I, Error>;
}
struct StreamingRequest;
impl<W> WriteBody<W> for StreamingRequest
where
W: Write,
{
fn write_body(&mut self, w: &mut W) -> Result<(), Error> {
// ...
Ok(())
}
fn reset(&mut self) -> bool {
true
}
}
enum StreamingRequestSerializer {}
impl<W> SerializeRequest<'static, StreamingRequest, W> for StreamingRequestSerializer
where
W: Write,
{
fn content_type(_: &StreamingRequest) -> HeaderValue {
HeaderValue::from_static("text/plain")
}
fn serialize(value: StreamingRequest) -> Result<RequestBody<'static, W>, Error> {
Ok(RequestBody::Streaming(Box::new(value)))
}
}
enum StreamingResponseDeserializer {}
impl<R> DeserializeResponse<R, R> for StreamingResponseDeserializer {
fn accept() -> Option<HeaderValue> {
None
}
fn deserialize(response: Response<R>) -> Result<R, Error> {
Ok(response.into_body())
}
}