#[conjure_endpoints]Expand description
Creates a Conjure service type wrapping types implementing the annotated trait.
For a trait named MyService, the macro will create a type named MyServiceEndpoints which
implements the conjure Service trait.
The attribute has a parameter:
name- The value returned from theEndpointMetadata::service_namemethod. Defaults to the trait name.
§Parameters
The trait can optionally be declared generic over the request body and response writer types by
using the #[request_body] and #[response_writer] 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 returned from theEndpointMetadata::namemethod. Defaults to the method name.produces- A type implementingSerializeResponsewhich will be used to convert the value returned by the method into a response. Defaults toEmptyResponseSerializer.
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.decoder- A type implementingDecodeParamwhich will be used to decode the value. Defaults toFromStrDecoder.safe- If set, the parameter will be added to theSafeParamsresponse extension.log_as- The name of the parameter used in request logging and error reporting. Defaults to the argument name.
-
#[query]- A query parameter.Parameters:
name- The string used as the key in the encoded URI. Required.decoder- A type implementingDecodeParamwhich will be used to decode the value. Defaults toFromStrDecoder.safe- If set, the parameter will be added to theSafeParamsresponse extension.log_as- The name of the parameter used in request logging and error reporting. Defaults to the argument name.
-
#[auth]- ABearerTokenused to authenticate the request.Parameters:
cookie_name- The name of the cookie if the token is to be parsed from aCookieheader. If unset, it will be parsed from anAuthorizationheader instead.
-
#[header]- A header parameter.Parameters:
name- The header name. Required.decoder- A type implementingDecodeHeaderwhich will be used to decode the value. Defaults toFromStrDecoder.safe- If set, the parameter will be added to theSafeParamsresponse extension.log_as- The name of the parameter used in request logging and error reporting. Defaults to the argument name.
-
#[body]- The request body.Parameters:
deserializer- A type implementingDeserializeRequestwhich will be used to deserialize the request body into a value. Defaults toStdRequestDeserializer.safe- If set, the parameter will be added to theSafeParamsresponse extension.log_as- The name of the parameter used in request logging and error reporting. Defaults to the argument name.
-
#[context]- ARequestContextwhich provides lower level access to the request.
§Async
Both blocking and async services are supported. For technical reasons, async method definitions
will be rewritten by the macro to require the returned future be Send.
§Examples
use conjure_error::Error;
use conjure_http::{conjure_endpoints, endpoint};
use conjure_http::server::{
ConjureRuntime, DeserializeRequest, FromStrOptionDecoder, ResponseBody, SerializeResponse,
StdResponseSerializer, WriteBody,
};
use conjure_object::BearerToken;
use http::Response;
use http::header::{CONTENT_TYPE, HeaderMap, HeaderValue};
use std::io::Write;
#[conjure_endpoints]
trait MyService {
#[endpoint(method = GET, path = "/yaks/{yak_id}", produces = StdResponseSerializer)]
fn get_yak(
&self,
#[auth] auth: BearerToken,
#[path(safe)] yak_id: i32,
) -> Result<String, Error>;
#[endpoint(method = POST, path = "/yaks")]
fn create_yak(
&self,
#[auth] auth: BearerToken,
#[query(name = "parentName", decoder = FromStrOptionDecoder)] parent_id: Option<String>,
#[body] yak: String,
) -> Result<(), Error>;
}
#[conjure_endpoints]
trait AsyncMyService {
#[endpoint(method = GET, path = "/yaks/{yak_id}", produces = StdResponseSerializer)]
async fn get_yak(
&self,
#[auth] auth: BearerToken,
#[path(safe)] yak_id: i32,
) -> Result<String, Error>;
#[endpoint(method = POST, path = "/yaks")]
async fn create_yak(
&self,
#[auth] auth: BearerToken,
#[query(name = "parentName", decoder = FromStrOptionDecoder)] parent_id: Option<String>,
#[body] yak: String,
) -> Result<(), Error>;
}
#[conjure_endpoints]
trait MyStreamingService<#[request_body] I, #[response_writer] O>
where
O: Write,
{
#[endpoint(method = POST, path = "/streamData")]
fn receive_stream(
&self,
#[body(deserializer = StreamingRequestDeserializer)] body: I,
) -> Result<(), Error>;
#[endpoint(method = GET, path = "/streamData", produces = StreamingResponseSerializer)]
fn stream_response(&self) -> Result<StreamingResponse, Error>;
}
struct StreamingRequestDeserializer;
impl<I> DeserializeRequest<I, I> for StreamingRequestDeserializer {
fn deserialize(
_runtime: &ConjureRuntime,
_headers: &HeaderMap,
body: I,
) -> Result<I, Error> {
Ok(body)
}
}
struct StreamingResponse;
impl<O> WriteBody<O> for StreamingResponse
where
O: Write,
{
fn write_body(self: Box<Self>, w: &mut O) -> Result<(), Error> {
// ...
Ok(())
}
}
struct StreamingResponseSerializer;
impl<O> SerializeResponse<StreamingResponse, O> for StreamingResponseSerializer
where
O: Write,
{
fn serialize(
_runtime: &ConjureRuntime,
_request_headers: &HeaderMap,
body: StreamingResponse,
) -> Result<Response<ResponseBody<O>>, Error> {
let mut response = Response::new(ResponseBody::Streaming(Box::new(body)));
response.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static("text/plain"));
Ok(response)
}
}