As mentioned earlier interceptors are function. They will be called with some parameters and can return their modified values.
To better demonstrate it, let’s create each type of interceptor as examples.
Suppose we want to create a request interceptor with these requirements
Content-Type header to application/json value if the body is a plain object and called with POST HTTP method.Accept headers as application/json for all requests.
|
|
Some important points from above example
frest is the Frest instance which call this interceptorrequest is the original request state before it enters this interceptor TODOPromiseresolve the Promise with new request configuration. We can also resolve it to the original request, which means there is no modification to the request.What’s the implication if we use this interceptor?
stringify request body to JSON string in every requestNow we’ll look at how to create a response interceptor. We’ll use the same case around json like the request interceptor part.
Content-Type is compatible with application/jsonfetch Response bodyUsed is false.
|
|
Some important points from above example
frest same as request interceptorrequest same as request interceptorresponse the Frest responsePromise.response is an object which contains properties:
origin the original fetch Response instancebody parsed value of the response body. It’s response interceptor which will fill this value.fetch Response instance as origin property. The body value is the parsed JSON response.What’s the implication if we use this interceptor?
Response.bodyIn Frest any non OK response (status outside 2xx) will result in a thrown error. This is useful so we can have a common place to check for error (instead of checking ok property in fetch response).
Let’s look at how we implement error interceptor. Since we have created request and response interceptor to deal with JSON data, we’ll also create an interceptor to parse non OK response, if any. The tasks are
Content-Type is compatible with application/json
|
|
Some important points from above example
FrestErrorPromiseFrestError instance will have these properties
frest same as other interceptorrequest same as other interceptorresponse same as response interceptorresponse property can be undefined, if the error happened before the request is sentbodyUsed if we want to parse the response bodyIf we want to recover from an error, instead of rejecting the returned promise, we can resolve it with another response. Suppose we want to make another request to retry with different config
|
|
In above example, frest an request are the properties of FrestError
in the interceptor arg. They refer to the same Frest instance
and request config when we make the request. If the retry request is
successful, Frest will recover with the resulting response
and the error will not be thrown.
Those 3 interceptor type examples above are already implemented in the official frest-json package. Check out the documentation of how to use it.
We can add/remove interceptors to Frest instance using either
configuration in constructor or calling add[Type]Interceptor and
remove[Type]Interceptor method.
To add them when creating Frest instance:
|
|
To add/remove them using methods of Frest instance:
|
|
By convention, interceptors should have a unique identifier, assigned
in the function itself (see above examples of creating interceptors).
So we can also remove an interceptor using its id.
Suppose we want to remove jsonRequestInterceptor created in example above, we can do it like so
|
|
As we can see in ways of adding interceptors above, the interceptors are stored as array depending on their type. When there are multiple interceptors with the same type, they’ll be executed in the order of when they’re added.
|
|
In above example, interceptor1 will be called first.
The returned request, if any, from interceptor1 will be passed down to interceptor2. It’s the same way with interceptor3.
This is why we must always check the bodyUsed property of fetch Response, in the case of response interceptor. The body could have been
used/read in other response interceptor, by the time it arrives in our interceptor.