You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An interceptor is a class annotated with the `@injectable()` decorator and implements the EllarInterceptor interface.
4
+
During request-response cycle, interceptors are called after middleware execution before route handler execution.
5
+
6
+
Interceptors have a set of useful capabilities which are inspired by the [Aspect Oriented Programming (AOP) technique](https://en.wikipedia.org/wiki/Aspect-oriented_programming){target="_blank"} technique.
7
+
They make it possible to:
8
+
9
+
- bind extra logic before / after method execution
10
+
- transform the result returned from a function
11
+
- transform the exception thrown from a function
12
+
- extend the basic function behavior
13
+
- completely override a function depending on specific conditions (e.g., for caching purposes)
14
+
15
+
## **Basic**
16
+
Each interceptor implements the `intercept()` method, which takes two arguments.
17
+
The first one is the `ExecutionContext` instance (exactly the same object as for [guards](./guards)) and
18
+
`next_interceptor` awaitable function that executes the next interceptor in the execution chain.
`intercept` function of interceptor class is an asynchronous function.
35
+
36
+
## **Execution context**
37
+
The `ExecutionContext` adds several new helper methods that provide additional details about the current execution process.
38
+
These details can be helpful in building more generic interceptors that can work across a broad set of controllers, methods, and execution contexts.
39
+
Learn more about `ExecutionContext`[here](../basics/execution-context).
40
+
41
+
## **Next Interceptor Handler**
42
+
The second argument, `next_interceptor`, in `intercept` of EllarInterceptor class is used to invoke the route handler method at some point in your interceptor.
43
+
If you don't call the `next_interceptor` method in your implementation of the `intercept()` method, the route handler method won't be executed at all.
44
+
45
+
This approach means that the `intercept()` method effectively wraps the request/response cycle.
46
+
As a result, you may implement custom logic **both before and after** the execution of the final route handler.
47
+
It's clear that you can write code in your `intercept()` method that executes before calling `next_interceptor()`,
48
+
but how do you affect what happens afterward? depending on the nature of the data returned by `next_interceptor()`,
49
+
further manipulation can be done before final response to the client.
50
+
51
+
Using Aspect Oriented Programming terminology, the invocation of the route handler
52
+
(i.e., calling `next_interceptor()`) is called a Pointcut, indicating that it's the point at which our
53
+
additional logic is inserted.
54
+
55
+
Consider, for example, an incoming `POST /car` request. This request is destined for the `create()` handler
56
+
defined inside the `CarController`. If an interceptor which does not call the `next_interceptor()`
57
+
method is called anywhere along the way, the `create()` method won't be executed.
58
+
Once `next_interceptor()` is called, the `create()` handler will be triggered. And once the response is returned,
59
+
additional operations can be performed on the data returned, and a final result returned to the client.
60
+
61
+
62
+
## **Aspect interception**
63
+
The first use case we'll look at is to use an interceptor to log user interaction (e.g., storing user calls, asynchronously dispatching events or calculating a timestamp).
64
+
We show a simple LoggingInterceptor below:
65
+
66
+
```python
67
+
import typing as t
68
+
import logging
69
+
import time
70
+
from ellar.common import EllarInterceptor, IExecutionContext
Interceptors, like controllers, providers, guards, and so on, can inject dependencies through their `constructor`.
92
+
93
+
## **Binding interceptors**
94
+
In order to set up the interceptor, we use the `@UseInterceptors()` decorator imported from the `ellar.common` package.
95
+
Like **guards**, interceptors can be controller-scoped, method-scoped, or global-scoped.
96
+
97
+
```python
98
+
from ellar.common import UseInterceptors, Controller
99
+
100
+
@UseInterceptors(LoggingInterceptor)
101
+
@Controller()
102
+
classCarController:
103
+
...
104
+
```
105
+
106
+
Note that we passed the LoggingInterceptor type (instead of an instance), leaving responsibility for instantiation to the framework and enabling dependency injection.
107
+
As with guards, we can also pass an in-place instance:
108
+
109
+
```python
110
+
from ellar.common import UseInterceptors, Controller
111
+
112
+
@UseInterceptors(LoggingInterceptor())
113
+
@Controller()
114
+
classCarController:
115
+
...
116
+
```
117
+
118
+
As mentioned, the construction above attaches the interceptor to every handler declared by this controller.
119
+
If we want to restrict the interceptor's scope to a single method, we simply apply the decorator at the method level.
120
+
121
+
In order to set up a global interceptor, we use the use_global_interceptors() method of the Ellar application instance:
0 commit comments