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

feat: implement schemas endpoints in schema manager

parent ad2758be
No related branches found
No related tags found
No related merge requests found
import type { TestingModule } from '@nestjs/testing';
import type { EventAnonCredsSchemasRegisterInput } from '@ocm/shared';
import { Test } from '@nestjs/testing';
import {
......@@ -31,23 +32,20 @@ describe('SchemasService', () => {
describe('getAll', () => {
it('should return the data from NATS client', (done) => {
const unsubscribe$ = new Subject<void>();
const payload = {
tenantId: 'mocked tenantId',
endpoint: EventAnonCredsSchemasGetAll.token,
};
const tenantId = 'mocked tenantId';
const expectedResult: EventAnonCredsSchemasGetAll['data'] = [];
natsClientMock.send.mockReturnValueOnce(
of(new EventAnonCredsSchemasGetAll([], payload.tenantId)),
of(new EventAnonCredsSchemasGetAll([], tenantId)),
);
service
.getAll(payload)
.getAll(tenantId)
.pipe(takeUntil(unsubscribe$))
.subscribe((result) => {
expect(natsClientMock.send).toHaveBeenCalledWith(
{ endpoint: EventAnonCredsSchemasGetAll.token },
payload,
EventAnonCredsSchemasGetAll.token,
{ tenantId },
);
expect(result).toStrictEqual(expectedResult);
......@@ -63,10 +61,8 @@ describe('SchemasService', () => {
describe('getById', () => {
it('should return the data from NATS client', (done) => {
const unsubscribe$ = new Subject<void>();
const payload = {
tenantId: 'mocked tenantId',
schemaId: 'mocked id',
};
const tenantId = 'mocked tenantId';
const schemaId = 'mocked id';
const expectedResult: EventAnonCredsSchemasGetById['data'] = {
issuerId: 'mocked issuerDid',
name: 'mocked name',
......@@ -75,16 +71,16 @@ describe('SchemasService', () => {
};
natsClientMock.send.mockReturnValueOnce(
of(new EventAnonCredsSchemasGetById(expectedResult, payload.tenantId)),
of(new EventAnonCredsSchemasGetById(expectedResult, tenantId)),
);
service
.getById(payload)
.getById(tenantId, schemaId)
.pipe(takeUntil(unsubscribe$))
.subscribe((result) => {
expect(natsClientMock.send).toHaveBeenCalledWith(
{ endpoint: EventAnonCredsSchemasGetById.token },
payload,
EventAnonCredsSchemasGetById.token,
{ tenantId, schemaId },
);
expect(result).toStrictEqual(expectedResult);
......@@ -100,31 +96,31 @@ describe('SchemasService', () => {
describe('register', () => {
it('should return the data from NATS client', (done) => {
const unsubscribe$ = new Subject<void>();
const payload = {
tenantId: 'mocked tenantId',
const tenantId = 'mocked tenantId';
const payload: Omit<EventAnonCredsSchemasRegisterInput, 'tenantId'> = {
issuerDid: 'mocked issuerDid',
name: 'mocked name',
version: '1.0.0',
attributeNames: ['mocked attribute1', 'mocked attribute2'],
};
const expectedResult: EventAnonCredsSchemasRegister['data'] = {
issuerId: 'mocked issuerDid',
issuerId: 'mocked issuerId',
name: 'mocked name',
version: '1.0.0',
attrNames: ['mocked attribute1', 'mocked attribute2'],
};
natsClientMock.send.mockReturnValueOnce(
of(new EventAnonCredsSchemasRegister(expectedResult, payload.tenantId)),
of(new EventAnonCredsSchemasRegister(expectedResult, tenantId)),
);
service
.register(payload)
.register(tenantId, payload)
.pipe(takeUntil(unsubscribe$))
.subscribe((result) => {
expect(natsClientMock.send).toHaveBeenCalledWith(
{ endpoint: EventAnonCredsSchemasRegister.token },
payload,
EventAnonCredsSchemasRegister.token,
{ ...payload, tenantId },
);
expect(result).toStrictEqual(expectedResult);
......
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsString } from 'class-validator';
export class TenantIdParam {
@IsString()
@IsNotEmpty()
@ApiProperty({
description: 'The tenant ID to use for the request',
format: 'string',
})
public tenantId: string;
}
......@@ -13,27 +13,24 @@ import {
Param,
Post,
Query,
UseInterceptors,
UsePipes,
ValidationPipe,
Version,
} from '@nestjs/common';
import {
ApiBody,
ApiOperation,
ApiParam,
ApiQuery,
ApiResponse,
ApiTags,
} from '@nestjs/swagger';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { MultitenancyParams } from '@ocm/shared';
import { Observable, of, switchMap } from 'rxjs';
import { ResponseFormatInterceptor } from '../common/response-format.interceptor.js';
import { GetByIdParams } from './dto/get-by-id.dto.js';
import { RegisterSchemaPayload } from './dto/register-schema.dto.js';
import { TenantIdParam } from './dto/tenant-id.dto.js';
import { SchemasService } from './schemas.service.js';
@Controller('schemas')
@Controller()
@UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
@UseInterceptors(ResponseFormatInterceptor)
@ApiTags('Schemas')
export class SchemasController {
public constructor(private readonly schemasService: SchemasService) {}
......@@ -44,34 +41,64 @@ export class SchemasController {
summary: 'Fetch a list of schemas',
description: 'This call provides a list of schemas for a given tenant',
})
@ApiQuery({ name: 'tenantId', required: true })
@ApiResponse({
status: HttpStatus.OK,
description: 'Schemas fetched successfully',
content: {
// TBD
'application/json': {
schema: {},
examples: {
'Schemas fetched successfully': {
value: {
statusCode: 200,
message: 'Schemas fetched successfully',
data: [],
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Tenant not found',
content: {
// TBD
'application/json': {
schema: {},
examples: {
'Tenant not found': {
value: {
statusCode: 404,
message: 'Tenant not found',
data: null,
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.INTERNAL_SERVER_ERROR,
description: 'Internal server error',
content: {
// TBD
'application/json': {
schema: {},
examples: {
'Internal server error': {
value: {
statusCode: 500,
message: 'Internal server error',
error: 'Internal Server Error',
},
},
},
},
},
})
public getAll(
@Query() { tenantId }: TenantIdParam,
@Query() { tenantId }: MultitenancyParams,
): Observable<EventAnonCredsSchemasGetAll['data']> {
return this.schemasService.getAll({
tenantId,
});
return this.schemasService.getAll(tenantId);
}
@Version('1')
......@@ -81,53 +108,92 @@ export class SchemasController {
description:
'This call allows you to retrieve schema data for a given tenant by specifying the `schemaId`.',
})
@ApiParam({ name: 'schemaId', required: true })
@ApiQuery({ name: 'tenantId', required: true })
@ApiResponse({
status: HttpStatus.OK,
description: 'Schema fetched successfully',
content: {
// TBD
'application/json': {
schema: {},
examples: {
'Schema fetched successfully': {
value: {
statusCode: 200,
message: 'Schema fetched successfully',
data: {
id: '71b784a3',
},
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Tenant not found',
content: {
// TBD
'application/json': {
schema: {},
examples: {
'Tenant not found': {
value: {
statusCode: 404,
message: 'Tenant not found',
data: null,
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Schema not found',
content: {
// TBD
'application/json': {
schema: {},
examples: {
'Schema not found': {
value: {
statusCode: 404,
message: 'Schema not found',
data: null,
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.INTERNAL_SERVER_ERROR,
description: 'Internal server error',
content: {
// TBD
'application/json': {
schema: {},
examples: {
'Internal server error': {
value: {
statusCode: 500,
message: 'Internal server error',
error: 'Internal Server Error',
},
},
},
},
},
})
public getById(
@Param() { schemaId }: GetByIdParams,
@Query() { tenantId }: TenantIdParam,
@Query() { tenantId }: MultitenancyParams,
): Observable<EventAnonCredsSchemasGetById['data']> {
return this.schemasService
.getById({
tenantId,
schemaId,
})
.pipe(
switchMap((schema) => {
if (schema === null) {
throw new NotFoundException(`Schema with id ${schemaId} not found`);
}
return of(schema);
}),
);
return this.schemasService.getById(tenantId, schemaId).pipe(
switchMap((schema) => {
if (schema === null) {
throw new NotFoundException(`Schema with id ${schemaId} not found`);
}
return of(schema);
}),
);
}
@Version('1')
......@@ -137,50 +203,102 @@ export class SchemasController {
description:
'This call provides the capability to create new schema on ledger by name, author, version, schema attributes and type. Later this schema can be used to issue new credential definition. This call returns an information about created schema.',
})
@ApiQuery({ name: 'tenantId', required: true })
@ApiBody({ type: RegisterSchemaPayload })
@ApiResponse({
status: HttpStatus.CREATED,
description: 'Schema registered successfully',
content: {
'application/json': {},
'application/json': {
schema: {},
examples: {
'Schema registered successfully': {
value: {
statusCode: 201,
message: 'Schema registered successfully',
data: {
id: '71b784a3',
},
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
description: 'Tenant not found',
content: {
'application/json': {},
'application/json': {
schema: {},
examples: {
'Tenant not found': {
value: {
statusCode: 404,
message: 'Tenant not found',
data: null,
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description: 'All fields are required for schema registration',
content: {
'application/json': {},
'application/json': {
schema: {},
examples: {
'All fields are required for schema registration': {
value: {
statusCode: 400,
message: 'All fields are required for schema registration',
error: 'Bad Request',
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.CONFLICT,
description: 'Schema already exists',
content: {
'application/json': {},
'application/json': {
schema: {},
examples: {
'Schema already exists': {
value: {
statusCode: 409,
message: 'Schema already exists',
error: 'Conflict',
},
},
},
},
},
})
@ApiResponse({
status: HttpStatus.INTERNAL_SERVER_ERROR,
description: 'Internal server error',
content: {
'application/json': {},
'application/json': {
schema: {},
examples: {
'Internal server error': {
value: {
statusCode: 500,
message: 'Internal server error',
error: 'Internal Server Error',
},
},
},
},
},
})
public register(
@Query() { tenantId }: TenantIdParam,
@Query() { tenantId }: MultitenancyParams,
@Body() payload: RegisterSchemaPayload,
): Observable<EventAnonCredsSchemasRegister['data']> {
return this.schemasService.register({
...payload,
tenantId,
});
return this.schemasService.register(tenantId, payload);
}
}
......@@ -22,40 +22,36 @@ export class SchemasService {
) {}
public getAll(
payload: EventAnonCredsSchemasGetAllInput,
tenantId: string,
): Observable<EventAnonCredsSchemasGetAll['data']> {
const pattern = { endpoint: EventAnonCredsSchemasGetAll.token };
return this.natsClient
.send<EventAnonCredsSchemasGetAll, EventAnonCredsSchemasGetAllInput>(
pattern,
payload,
EventAnonCredsSchemasGetAll.token,
{ tenantId },
)
.pipe(map((result) => result.data));
}
public getById(
payload: EventAnonCredsSchemasGetByIdInput,
tenantId: string,
schemaId: EventAnonCredsSchemasGetByIdInput['schemaId'],
): Observable<EventAnonCredsSchemasGetById['data']> {
const pattern = { endpoint: EventAnonCredsSchemasGetById.token };
return this.natsClient
.send<EventAnonCredsSchemasGetById, EventAnonCredsSchemasGetByIdInput>(
pattern,
payload,
EventAnonCredsSchemasGetById.token,
{ tenantId, schemaId },
)
.pipe(map((result) => result.data));
}
public register(
payload: EventAnonCredsSchemasRegisterInput,
tenantId: string,
payload: Omit<EventAnonCredsSchemasRegisterInput, 'tenantId'>,
): Observable<EventAnonCredsSchemasRegister['data']> {
const pattern = { endpoint: EventAnonCredsSchemasRegister.token };
return this.natsClient
.send<EventAnonCredsSchemasRegister, EventAnonCredsSchemasRegisterInput>(
pattern,
payload,
EventAnonCredsSchemasRegister.token,
{ ...payload, tenantId },
)
.pipe(map((result) => result.data));
}
......
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