Skip to content

Commit

Permalink
feat: use Nest.js SDK in backend
Browse files Browse the repository at this point in the history
  • Loading branch information
lukas-reining committed Jan 19, 2024
1 parent 1827862 commit 16589ef
Show file tree
Hide file tree
Showing 12 changed files with 67 additions and 174 deletions.
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@openfeature/flagd-provider": "^0.9.0",
"@openfeature/flagd-web-provider": "^0.4.1",
"@openfeature/go-feature-flag-provider": "^0.6.1",
"@openfeature/nestjs-sdk": "^0.0.4-experimental",
"@openfeature/open-telemetry-hooks": "^0.3.0",
"@openfeature/server-sdk": "^1.7.5",
"@openfeature/web-sdk": "0.4.7",
Expand Down
88 changes: 29 additions & 59 deletions packages/app/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,26 @@
import {HttpModule} from '@nestjs/axios';
import {MiddlewareConsumer, Module, NestModule, Scope} from '@nestjs/common';
import {REQUEST} from '@nestjs/core';
import {ExecutionContext, Module} from '@nestjs/common';
import {ServeStaticModule} from '@nestjs/serve-static';
import {AsyncLocalStorageTransactionContext, LoggingHook, OpenFeatureLogger} from '@openfeature/extra';
import { FlagMetadata, OpenFeature } from '@openfeature/server-sdk';
import {MetricsHook, TracingHook as SpanEventBasedTracingHook} from '@openfeature/open-telemetry-hooks';
import {LoggingHook, OpenFeatureLogger} from '@openfeature/extra';
import {FlagMetadata} from '@openfeature/js-sdk';
import {TracingHook as SpanEventBasedTracingHook, MetricsHook} from '@openfeature/open-telemetry-hooks';
import {ProviderService} from '@openfeature/provider';
import {Request} from 'express';
import {Agent} from 'http';
import {LoggerModule} from 'nestjs-pino';
import {join} from 'path';
import {OPENFEATURE_CLIENT, REQUEST_DATA} from './constants';
import {FibonacciAsAServiceController} from './fibonacci-as-a-service.controller';
import {FibonacciService} from './fibonacci/fibonacci.service';
import {ProvidersController} from './providers.controller';
import {TransactionContextMiddleware} from './transaction-context.middleware';
import {RequestData} from './types';
import {UtilsController} from './utils.controller';

/**
* Set a global logger for OpenFeature. This is logger will available in hooks.
*/
OpenFeature.setLogger(new OpenFeatureLogger('OpenFeature'));
import {EvaluationContext, OpenFeatureModule} from "@openfeature/nestjs-sdk";

function attributeMapper(flagMetadata: FlagMetadata) {
return {
...('scope' in flagMetadata && { scope: flagMetadata.scope }),
...('scope' in flagMetadata && {scope: flagMetadata.scope}),
};
}

/**
* Adding hooks to at the global level will ensure they always run
* as part of a flag evaluation lifecycle.
*/
OpenFeature.addHooks(
new LoggingHook(),
new SpanEventBasedTracingHook({attributeMapper}),
new MetricsHook({attributeMapper}));

/**
* The transaction context propagator is an experimental feature
* that allows evaluation context to be set anywhere in a request
* and have it automatically available during a flag evaluation.
*/
OpenFeature.setTransactionContextPropagator(new AsyncLocalStorageTransactionContext());

@Module({
imports: [
LoggerModule.forRoot({
Expand All @@ -59,53 +35,47 @@ OpenFeature.setTransactionContextPropagator(new AsyncLocalStorageTransactionCont
transport:
process.env['NODE' + '_ENV'] !== 'production'
? {
target: 'pino-pretty',
options: {
hideObject: true,
},
}
target: 'pino-pretty',
options: {
hideObject: true,
},
}
: undefined,
},
}),
ServeStaticModule.forRoot({
rootPath: join(__dirname, '..', 'ui'),
}),
HttpModule.register({
httpAgent: new Agent({ keepAlive: true }),
httpAgent: new Agent({keepAlive: true}),
}),
],
controllers: [FibonacciAsAServiceController, UtilsController, ProvidersController],
providers: [
FibonacciService,
ProviderService,
{
provide: OPENFEATURE_CLIENT,
useFactory: () => {
const client = OpenFeature.getClient('app');
return client;
},
},
{
provide: REQUEST_DATA,
useFactory: (req: Request): RequestData => {
OpenFeatureModule.forRoot({
// Set a global logger for OpenFeature. This is logger will available in hooks.
logger: new OpenFeatureLogger('OpenFeature'),
//Adding hooks to at the global level will ensure they always run as part of a flag evaluation lifecycle.
hooks: [new LoggingHook(), new SpanEventBasedTracingHook({attributeMapper}), new MetricsHook({attributeMapper})],
// This context will be used for all flag evaluations in the callstack
contextFactory: async (context: ExecutionContext): Promise<EvaluationContext> => {
const req = await context.switchToHttp().getRequest<Request>()
const authHeaderValue = req.header('Authorization') || 'anonymous';
const userAgent = req.header('user-agent');
return {
ts: new Date().getTime(),
ip: (req.headers['x-forwarded-for'] as string) || (req.socket.remoteAddress as string),
email: authHeaderValue,
method: req.method,
path: req.path,
...(userAgent && { userAgent }),
...(userAgent && {userAgent}),
targetingKey: authHeaderValue,
};
},
scope: Scope.REQUEST,
inject: [REQUEST],
},
})
],
controllers: [FibonacciAsAServiceController, UtilsController, ProvidersController],
providers: [
FibonacciService,
ProviderService,
],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(TransactionContextMiddleware).forRoutes(FibonacciAsAServiceController);
}
export class AppModule {
}
2 changes: 0 additions & 2 deletions packages/app/src/app/constants.ts

This file was deleted.

17 changes: 9 additions & 8 deletions packages/app/src/app/fibonacci/fibonacci.service.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { HttpService } from '@nestjs/axios';
import { Inject, Injectable } from '@nestjs/common';
import { fibonacci } from '@openfeature/fibonacci';
import { Client } from '@openfeature/server-sdk';
import { OPENFEATURE_CLIENT } from '../constants';
import { lastValueFrom, map } from 'rxjs';
import {HttpService} from '@nestjs/axios';
import {Injectable} from '@nestjs/common';
import {fibonacci} from '@openfeature/fibonacci';
import {Client} from '@openfeature/js-sdk';
import {lastValueFrom, map} from 'rxjs';
import {FeatureClient} from "@openfeature/nestjs-sdk";

@Injectable()
export class FibonacciService {
private readonly FIB_SERVICE_URL = process.env.FIB_SERVICE_URL || 'http://localhost:30001';

constructor(private readonly httpService: HttpService, @Inject(OPENFEATURE_CLIENT) private client: Client) {}
constructor(private readonly httpService: HttpService, @FeatureClient() private client: Client) {
}

async calculateFibonacci(num: number): Promise<{ result: number }> {
const useRemoteFibService = await this.client.getBooleanValue('use-remote-fib-service', false);
Expand All @@ -18,7 +19,7 @@ export class FibonacciService {
return lastValueFrom(
this.httpService
.get<{ result: number }>(`${this.FIB_SERVICE_URL}/calculate`, {
params: { num },
params: {num},
auth: {
username: process.env.FIB_SERVICE_USER || '',
password: process.env.FIB_SERVICE_PASS || '',
Expand Down
19 changes: 0 additions & 19 deletions packages/app/src/app/transaction-context.middleware.ts

This file was deleted.

13 changes: 0 additions & 13 deletions packages/app/src/app/types.ts

This file was deleted.

53 changes: 17 additions & 36 deletions packages/fibonacci-service/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,19 @@
import {MiddlewareConsumer, Module, NestModule} from '@nestjs/common';
import {Module} from '@nestjs/common';
import {AppController} from './app.controller';
import {LoggerModule} from 'nestjs-pino';
import { FlagMetadata, OpenFeature } from '@openfeature/server-sdk';
import {AsyncLocalStorageTransactionContext, LoggingHook, OpenFeatureLogger} from '@openfeature/extra';
import {FlagMetadata} from '@openfeature/server-sdk';
import {LoggingHook, OpenFeatureLogger} from '@openfeature/extra';
import {MetricsHook, TracingHook as SpanEventBasedTracingHook} from '@openfeature/open-telemetry-hooks';
import {TransactionContextMiddleware} from './transaction-context.middleware';
import {ProviderService} from '@openfeature/provider';
import {ProvidersController} from './providers.controller';

/**
* Set a global logger for OpenFeature. This is logger will available in hooks.
*/
OpenFeature.setLogger(new OpenFeatureLogger('OpenFeature'));
import {OpenFeatureModule} from "@openfeature/nestjs-sdk";

function attributeMapper(flagMetadata: FlagMetadata) {
return {
...('scope' in flagMetadata && { scope: flagMetadata.scope }),
...('scope' in flagMetadata && {scope: flagMetadata.scope}),
};
}

/**
* Adding hooks to at the global level will ensure they always run
* as part of a flag evaluation lifecycle.
*/
OpenFeature.addHooks(
new LoggingHook(),
new SpanEventBasedTracingHook({attributeMapper}),
new MetricsHook({ attributeMapper }));

/**
* The transaction context propagator is an experimental feature
* that allows evaluation context to be set anywhere in a request
* and have it automatically available during a flag evaluation.
*/
OpenFeature.setTransactionContextPropagator(new AsyncLocalStorageTransactionContext());

@Module({
imports: [
LoggerModule.forRoot({
Expand All @@ -49,20 +28,22 @@ OpenFeature.setTransactionContextPropagator(new AsyncLocalStorageTransactionCont
transport:
process.env['NODE' + '_ENV'] !== 'production'
? {
target: 'pino-pretty',
options: {
hideObject: true,
},
}
target: 'pino-pretty',
options: {
hideObject: true,
},
}
: undefined,
},
}),
OpenFeatureModule.forRoot({
// Set a global logger for OpenFeature. This is logger will available in hooks.
logger: new OpenFeatureLogger('OpenFeature'),
//Adding hooks to at the global level will ensure they always run as part of a flag evaluation lifecycle.
hooks: [new LoggingHook(), new SpanEventBasedTracingHook({attributeMapper}), new MetricsHook({attributeMapper})],
})
],
controllers: [AppController, ProvidersController],
providers: [ProviderService],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(TransactionContextMiddleware).forRoutes(AppController);
}
}
export class AppModule {}

This file was deleted.

1 change: 0 additions & 1 deletion packages/openfeature-extra/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * from './lib/hooks';
export * from './lib/transaction-context';
export * from './lib/logger';

This file was deleted.

This file was deleted.

0 comments on commit 16589ef

Please sign in to comment.