From 8a66c2cd2c6c1911fdcb330cba33ae1d3dbf27be Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Tue, 16 Apr 2024 09:40:00 +0200 Subject: [PATCH] feat: add interceptor page Closes: #18 --- docs/docs/interceptors.md | 53 +++++++++++++++++++ .../interceptors/interceptor-example.ts | 21 ++++++++ .../interceptors/interceptor-usage.ts | 25 +++++++++ 3 files changed, 99 insertions(+) create mode 100644 docs/docs/snippets/interceptors/interceptor-example.ts create mode 100644 docs/docs/snippets/interceptors/interceptor-usage.ts diff --git a/docs/docs/interceptors.md b/docs/docs/interceptors.md index e69de29..4a48428 100644 --- a/docs/docs/interceptors.md +++ b/docs/docs/interceptors.md @@ -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 + + + +## Interceptor class + +To create an interceptor class you need to implement the @@InterceptorMethods@@ interface and implement the +`intercept(context: InterceptorContext, 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 diff --git a/docs/docs/snippets/interceptors/interceptor-example.ts b/docs/docs/snippets/interceptors/interceptor-example.ts new file mode 100644 index 0000000..779ef7c --- /dev/null +++ b/docs/docs/snippets/interceptors/interceptor-example.ts @@ -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, 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; + } +} diff --git a/docs/docs/snippets/interceptors/interceptor-usage.ts b/docs/docs/snippets/interceptors/interceptor-usage.ts new file mode 100644 index 0000000..a27f3d2 --- /dev/null +++ b/docs/docs/snippets/interceptors/interceptor-usage.ts @@ -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"); + } +}