Skip to content
Snippets Groups Projects
Verified Commit 224971cf authored by Konstantin Tsabolov's avatar Konstantin Tsabolov
Browse files

chore(schema-manager): make use of shared health modules and response format interceptor

parent 8793e5a1
No related branches found
No related tags found
No related merge requests found
...@@ -24,16 +24,13 @@ ...@@ -24,16 +24,13 @@
"test:e2e": "jest --config ./test/jest.config.js" "test:e2e": "jest --config ./test/jest.config.js"
}, },
"dependencies": { "dependencies": {
"@nestjs/axios": "^3.0.1",
"@nestjs/common": "^10.2.10", "@nestjs/common": "^10.2.10",
"@nestjs/config": "^3.1.1", "@nestjs/config": "^3.1.1",
"@nestjs/core": "^10.2.10", "@nestjs/core": "^10.2.10",
"@nestjs/microservices": "^10.2.10", "@nestjs/microservices": "^10.2.10",
"@nestjs/platform-express": "^10.2.8", "@nestjs/platform-express": "^10.2.8",
"@nestjs/swagger": "^7.1.16", "@nestjs/swagger": "^7.1.16",
"@nestjs/terminus": "^10.1.1",
"@ocm/shared": "workspace:*", "@ocm/shared": "workspace:*",
"axios": "^1.6.2",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.0", "class-validator": "^0.14.0",
"express": "^4.17.3", "express": "^4.17.3",
......
...@@ -4,6 +4,7 @@ import { Module } from '@nestjs/common'; ...@@ -4,6 +4,7 @@ import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config'; import { ConfigModule } from '@nestjs/config';
import { RouterModule } from '@nestjs/core'; import { RouterModule } from '@nestjs/core';
import { ClientsModule, Transport } from '@nestjs/microservices'; import { ClientsModule, Transport } from '@nestjs/microservices';
import { HealthModule } from '@ocm/shared';
import { NATS_CLIENT } from './common/constants.js'; import { NATS_CLIENT } from './common/constants.js';
import { httpConfig } from './config/http.config.js'; import { httpConfig } from './config/http.config.js';
...@@ -11,7 +12,6 @@ import { natsConfig } from './config/nats.config.js'; ...@@ -11,7 +12,6 @@ import { natsConfig } from './config/nats.config.js';
import { ssiConfig } from './config/ssi.config.js'; import { ssiConfig } from './config/ssi.config.js';
import { validationSchema } from './config/validation.js'; import { validationSchema } from './config/validation.js';
import { CredentialDefinitionsModule } from './credential-definitions/credential-definitions.module.js'; import { CredentialDefinitionsModule } from './credential-definitions/credential-definitions.module.js';
import { HealthModule } from './health/health.module.js';
import { SchemasModule } from './schemas/schemas.module.js'; import { SchemasModule } from './schemas/schemas.module.js';
@Module({ @Module({
...@@ -44,7 +44,20 @@ import { SchemasModule } from './schemas/schemas.module.js'; ...@@ -44,7 +44,20 @@ import { SchemasModule } from './schemas/schemas.module.js';
], ],
}), }),
HealthModule, HealthModule.registerAsync({
inject: [natsConfig.KEY],
useFactory: (config: ConfigType<typeof natsConfig>) => {
const options: Parameters<typeof HealthModule.register>[0] = {};
if (config.monitoringUrl) {
options.nats = {
monitoringUrl: config.monitoringUrl as string,
};
}
return options;
},
}),
SchemasModule, SchemasModule,
CredentialDefinitionsModule, CredentialDefinitionsModule,
......
import type { ExecutionContext } from '@nestjs/common';
import type { TestingModule } from '@nestjs/testing';
import { Test } from '@nestjs/testing';
import { of } from 'rxjs';
import { ResponseFormatInterceptor } from '../response-format.interceptor.js';
describe('ResponseFormatInterceptor', () => {
let interceptor: ResponseFormatInterceptor;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ResponseFormatInterceptor],
}).compile();
interceptor = module.get<ResponseFormatInterceptor>(
ResponseFormatInterceptor,
);
});
it('should be defined', () => {
expect(interceptor).toBeDefined();
expect(interceptor).toBeInstanceOf(ResponseFormatInterceptor);
});
it('should intercept the request and format the response', (done) => {
const context: ExecutionContext = {
switchToHttp: () => ({
getResponse: () => ({
statusCode: 200,
}),
}),
} as ExecutionContext;
const next = {
handle: jest.fn().mockReturnValue(of('Hello World')),
};
const result = interceptor.intercept(context, next);
expect(result).toBeDefined();
expect(next.handle).toHaveBeenCalled();
result.subscribe((response) => {
expect(response).toEqual({ statusCode: 200, data: 'Hello World' });
done();
});
});
});
import type {
CallHandler,
ExecutionContext,
NestInterceptor,
} from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { map, type Observable } from 'rxjs';
@Injectable()
export class ResponseFormatInterceptor implements NestInterceptor {
public intercept(
context: ExecutionContext,
next: CallHandler,
): Observable<unknown> {
const ctx = context.switchToHttp();
const response = ctx.getResponse();
return next.handle().pipe(
map((data) => {
return {
statusCode: response.statusCode,
data,
};
}),
);
}
}
...@@ -11,9 +11,7 @@ import { ...@@ -11,9 +11,7 @@ import {
ValidationPipe, ValidationPipe,
} from '@nestjs/common'; } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { MultitenancyParams } from '@ocm/shared'; import { MultitenancyParams, ResponseFormatInterceptor } from '@ocm/shared';
import { ResponseFormatInterceptor } from '../common/response-format.interceptor.js';
import { CredentialDefinitionsService } from './credential-definitions.service.js'; import { CredentialDefinitionsService } from './credential-definitions.service.js';
import { CreateCredentialDefinitionPayload } from './dto/create-credential-definition.dto.js'; import { CreateCredentialDefinitionPayload } from './dto/create-credential-definition.dto.js';
......
import type { HealthIndicatorFunction } from '@nestjs/terminus';
import { Controller, Get } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import {
HealthCheck,
HealthCheckService,
HttpHealthIndicator,
} from '@nestjs/terminus';
@Controller()
export class HealthController {
public constructor(
private readonly config: ConfigService,
private readonly health: HealthCheckService,
private readonly http: HttpHealthIndicator,
) {}
@Get()
@HealthCheck()
public check() {
const healthIndicators: HealthIndicatorFunction[] = [];
const natsMonitoringUrl = this.config.get('nats.monitoringUrl');
if (typeof natsMonitoringUrl === 'string') {
healthIndicators.push(() =>
this.http.pingCheck('nats', natsMonitoringUrl),
);
} else {
healthIndicators.push(() => ({ nats: { status: 'down' } }));
}
return this.health.check(healthIndicators);
}
}
import type { ConfigType } from '@nestjs/config';
import { HttpModule } from '@nestjs/axios';
import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { TerminusModule } from '@nestjs/terminus';
import { SERVICE_NAME } from '../common/constants.js';
import { natsConfig } from '../config/nats.config.js';
import { HealthController } from './health.controller.js';
@Module({
imports: [
TerminusModule,
HttpModule,
ClientsModule.registerAsync({
clients: [
{
name: SERVICE_NAME,
inject: [natsConfig.KEY],
useFactory: (config: ConfigType<typeof natsConfig>) => ({
transport: Transport.NATS,
options: {
servers: [config.url as string],
},
}),
},
],
}),
],
controllers: [HealthController],
})
export class HealthModule {}
...@@ -19,11 +19,9 @@ import { ...@@ -19,11 +19,9 @@ import {
Version, Version,
} from '@nestjs/common'; } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { MultitenancyParams } from '@ocm/shared'; import { MultitenancyParams, ResponseFormatInterceptor } from '@ocm/shared';
import { Observable, of, switchMap } from 'rxjs'; import { Observable, of, switchMap } from 'rxjs';
import { ResponseFormatInterceptor } from '../common/response-format.interceptor.js';
import { GetByIdParams } from './dto/get-by-id.dto.js'; import { GetByIdParams } from './dto/get-by-id.dto.js';
import { RegisterSchemaPayload } from './dto/register-schema.dto.js'; import { RegisterSchemaPayload } from './dto/register-schema.dto.js';
import { SchemasService } from './schemas.service.js'; import { SchemasService } from './schemas.service.js';
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment