Skip to content

Commit

Permalink
feat: add interceptor page
Browse files Browse the repository at this point in the history
Closes: #18
  • Loading branch information
Romakita committed Apr 16, 2024
1 parent 0f3bf39 commit 8a66c2c
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 0 deletions.
53 changes: 53 additions & 0 deletions docs/docs/interceptors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Interceptors

An interceptor is a class annotated with the @@Interceptor@@ decorator. Interceptors should implement the @@InterceptorMethods@@ interface.

Interceptors have a set of useful capabilities which are inspired by the [Aspect Oriented Programming](https://en.wikipedia.org/wiki/Aspect-oriented_programming) (AOP) technique.

Creating and consuming an interceptor is a two-step process:

1. Create and annotate the interceptor class that will intercept calls to service methods
2. Decide which methods will be **intercepted** by which **interceptor**

They make it possible to:

- bind extra logic before/after method execution
- transform the result returned from a function
- transform the exception thrown from a function
- extend the basic function's behavior
- completely override a function depending on specific conditions

## Decorators

<ApiList query="module == '@tsed/di' && symbolType === 'decorator'" />

## Interceptor class

To create an interceptor class you need to implement the @@InterceptorMethods@@ interface and implement the
`intercept(context: InterceptorContext<any>, next?: InterceptorNext)` method, and use the `@Interceptor()` annotation to register your interceptor class.

Inside your `src/interceptors/MyInterceptor.ts` file, create the following simple interceptor.

<<< @/docs/snippets/interceptors/interceptor-example.ts

## Use the interceptor

Now that your interceptor logic is in place, you can use it in any other service. You need to use the `@Intercept(InterceptorClass, opts)` annotation to register which interceptor should be used for the specific method you want to intercept.
An example service in `src/services/MyService.ts`:

<<< @/docs/snippets/interceptors/interceptor-usage.ts

If the service method is executed like `myServiceInstance.mySimpleMethod()` we will get the following output:

```bash
the method mySimpleMethod will be executed with args and static data simple data
the simple method is executed
the method was executed, and returned undefined
```

## Catch error with Interceptor

You can also catch errors with an interceptor.
To do this, you need to implement the `intercept` method in your interceptor class:

<<< @/docs/snippets/interceptors/interceptor-catch-error.ts
21 changes: 21 additions & 0 deletions docs/docs/snippets/interceptors/interceptor-example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {InterceptorMethods, InterceptorContext, InterceptorNext, Interceptor} from "@tsed/di";

@Interceptor()
export class MyInterceptor implements InterceptorMethods {
/**
* ctx: The context that holds the dynamic data related to the method execution and the proceed method
* to proceed with the original method execution
*
* opts: Static params that can be provided when the interceptor is attached to a specific method
*/
async intercept(context: InterceptorContext<any>, next: InterceptorNext) {
console.log(`the method ${context.propertyKey} will be executed with args ${context.args} and static data ${context.options}`);
// let the original method by calling next function
const result = await next();

console.log(`the method was executed, and returned ${result}`);

// must return the returned value back to the caller
return result;
}
}
25 changes: 25 additions & 0 deletions docs/docs/snippets/interceptors/interceptor-usage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {Intercept, Injectable} from "@tsed/di";
import {MyInterceptor} from "../interceptors/MyInterceptor";

@Injectable()
export class MyService {
// MyInterceptor is going to be used to intercept this method whenever called
// 'simple data' is static data that will be passed as second arg to the interceptor.intercept method
@Intercept(MyInterceptor, "simple data")
mySimpleMethod() {
console.log("the simple method is executed");
}
}

// on class
@Injectable()
@Intercept(MyInterceptor, "simple data")
export class MyService2 {
mySimpleMethod1() {
console.log("the simple method is executed");
}

mySimpleMethod2() {
console.log("the simple method is executed");
}
}

0 comments on commit 8a66c2c

Please sign in to comment.