-
Notifications
You must be signed in to change notification settings - Fork 37
docs: Nest SDK #750
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
docs: Nest SDK #750
Changes from 5 commits
4dd59c4
d837440
cad673a
88bf4f7
04e92b7
f0c9afe
c527bc9
9f1b5f6
3de4dff
de8aa97
87f1b51
34e70d5
1f932e6
3564be5
4035c25
d7801d3
3c33c06
988853b
73547b4
c759819
6d62232
49072d6
8948eda
82ede1e
529178b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,11 +25,45 @@ | |
[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. | ||
|
||
<!-- x-hide-in-docs-end --> | ||
|
||
🧪 This SDK is experimental. | ||
|
||
#### Here's a basic example of how to use the OpenFeature NestJS API with `InMemoryProvider`. | ||
## Overview | ||
|
||
The OpenFeature NestJS SDK is a package that provides a NestJS wrapper for the [OpenFeature Server SDK](). | ||
|
||
It's main capabilities are: | ||
- Provide a NestJS global module to simplify OpenFeature configuration and usage within NestJS; | ||
- Supply custom parameter decorators (for controllers), that inject observables with feature flags resolution details; | ||
luizgribeiro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- Inject context for flag evaluation seamlessly using NestJS interceptors | ||
luizgribeiro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- Provide decorators for OpenFeature Client injection into NestJS services and controllers | ||
luizgribeiro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- TODO: map other features | ||
luizgribeiro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## 🚀 Quick start | ||
|
||
### Requirements | ||
|
||
- Node.js version 16+ | ||
- NestJS | ||
lukas-reining marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#### Registering the Nest.js SDK module in the App Module: | ||
### Install | ||
|
||
#### npm | ||
|
||
```sh | ||
npm install --save @openfeature/nestjs-sdk | ||
``` | ||
|
||
#### yarn | ||
|
||
```sh | ||
yarn add @openfeature/nestjs-sdk | ||
luizgribeiro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
|
||
### Usage | ||
|
||
The example bellow shows how to use the `OpenFeatureModule` with OpenFeature's `InMemoryProvider`. | ||
luizgribeiro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```ts | ||
import { Module } from '@nestjs/common'; | ||
|
@@ -46,11 +80,6 @@ import { InMemoryProvider } from '@openfeature/web-sdk'; | |
variants: { default: true }, | ||
disabled: false | ||
}, | ||
companyName: { | ||
defaultVariant: 'default', | ||
variants: { default: "BigCorp" }, | ||
disabled: false | ||
} | ||
}), | ||
providers: { | ||
differentProvider: new InMemoryProvider() | ||
|
@@ -61,7 +90,7 @@ import { InMemoryProvider } from '@openfeature/web-sdk'; | |
export class AppModule {} | ||
``` | ||
|
||
#### Injecting a feature flag with header value in evaluation context into an endpoint handler method | ||
With the `OpenFeatureModule` configured it is now possible to inject flag evaluation details into route handlers like in the following code snippet. | ||
luizgribeiro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```ts | ||
import { Controller, ExecutionContext, Get } from '@nestjs/common'; | ||
|
@@ -70,27 +99,13 @@ 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<Request>(); | ||
const userId = request.header('x-user-id'); | ||
|
||
if (!userId) { | ||
return undefined; | ||
} | ||
|
||
return { | ||
targetingKey: userId, | ||
}; | ||
} | ||
|
||
@Controller() | ||
export class OpenFeatureController { | ||
@Get('/welcome') | ||
public async welcome( | ||
@BooleanFeatureFlag({ | ||
flagKey: 'testBooleanFlag', | ||
defaultValue: false, | ||
contextFactory: getContext, | ||
}) | ||
feature: Observable<EvaluationDetails<boolean>>, | ||
lukas-reining marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) { | ||
|
@@ -103,7 +118,7 @@ export class OpenFeatureController { | |
} | ||
``` | ||
|
||
#### Injecting the default and a named client into a service: | ||
It is also possible to inject the default and a named OpenFeature client into a service via it's constructor with Nest dependency injection system. | ||
luizgribeiro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```ts | ||
import { Injectable } from '@nestjs/common'; | ||
|
@@ -114,15 +129,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, | ||
Comment on lines
139
to
+140
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should rename this to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It has been We could remove the export of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think @toddbaert? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry for the late reply - if we can remove that export, I'm fine with it! It's an improvement. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey @toddbaert, removing this should be considered a breaking change I would say. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm, well, if I understand correctly, it would be technically breaking, but I think it could be argued it was a misuse. All our doc recommends using the interface. If we want to be really strict, we could consider it a break and include it with some others I have in mind in a 2.0.0 (meaning to ask you guys about this soon... there's a small list of breaking improvements I think might be worth considering)... |
||
) {} | ||
|
||
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. | ||
lukas-reining marked this conversation as resolved.
Show resolved
Hide resolved
|
||
By default the interceptor is cofigured 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. | ||
luizgribeiro marked this conversation as resolved.
Show resolved
Hide resolved
|
Uh oh!
There was an error while loading. Please reload this page.