Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

18 interceptors #31

Merged
merged 2 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
2 changes: 1 addition & 1 deletion docs/docs/pipes.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Pipes

A pipe is a class annotated with the @@Injectable@@ decorator.
Pipes should implement the @@IPipe@@ interface.
Pipes should implement the @@PipeMethods@@ interface.

Pipes have two typical use cases:

Expand Down
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");
}
}
Loading