JavaScript Interceptors
RESTHeartAn interceptor
An interceptor runs on the requests of other services, before or after they are handled, to observe or change the request or the response. The module exports it as its default export, declared with defineInterceptor:
import { defineInterceptor } from "restheart:sdk";
export default defineInterceptor({
name: "helloWorldInterceptor",
description: "modifies the response of helloWorldService",
interceptPoint: "RESPONSE",
contentKind: "json",
handle(req, res) {
res.content = { ...res.content, note: "modified by helloWorldInterceptor" };
},
resolve(req, res) {
return req.isHandledBy("helloWorldService") && req.isGet();
},
});
The module file goes in rh:interceptors of package.json, see Packaging.
| property | description | mandatory | default |
|---|---|---|---|
|
the name of the interceptor; also the name of its section in |
yes |
|
|
what it does |
yes |
|
|
when it runs, see below |
no |
|
|
which requests it sees and how their bodies are typed, see below |
no |
|
|
what it does, when |
yes |
|
|
whether to run |
yes |
req and res are the same objects a service gets, with the same members. In a request interceptor req.content and req.headers are assignable; in a response interceptor res.content, res.statusCode and res.headers are.
Intercept points
| intercept point | when |
|---|---|
|
before the request content is parsed; |
|
before authentication; |
|
after authentication and authorization, before the service; the default |
|
after the service, before the response is sent |
|
after the response is sent, in a separate thread; for what must not add to the latency |
See the request lifecycle for where each point sits in the pipeline.
contentKind
An interceptor runs on the requests of the services with the same content kind: a json interceptor sees the requests handled by JsonService plugins, a string one those of StringService plugins. Two kinds exist for interceptors only:
| kind | requests |
|---|---|
|
the requests handled by the MongoDB service, the REST API on collections and documents. |
|
the requests handled by the csv loader ( |
A mongo interceptor is how the data API is extended: a field added to every document on the way out, a timestamp added on the way in, a check on what is being written.
req.mongo
For contentKind: "mongo", req.mongo exposes the MongoDB part of the request, a curated subset of the Java MongoRequest:
| member | value |
|---|---|
|
the database and the collection of the request |
|
the document id as native data: |
|
the |
|
the pagination |
|
what the request addresses |
|
the Java |
import { defineInterceptor, bson } from "restheart:sdk";
// adds a field to the document of GET /coll/<docid>
export default defineInterceptor({
name: "mongoGetDocInterceptor",
description: "modifies the response of GET /coll/<docid>",
interceptPoint: "RESPONSE",
contentKind: "mongo",
handle(req, res) {
res.content = { ...res.content, id: bson.oid(req.mongo.documentId), injected: true };
},
resolve(req, res) {
return req.isGet() && req.mongo.isDocument() && req.mongo.collectionName === "coll";
},
});
import { defineInterceptor } from "restheart:sdk";
// adds a timestamp to the document of POST /coll; a native Date is written as a BSON date
export default defineInterceptor({
name: "mongoPostCollInterceptor",
description: "modifies the content of POST requests adding a timestamp",
interceptPoint: "REQUEST_AFTER_AUTH",
contentKind: "mongo",
handle(req, res) {
req.content = { ...req.content, timestamp: new Date() };
},
resolve(req, res) {
return req.isPost() && req.mongo.collectionName === "coll";
},
});
Errors
The rules of services apply: a typed error thrown by handle is answered with its status and stops the request, any other exception is a 500 logged with the interceptor name. An exception in resolve is logged and the request is set in error.
Interceptors written before 9.14.0
An interceptor that exports options, handle and resolve, with pluginClass naming the Java interceptor class, keeps working unchanged and receives the Java request and response. pluginClass is deprecated in favour of contentKind:
pluginClass |
contentKind |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|