ServiceBuilderExt

Trait ServiceBuilderExt 

Source
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§

Source

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);
Source

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§

Source

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,

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);
Source

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,

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);
Source

fn instrument<F, Request>( self, span_fn: F, ) -> ServiceBuilder<Stack<InstrumentLayer<F, Request>, L>>
where F: Fn(&Request) -> Span,

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);
Source

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,

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()
    }
}
Source

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.

Implementations on Foreign Types§

Source§

impl<L> ServiceBuilderExt<L> for ServiceBuilder<L>

Source§

fn layer<T>(self, layer: T) -> ServiceBuilder<Stack<T, L>>

Source§

fn buffered<Request>(self) -> ServiceBuilder<Stack<BufferLayer<Request>, L>>

Implementors§