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

feat: adds RequireFlagsEnabled decorator #1159

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions packages/nest/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export * from './open-feature.module';
export * from './feature.decorator';
export * from './evaluation-context-interceptor';
export * from './context-factory';
export * from './require-flags-enabled.decorator';
// re-export the server-sdk so consumers can access that API from the nestjs-sdk
export * from '@openfeature/server-sdk';
87 changes: 87 additions & 0 deletions packages/nest/src/require-flags-enabled.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import {

Check failure on line 1 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (18.x)

Imports "CallHandler", "ExecutionContext", "HttpException" and "NestInterceptor" are only used as type

Check failure on line 1 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (20.x)

Imports "CallHandler", "ExecutionContext", "HttpException" and "NestInterceptor" are only used as type

Check failure on line 1 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (22.x)

Imports "CallHandler", "ExecutionContext", "HttpException" and "NestInterceptor" are only used as type
applyDecorators,
CallHandler,
ExecutionContext,
HttpException,
mixin,
NestInterceptor,
NotFoundException,
UseInterceptors,
} from '@nestjs/common';
import { OpenFeature } from '@openfeature/server-sdk';

/**
* Options for injecting a feature flag into a route handler.
*/
interface RequireFlagsEnabledProps {
/**
* The key of the feature flag.
* @see {@link Client#getBooleanValue}
*/
flagKeys: string[];
/**
* The exception to throw if any of the required feature flags are not enabled.
* Defaults to a 404 Not Found exception.
* @see {@link HttpException}
*/
exception?: HttpException;

/**
* The domain of the OpenFeature client, if a domain scoped client should be used.
* @see {@link OpenFeature#getClient}
*/
domain?: string;
}

/**
* Returns a domain scoped or the default OpenFeature client with the given context.
* @param {string} domain The domain of the OpenFeature client.
* @returns {Client} The OpenFeature client.

Check warning on line 39 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (18.x)

The type 'Client' is undefined

Check warning on line 39 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (20.x)

The type 'Client' is undefined

Check warning on line 39 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (22.x)

The type 'Client' is undefined
*/
function getClientForEvaluation(domain?: string) {
return domain ? OpenFeature.getClient(domain) : OpenFeature.getClient();
}

/**

Check warning on line 45 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (18.x)

Missing JSDoc @param "props" declaration

Check warning on line 45 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (20.x)

Missing JSDoc @param "props" declaration

Check warning on line 45 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (22.x)

Missing JSDoc @param "props" declaration
* Controller or Route permissions handler decorator.
*
* Requires that the given feature flags are enabled for the request to be processed, else throws an exception.
*
* For example:
* ```typescript
* @RequireFlagsEnabled({
* flagKeys: ['flagName', 'flagName2'], // Required, an array of Boolean feature flag keys
* exception: new ForbiddenException(), // Optional, defaults to a 404 Not Found exception
* domain: 'my-domain', // Optional, defaults to the default OpenFeature client
* })
* @Get('/')
* public async handleGetRequest()
* ```
* @param {RequireFlagsEnabledProps} options The options for injecting the feature flag.

Check warning on line 60 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (18.x)

Expected @param names to be "props". Got "options"

Check warning on line 60 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (20.x)

Expected @param names to be "props". Got "options"

Check warning on line 60 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (22.x)

Expected @param names to be "props". Got "options"
* @returns {Decorator}

Check warning on line 61 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (18.x)

The type 'Decorator' is undefined

Check warning on line 61 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (18.x)

Missing JSDoc @returns description

Check warning on line 61 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (20.x)

The type 'Decorator' is undefined

Check warning on line 61 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (20.x)

Missing JSDoc @returns description

Check warning on line 61 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (22.x)

The type 'Decorator' is undefined

Check warning on line 61 in packages/nest/src/require-flags-enabled.decorator.ts

View workflow job for this annotation

GitHub Actions / build-test-lint (22.x)

Missing JSDoc @returns description
*/
export const RequireFlagsEnabled = (props: RequireFlagsEnabledProps): ClassDecorator & MethodDecorator =>
applyDecorators(UseInterceptors(FlagsEnabledInterceptor(props)));

const FlagsEnabledInterceptor = (props: RequireFlagsEnabledProps) => {
class FlagsEnabledInterceptor implements NestInterceptor {
constructor() {}

async intercept(context: ExecutionContext, next: CallHandler) {
const req = context.switchToHttp().getRequest();
const client = getClientForEvaluation(props.domain);

for (const flagKey of props.flagKeys) {
const endpointAccessible = await client.getBooleanValue(flagKey, false);

if (!endpointAccessible) {
throw props.exception || new NotFoundException(`Cannot ${req.method} ${req.url}`);
}
}

return next.handle();
}
}

return mixin(FlagsEnabledInterceptor);
};
Loading