Interceptors
Interceptors play a crucial role in the RESTHeart framework, allowing developers to observe and modify requests and responses throughout the request lifecycle. This document provides an overview of the Interceptor class, available interceptor interfaces, and usage examples.
The Interceptor Class
An Interceptor
is comprised of a class implementing one of the Interceptor
interfaces, such as MongoInterceptor
, and annotated with @RegisterPlugin
.
The Interceptor
interface encompasses two pivotal methods: handle(req, res)
and resolve(req, res)
. The paramount method is handle(req, res)
, which is triggered only when resolve(req, res)
evaluates to true
. This design ensures that the interceptor’s logic is selectively applied, allowing developers to execute customized actions precisely when conditions specified in the resolve()
method are met.
The req
and res
arguments allow you to retrieve and modify the content, query parameters, and headers of both the request and response objects.
The special interceptor interface, WildcardInterceptor
, intercepts requests handled by any Service
. Other interceptors can handle requests with matching types between the Service and the Interceptor:
-
WildcardInterceptor
: Intercepts requests handled by any service -
ByteArrayInterceptor
: Intercepts requests handled by services implementingByteArrayService
-
JsonInterceptor
: Intercepts requests handled by services implementingJsonService
-
BsonInterceptor
: Intercepts requests handled by services implementingBsonService
-
MongoInterceptor
: Intercepts requests handled by theMongoService
-
GraphQLInterceptor
: Intercepts GraphQL requests -
ProxyInterceptor
: Intercepts proxied requests
Note
|
MongoInterceptor is particularly useful as it allows intercepting requests to the MongoService , adding logic to its data API. For instance, the following response interceptor removes the property secret from GET /coll .
|
@RegisterPlugin(name = "secretFilter",
interceptPoint = InterceptPoint.RESPONSE,
description = "removes the property 'secret' from GET /coll")
public class ReadOnlyPropFilter implements MongoInterceptor {
@Override
public void handle(MongoRequest request, MongoResponse response) throws Exception {
if (response.getContent().isDocument()) {
response.getContent().asDocument().remove("secret");
} else if (request.getContent().isArray()) {
response.getContent().asArray().stream()
.map(doc -> doc.asDocument())
.forEach(doc -> doc.remove("secret"));
}
}
@Override
public boolean resolve(MongoRequest request, MongoResponse response) {
return request.isGet()
&& response.getContent() != null
&& "coll".equalsIgnoreCase(request.getCollectionName());
}
}
Tip
|
Watch Interceptors |
@RegisterPlugin Annotation
All plugins, including Interceptors
, must be annotated with @RegisterPlugin
. This annotation serves two primary purposes:
-
Discovery: Allows RESTHeart to discover plugin implementation classes in deployed JARs (see How to Deploy Plugins).
-
Configuration: Specifies parameters such as the URI of a service or the intercept point of an interceptor.
Example:
@RegisterPlugin(name = "foo",
description = "just an example service",
defaultUri="/foo", // optional, default /<service-name>
secure=false, // optional, default false
enabledByDefault=false) // optional, default true
public class MyPlugin implements JsonService {
...
}
Annotation Parameters:
param | description | mandatory | default value |
---|---|---|---|
|
the name of the Interceptor |
yes |
none |
|
description of the Interceptor |
yes |
none |
|
|
no |
|
|
the intercept point: |
no |
|
|
Only used by Interceptors of proxied resources (the content is always available to Interceptor of Services) Set it to |
no |
|
|
the execution priority (less is higher priority) |
no |
|
Intercept Point Note: REQUEST_BEFORE_EXCHANGE_INIT
An interceptor using this intercept point will handle requests before the exchange initialization occurs. Such interceptors must implement the WildcardInterceptor
interface, ensuring that the Interceptor.handle(request, response)
method receives both UninitializedRequest
and UninitializedResponse
objects.
Additionally, interceptors at this stage may:
-
Provide a custom initializer for requests by using
PluginUtils.attachCustomRequestInitializer()
. -
Modify the raw content of the request using
Request.setRawContent()
.
This setup allows for preliminary modifications and configurations to be applied to requests at an early stage in the processing pipeline.
Transforming Request Content Format
Interceptors at REQUEST_BEFORE_EXCHANGE_INIT
can inspect and modify the request before it is initialized. The handle(req, res)
and resolve(req, res)
methods receive the request as UninitializedRequest
and the response as UninitializedResponse
. This is particularly useful for transforming request content formats.
Example:
@RegisterPlugin(name = "xmlToBsonTransformer",
interceptPoint = InterceptPoint.REQUEST_BEFORE_EXCHANGE_INIT,
description = "transforms XML request to Bson for MongoService")
public class XmlToBsonTransformer implements WildcardInterceptor {
@Override
public void handle(UninitializedRequest req, UninitializedResponse res) throws Exception {
// Transforming XML to Bson
}
@Override
public boolean resolve(UninitializedRequest req, UninitializedResponse res) {
// Logic to determine when to apply the transformer
}
}
Important
|
Only WildcardInterceptor can use the REQUEST_BEFORE_EXCHANGE_INIT intercept point.
|
For a practical example of transforming request and response content to and from a different format than expected by a service, refer to the protobuffer-contacts example.