pub trait ServiceBuilderExt<L>: Sized {
// Required methods
fn buffered<Request>(self) -> ServiceBuilder<Stack<BufferLayer<Request>, L>>;
fn layer<T>(self, layer: T) -> ServiceBuilder<Stack<T, L>>;
// Provided methods
fn checkpoint<S, Request>(
self,
checkpoint_fn: impl Fn(Request) -> Result<ControlFlow<<S as Service<Request>>::Response, Request>, <S as Service<Request>>::Error> + Send + Sync + 'static,
) -> ServiceBuilder<Stack<CheckpointLayer<S, Request>, L>>
where S: Service<Request> + Send + 'static,
Request: Send + 'static,
S::Future: Send,
S::Response: Send + 'static,
S::Error: Into<BoxError> + Send + 'static { ... }
fn checkpoint_async<F, S, Fut, Request>(
self,
async_checkpoint_fn: F,
) -> ServiceBuilder<Stack<AsyncCheckpointLayer<S, Fut, Request>, L>>
where S: Service<Request, Error = BoxError> + Clone + Send + 'static,
Fut: Future<Output = Result<ControlFlow<<S as Service<Request>>::Response, Request>, BoxError>>,
F: Fn(Request) -> Fut + Send + Sync + 'static { ... }
fn instrument<F, Request>(
self,
span_fn: F,
) -> ServiceBuilder<Stack<InstrumentLayer<F, Request>, L>>
where F: Fn(&Request) -> Span { ... }
fn map_first_graphql_response<Callback>(
self,
callback: Callback,
) -> ServiceBuilder<Stack<MapFirstGraphqlResponseLayer<Callback>, L>>
where Callback: FnOnce(Context, Parts, Response) -> (Parts, Response) + Clone + Send + 'static { ... }
fn map_future_with_request_data<RF, MF>(
self,
req_fn: RF,
map_fn: MF,
) -> ServiceBuilder<Stack<MapFutureWithRequestDataLayer<RF, MF>, L>> { ... }
}
Expand description
Extension to the ServiceBuilder
trait to make it easy to add router specific capabilities
(e.g.: checkpoints) to a Service
.
Required Methods§
Sourcefn buffered<Request>(self) -> ServiceBuilder<Stack<BufferLayer<Request>, L>>
fn buffered<Request>(self) -> ServiceBuilder<Stack<BufferLayer<Request>, L>>
Adds a buffer to the service stack with a default size.
This is useful for making services Clone
and Send
§Examples
let _ = ServiceBuilder::new()
.buffered()
.service(service);
Sourcefn layer<T>(self, layer: T) -> ServiceBuilder<Stack<T, L>>
fn layer<T>(self, layer: T) -> ServiceBuilder<Stack<T, L>>
Utility function to allow us to specify default methods on this trait rather than duplicating in the impl.
§Arguments
layer
: The layer to add to the service stack.
returns: ServiceBuilder<Stack<T, L>>
Provided Methods§
Sourcefn checkpoint<S, Request>(
self,
checkpoint_fn: impl Fn(Request) -> Result<ControlFlow<<S as Service<Request>>::Response, Request>, <S as Service<Request>>::Error> + Send + Sync + 'static,
) -> ServiceBuilder<Stack<CheckpointLayer<S, Request>, L>>
fn checkpoint<S, Request>( self, checkpoint_fn: impl Fn(Request) -> Result<ControlFlow<<S as Service<Request>>::Response, Request>, <S as Service<Request>>::Error> + Send + Sync + 'static, ) -> ServiceBuilder<Stack<CheckpointLayer<S, Request>, L>>
Decide if processing should continue or not, and if not allow returning of a response.
This is useful for validation functionality where you want to abort processing but return a valid response.
§Arguments
checkpoint_fn
: Ths callback to decides if processing should continue or not.
returns: ServiceBuilder<Stack<CheckpointLayer<S, Request>, L>>
§Examples
let _ = ServiceBuilder::new()
.checkpoint(|req: supergraph::Request|{
if req.supergraph_request.method() == Method::GET {
Ok(ControlFlow::Break(supergraph::Response::builder()
.data("Only get requests allowed")
.context(req.context)
.build()?))
} else {
Ok(ControlFlow::Continue(req))
}
})
.service(service);
Sourcefn checkpoint_async<F, S, Fut, Request>(
self,
async_checkpoint_fn: F,
) -> ServiceBuilder<Stack<AsyncCheckpointLayer<S, Fut, Request>, L>>
fn checkpoint_async<F, S, Fut, Request>( self, async_checkpoint_fn: F, ) -> ServiceBuilder<Stack<AsyncCheckpointLayer<S, Fut, Request>, L>>
Decide if processing should continue or not, and if not allow returning of a response.
Unlike checkpoint it is possible to perform async operations in the callback. However
this requires that the service is Clone
. This can be achieved using .buffered()
.
This is useful for things like authentication where you need to make an external call to check if a request should proceed or not.
§Arguments
async_checkpoint_fn
: The asynchronous callback to decide if processing should continue or not.
returns: ServiceBuilder<Stack<AsyncCheckpointLayer<S, Request>, L>>
§Examples
use futures::FutureExt;
let _ = ServiceBuilder::new()
.checkpoint_async(|req: supergraph::Request|
async {
if req.supergraph_request.method() == Method::GET {
Ok(ControlFlow::Break(supergraph::Response::builder()
.data("Only get requests allowed")
.context(req.context)
.build()?))
} else {
Ok(ControlFlow::Continue(req))
}
}
.boxed()
)
.buffered()
.service(service);
Sourcefn instrument<F, Request>(
self,
span_fn: F,
) -> ServiceBuilder<Stack<InstrumentLayer<F, Request>, L>>
fn instrument<F, Request>( self, span_fn: F, ) -> ServiceBuilder<Stack<InstrumentLayer<F, Request>, L>>
Place a span around the request.
This is useful for adding a new span with custom attributes to tracing.
Note that it is not possible to add extra attributes to existing spans. However, you can add empty placeholder attributes to your span if you want to supply those attributes later.
§Arguments
span_fn
: The callback to create the span given the request.
returns: ServiceBuilder<Stack<InstrumentLayer<F, Request>, L>>
§Examples
let instrumented = ServiceBuilder::new()
.instrument(|_request| info_span!("query_planning"))
.service(service);
Sourcefn map_first_graphql_response<Callback>(
self,
callback: Callback,
) -> ServiceBuilder<Stack<MapFirstGraphqlResponseLayer<Callback>, L>>
fn map_first_graphql_response<Callback>( self, callback: Callback, ) -> ServiceBuilder<Stack<MapFirstGraphqlResponseLayer<Callback>, L>>
Maps HTTP parts, as well as the first GraphQL response, to different values.
In supergraph and execution services, the service response contains
not just one GraphQL response but a stream of them,
in order to support features such as @defer
.
This method wraps a service and calls a callback
when the first GraphQL response
in the stream returned by the inner service becomes available.
The callback can then access the HTTP parts (headers, status code, etc)
or the first GraphQL response before returning them.
Note that any subsequent GraphQLÂ responses after the first will be forwarded unmodified.
In order to inspect or modify all GraphQL responses,
consider using map_response
together with supergraph::Response::map_stream
instead.
(See the example in map_stream
’s documentation.)
In that case however HTTP parts cannot be modified because they may have already been sent.
§Example
use apollo_router::services::supergraph;
use apollo_router::layers::ServiceBuilderExt as _;
use tower::ServiceExt as _;
struct ExamplePlugin;
#[async_trait::async_trait]
impl apollo_router::plugin::Plugin for ExamplePlugin {
// …
fn supergraph_service(&self, inner: supergraph::BoxService) -> supergraph::BoxService {
tower::ServiceBuilder::new()
.map_first_graphql_response(|context, mut http_parts, mut graphql_response| {
// Something interesting here
(http_parts, graphql_response)
})
.service(inner)
.boxed()
}
}
Sourcefn map_future_with_request_data<RF, MF>(
self,
req_fn: RF,
map_fn: MF,
) -> ServiceBuilder<Stack<MapFutureWithRequestDataLayer<RF, MF>, L>>
fn map_future_with_request_data<RF, MF>( self, req_fn: RF, map_fn: MF, ) -> ServiceBuilder<Stack<MapFutureWithRequestDataLayer<RF, MF>, L>>
Similar to map_future but also providing an opportunity to extract information out of the request for use when constructing the response.
§Arguments
req_fn
: The callback to extract data from the request.map_fn
: The callback to map the future.
returns: ServiceBuilder<Stack<MapFutureWithRequestDataLayer<RF, MF>, L>>
§Examples
let _ : supergraph::BoxService = ServiceBuilder::new()
.map_future_with_request_data(
|req: &supergraph::Request| req.context.clone(),
|ctx : Context, fut| async { fut.await })
.service(service)
.boxed();
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.