diff --git a/packages/nest/README.md b/packages/nest/README.md
index 44d4b8770..c6770aeec 100644
--- a/packages/nest/README.md
+++ b/packages/nest/README.md
@@ -7,7 +7,7 @@
-OpenFeature Nest.js SDK
+OpenFeature NestJS SDK
@@ -15,7 +15,11 @@
-
+
+
+
+
+
@@ -25,11 +29,49 @@
[OpenFeature](https://openfeature.dev) is an open specification that provides a vendor-agnostic, community-driven API
for feature flagging that works with your favorite feature flag management tool.
-๐งช This SDK is experimental.
+
+
+## Overview
+
+The OpenFeature NestJS SDK is a package that provides a NestJS wrapper for the [OpenFeature Server SDK](https://openfeature.dev/docs/reference/technologies/server/javascript/).
+
+Capabilities include:
+
+- Provide a NestJS global module to simplify OpenFeature configuration and usage within NestJS;
+- Injecting feature flags directly into controller route handlers by using decorators;
+- Injecting transaction evaluation context for flag evaluations directly from [execution context](https://docs.nestjs.com/fundamentals/execution-context) (HTTP header values, client IPs, etc.);
+- Injecting OpenFeature clients into NestJS services and controllers by using decorators;
+- Setting up logging, event handling, hooks and providers directly when registering the module.
+
+## ๐ Quick start
+
+### Requirements
+
+- Node.js version 16+
+- NestJS version 8+
+
+### Install
+
+#### npm
+
+```sh
+npm install --save @openfeature/nestjs-sdk
+```
+
+#### Required peer dependencies
-#### Here's a basic example of how to use the OpenFeature NestJS API with `InMemoryProvider`.
+The following list contains the peer dependencies of `@openfeature/nestjs-sdk` with it's expected and compatible versions:
-#### Registering the Nest.js SDK module in the App Module:
+* `@openfeature/server-sdk`: >=1.7.5
+* `@nestjs/common`: ^8.0.0 || ^9.0.0 || ^10.0.0
+* `@nestjs/core`: ^8.0.0 || ^9.0.0 || ^10.0.0
+* `rxjs`: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+The minimum required version of `@openfeature/server-sdk` currently is `1.7.5`.
+
+### Usage
+
+The example below shows how to use the `OpenFeatureModule` with OpenFeature's `InMemoryProvider`.
```ts
import { Module } from '@nestjs/common';
@@ -44,24 +86,19 @@ import { InMemoryProvider } from '@openfeature/web-sdk';
testBooleanFlag: {
defaultVariant: 'default',
variants: { default: true },
- disabled: false
+ disabled: false,
},
- companyName: {
- defaultVariant: 'default',
- variants: { default: "BigCorp" },
- disabled: false
- }
}),
providers: {
- differentProvider: new InMemoryProvider()
- }
- })
- ]
+ differentProvider: new InMemoryProvider(),
+ },
+ }),
+ ],
})
export class AppModule {}
```
-#### Injecting a feature flag with header value in evaluation context into an endpoint handler method
+With the `OpenFeatureModule` configured, it's possible to inject flag evaluation details into route handlers like in the following code snippet.
```ts
import { Controller, ExecutionContext, Get } from '@nestjs/common';
@@ -70,19 +107,6 @@ import { BooleanFeatureFlag } from '@openfeature/nestjs-sdk';
import { EvaluationDetails } from '@openfeature/server-sdk';
import { Request } from 'express';
-function getContext(executionContext: ExecutionContext) {
- const request = executionContext.switchToHttp().getRequest();
- const userId = request.header('x-user-id');
-
- if (!userId) {
- return undefined;
- }
-
- return {
- targetingKey: userId,
- };
-}
-
@Controller()
export class OpenFeatureController {
@Get('/welcome')
@@ -90,20 +114,19 @@ export class OpenFeatureController {
@BooleanFeatureFlag({
flagKey: 'testBooleanFlag',
defaultValue: false,
- contextFactory: getContext,
})
- feature: Observable>,
+ feature: Observable>,
) {
return feature.pipe(
map((details) =>
- details.value ? 'Welcome to this OpenFeature-enabled Nest.js app!' : 'Welcome to this Nest.js app!',
+ details.value ? 'Welcome to this OpenFeature-enabled NestJS app!' : 'Welcome to this NestJS app!',
),
);
}
}
```
-#### Injecting the default and a named client into a service:
+It is also possible to inject the default or named OpenFeature clients into a service via Nest dependency injection system.
```ts
import { Injectable } from '@nestjs/common';
@@ -114,15 +137,19 @@ import { FeatureClient } from '@openfeature/nestjs-sdk';
export class OpenFeatureTestService {
constructor(
@FeatureClient() private defaultClient: Client,
- @FeatureClient({ name: 'differentServer' }) private namedClient: Client,
- ) {
- }
+ @FeatureClient({ name: 'differentProvider' }) private namedClient: Client,
+ ) {}
- public async getMessage() {
- const companyName = await this.defaultClient.getStringValue('companyName', 'Unknown Company');
- return `Hey User from ${companyName}`;
+ public async getBoolean() {
+ return await this.defaultClient.getBooleanValue('testBooleanFlag', false);
}
}
```
+## Module aditional information
+
+### Flag evaluation context injection
+Whenever a flag evaluation occurs, context can be provided with information like user e-mail, role, targeting key, etc in order to trigger specific evaluation rules or logic. The `OpenFeatureModule` provides a way to configure context for each request using the `contextFactory` option.
+The `contextFactory` is ran in a NestJS interceptor scope to configure the evaluation context and than it is used in every flag evaluation related to this request.
+By default, the interceptor is configured globally, but it can be changed by setting the `useGlobalInterceptor` to `false`. In this case, it is still possible to configure a `contextFactory` that can be injected into route, module or controller bound interceptors.
diff --git a/packages/nest/src/evaluation-context-interceptor.ts b/packages/nest/src/evaluation-context-interceptor.ts
index 154e39ce4..5ec04d674 100644
--- a/packages/nest/src/evaluation-context-interceptor.ts
+++ b/packages/nest/src/evaluation-context-interceptor.ts
@@ -2,7 +2,31 @@ import { CallHandler, ExecutionContext, Inject, Injectable, NestInterceptor } fr
import { ContextFactory, ContextFactoryToken } from './context-factory';
import { Observable } from 'rxjs';
import { OpenFeature } from '@openfeature/server-sdk';
+import { OpenFeatureModule } from './open-feature.module';
+/**
+ * NestJS interceptor used in {@link OpenFeatureModule}
+ * to configure flag evaluation context.
+ *
+ * This interceptor is configured globally by default.
+ * If `useGlobalInterceptor` is set to `false` in {@link OpenFeatureModule} it needs to be configured for the specific controllers or routes.
+ *
+ * If just the interceptor class is passed to the `UseInterceptors` like below, the `contextFactory` provided in the {@link OpenFeatureModule} will be injected and used in order to create the context.
+ * ```ts
+ * //route interceptor
+ * @UseInterceptors(EvaluationContextInterceptor)
+ * @Get('/user-info')
+ * getUserInfo(){}
+ * ```
+ *
+ * A different `contextFactory` can also be provided, but the interceptor instance has to be instantiated like in the following example.
+ * ```ts
+ * //route interceptor
+ * @UseInterceptors(new EvaluationContextInterceptor())
+ * @Get('/user-info')
+ * getUserInfo(){}
+ * ```
+ */
@Injectable()
export class EvaluationContextInterceptor implements NestInterceptor {
constructor(@Inject(ContextFactoryToken) private contextFactory?: ContextFactory) {}
diff --git a/packages/nest/src/evaluation-context-propagator.ts b/packages/nest/src/evaluation-context-propagator.ts
index f979e1450..8a063639a 100644
--- a/packages/nest/src/evaluation-context-propagator.ts
+++ b/packages/nest/src/evaluation-context-propagator.ts
@@ -1,6 +1,5 @@
-import { TransactionContextPropagator } from '@openfeature/server-sdk';
+import { TransactionContextPropagator, EvaluationContext } from '@openfeature/server-sdk';
import { AsyncLocalStorage } from 'async_hooks';
-import { EvaluationContext } from '@openfeature/server-sdk';
export class AsyncLocalStorageTransactionContext implements TransactionContextPropagator {
private asyncLocalStorage = new AsyncLocalStorage();
diff --git a/packages/nest/src/open-feature.module.ts b/packages/nest/src/open-feature.module.ts
index 6f1aa5ded..2a0af1cf2 100644
--- a/packages/nest/src/open-feature.module.ts
+++ b/packages/nest/src/open-feature.module.ts
@@ -23,6 +23,9 @@ import { AsyncLocalStorageTransactionContext } from './evaluation-context-propag
import { EvaluationContextInterceptor } from './evaluation-context-interceptor';
import { ShutdownService } from './shutdown.service';
+/**
+ * OpenFeatureModule is a NestJS wrapper for OpenFeature Server-SDK.
+ */
@Module({})
export class OpenFeatureModule {
static forRoot({ useGlobalInterceptor = true, ...options }: OpenFeatureModuleOptions): DynamicModule {