diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml
index cff59388..756409b0 100644
--- a/.github/workflows/Release.yml
+++ b/.github/workflows/Release.yml
@@ -31,18 +31,18 @@ jobs:
- name: Test
run: |
npx nx run-many --target=test --all --code-coverage --coverage --reporters=default --reporters=default --coverageReporters=cobertura,html,json
- SUMMARY=$(node ./tools/utils/merge-codecoverage/index.js | grep "All files" | awk '{print $4}')
- echo "COVERAGE=$(echo ${SUMMARY})" >> $GITHUB_ENV
- - name: Cretae Badge
- uses: schneegans/dynamic-badges-action@v1.0.0
- with:
- auth: ${{ secrets.GIST_SECRET }}
- gistID: ${{ secrets.GIST_ID }}
- filename: coverage-json-api.json
- label: Test Coverage
- message: ${{ env.COVERAGE }}
- color: green
- namedLogo: jest
+# SUMMARY=$(node ./tools/utils/merge-codecoverage/index.js | grep "All files" | awk '{print $4}')
+# echo "COVERAGE=$(echo ${SUMMARY})" >> $GITHUB_ENV
+# - name: Cretae Badge
+# uses: schneegans/dynamic-badges-action@v1.0.0
+# with:
+# auth: ${{ secrets.GIST_SECRET }}
+# gistID: ${{ secrets.GIST_ID }}
+# filename: coverage-json-api.json
+# label: Test Coverage
+# message: ${{ env.COVERAGE }}
+# color: green
+# namedLogo: jest
- name: Deploy
run: npx nx affected --target=deploy --base=$BEFORE_SHA
diff --git a/README.md b/README.md
index 9a630f38..6c0050f3 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
- Json API plugin for
+ Json API plugins for
NestJS
framework
@@ -15,12 +15,9 @@
Tools to implement JSON API, such as, end point, query params, body params, validation and transformation response.
-## Description
-
-
-This plugin works upon TypeOrm library, which is used as the main database abstraction layer tool. The module automatically generates an API according to JSON API specification from the database structure (TypeORM entities). It supports features such as requests validation based on database fields types, request filtering, endpoints extending, data relations control and much more. Our module significantly reduces the development time of REST services by removing the need to negotiate the mechanism of client-server interaction and implementing automatic API generation without the need to write any code.
-
-
+- *[json-api-nestjs](https://github.com/klerick/nestjs-json-api/tree/master/libs/json-api-nestjs)* - plugin for create CRUD overs JSON API
+- *json-api-nestjs-sdk* - tool for client, call api over *json-api-nestjs*(coming soon...)
+- *kson-api-nestjs-acl* - tool for acl over *json-api-nestjs*(coming soon...)
## Installation
```bash
diff --git a/apps/example/src/app/resources/controllers/extend-book-list/extend-book-list.controller.ts b/apps/example/src/app/resources/controllers/extend-book-list/extend-book-list.controller.ts
new file mode 100644
index 00000000..79d5c0d6
--- /dev/null
+++ b/apps/example/src/app/resources/controllers/extend-book-list/extend-book-list.controller.ts
@@ -0,0 +1,8 @@
+import { ParseUUIDPipe } from '@nestjs/common';
+import { BookList } from 'database';
+import { JsonApi } from 'json-api-nestjs';
+
+@JsonApi(BookList, {
+ pipeForId: ParseUUIDPipe,
+})
+export class ExtendBookListController {}
diff --git a/apps/example/src/app/resources/controllers/extend-user/extend-user.controller.ts b/apps/example/src/app/resources/controllers/extend-user/extend-user.controller.ts
index 0012f242..2eec2fa7 100644
--- a/apps/example/src/app/resources/controllers/extend-user/extend-user.controller.ts
+++ b/apps/example/src/app/resources/controllers/extend-user/extend-user.controller.ts
@@ -1,5 +1,5 @@
import { Get, Param, Inject } from '@nestjs/common';
-
+import { HttpService } from '@nestjs/axios';
import { Users } from 'database';
import {
JsonApi,
@@ -10,6 +10,7 @@ import {
QueryParams,
} from 'json-api-nestjs';
import { ExampleService } from '../../service/example/example.service';
+import { map } from 'rxjs';
@JsonApi(Users, {
allowMethod: excludeMethod(['deleteRelationship']),
@@ -18,6 +19,7 @@ import { ExampleService } from '../../service/example/example.service';
export class ExtendUserController extends JsonBaseController {
@InjectService() public service: JsonApiService;
@Inject(ExampleService) protected exampleService: ExampleService;
+ @Inject(HttpService) protected httpService: HttpService;
public override getAll(query: QueryParams) {
return this.service.getAll({ query });
@@ -27,4 +29,11 @@ export class ExtendUserController extends JsonBaseController {
testOne(@Param('id') id: string): string {
return this.exampleService.testMethode(id);
}
+
+ @Get('test-http')
+ testHttp() {
+ return this.httpService
+ .get('http://localhost:3333/api/v1/book-list')
+ .pipe(map((r) => r.data));
+ }
}
diff --git a/apps/example/src/app/resources/resources.module.ts b/apps/example/src/app/resources/resources.module.ts
index 9aa6fa54..1064b86b 100644
--- a/apps/example/src/app/resources/resources.module.ts
+++ b/apps/example/src/app/resources/resources.module.ts
@@ -1,16 +1,19 @@
import { Module } from '@nestjs/common';
import { JsonApiModule } from 'json-api-nestjs';
-import { Users, Addresses, Comments, Roles } from 'database';
+import { HttpModule } from '@nestjs/axios';
+import { Users, Addresses, Comments, Roles, BookList } from 'database';
import { ExtendUserController } from './controllers/extend-user/extend-user.controller';
+import { ExtendBookListController } from './controllers/extend-book-list/extend-book-list.controller';
import { ExampleService } from './service/example/example.service';
@Module({
imports: [
JsonApiModule.forRoot({
- entities: [Users, Addresses, Comments, Roles],
- controllers: [ExtendUserController],
+ entities: [Users, Addresses, Comments, Roles, BookList],
+ controllers: [ExtendUserController, ExtendBookListController],
providers: [ExampleService],
+ imports: [HttpModule],
options: {
debug: true,
maxExecutionTime: 3000,
diff --git a/libs/database/src/lib/config.ts b/libs/database/src/lib/config.ts
index a77099eb..16fc73eb 100644
--- a/libs/database/src/lib/config.ts
+++ b/libs/database/src/lib/config.ts
@@ -1,11 +1,11 @@
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import { config as ormConfig } from './config-cli';
-import { Roles, Comments, Users, Addresses } from './entities';
+import { Roles, Comments, Users, Addresses, BookList } from './entities';
export const config: TypeOrmModuleOptions = {
...ormConfig,
...{
- entities: [Roles, Comments, Users, Addresses],
+ entities: [Roles, Comments, Users, Addresses, BookList],
},
};
diff --git a/libs/database/src/lib/entities/book-list.ts b/libs/database/src/lib/entities/book-list.ts
new file mode 100644
index 00000000..fa0caf7f
--- /dev/null
+++ b/libs/database/src/lib/entities/book-list.ts
@@ -0,0 +1,38 @@
+import {
+ Column,
+ Entity,
+ PrimaryGeneratedColumn,
+ UpdateDateColumn,
+} from 'typeorm';
+import { IsEmpty, IsNotEmpty } from 'class-validator';
+
+@Entity('book_list')
+export class BookList {
+ @PrimaryGeneratedColumn()
+ public id: string;
+
+ @IsNotEmpty()
+ @Column({
+ type: 'text',
+ nullable: false,
+ })
+ public text: string;
+
+ @IsEmpty()
+ @Column({
+ name: 'created_at',
+ type: 'timestamp',
+ nullable: true,
+ default: 'CURRENT_TIMESTAMP',
+ })
+ public createdAt: Date;
+
+ @IsEmpty()
+ @UpdateDateColumn({
+ name: 'updated_at',
+ type: 'timestamp',
+ nullable: true,
+ default: 'CURRENT_TIMESTAMP',
+ })
+ public updatedAt: Date;
+}
diff --git a/libs/database/src/lib/entities/index.ts b/libs/database/src/lib/entities/index.ts
index c3bf7220..35a21523 100644
--- a/libs/database/src/lib/entities/index.ts
+++ b/libs/database/src/lib/entities/index.ts
@@ -3,3 +3,4 @@ export * from './roles';
export * from './users';
export * from './comments';
export * from './users-have-roles';
+export * from './book-list';
diff --git a/libs/database/src/lib/migrations/1665469071344-CreateBookTable.ts b/libs/database/src/lib/migrations/1665469071344-CreateBookTable.ts
new file mode 100644
index 00000000..d1601bfc
--- /dev/null
+++ b/libs/database/src/lib/migrations/1665469071344-CreateBookTable.ts
@@ -0,0 +1,52 @@
+import {
+ MigrationInterface,
+ QueryRunner,
+ Table,
+ TableColumn,
+ TableForeignKey,
+} from 'typeorm';
+
+export class CreateCommentsTable1665469071344 implements MigrationInterface {
+ protected readonly tableName = 'book_list';
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`
+ CREATE EXTENSION IF NOT EXISTS "uuid-ossp"
+ `);
+ await queryRunner.createTable(
+ new Table({
+ name: this.tableName,
+ columns: [
+ new TableColumn({
+ name: 'id',
+ type: 'uuid',
+ isGenerated: true,
+ isPrimary: true,
+ unsigned: true,
+ generationStrategy: 'uuid',
+ }),
+ new TableColumn({
+ name: 'text',
+ type: 'text',
+ isNullable: false,
+ }),
+ new TableColumn({
+ name: 'created_at',
+ type: 'timestamp',
+ isNullable: true,
+ default: 'CURRENT_TIMESTAMP',
+ }),
+ new TableColumn({
+ name: 'updated_at',
+ type: 'timestamp',
+ isNullable: true,
+ default: 'CURRENT_TIMESTAMP',
+ }),
+ ],
+ })
+ );
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.dropTable(this.tableName);
+ }
+}
diff --git a/libs/json-api-nestjs/README.md b/libs/json-api-nestjs/README.md
index 7e5ffc2e..81d5c4ea 100644
--- a/libs/json-api-nestjs/README.md
+++ b/libs/json-api-nestjs/README.md
@@ -1,6 +1,7 @@
-****strong text****
# json-api-nestjs
+This plugin works upon TypeOrm library, which is used as the main database abstraction layer tool. The module automatically generates an API according to JSON API specification from the database structure (TypeORM entities). It supports features such as requests validation based on database fields types, request filtering, endpoints extending, data relations control and much more. Our module significantly reduces the development time of REST services by removing the need to negotiate the mechanism of client-server interaction and implementing automatic API generation without the need to write any code.
+
## Installation
```bash
@@ -47,9 +48,11 @@ export interface ModuleOptions {
controllers?: NestController[]; // List of controller, if you need extend default present
connectionName?: string; // Type orm connection name: "default" is default name
providers?: NestProvider[]; // List of addition provider for useing in custom controller
+ imports?: NestImport[]; // List of addition module for useing in custom controller
options?: {
requiredSelectField?: boolean; // Need list of select field in get endpoint, try is default
debug?: boolean; // Debug info in result object
+ pipeForId?: Type // Nestjs pipe for validate id params, by default ParseIntPipe
};
}
```
diff --git a/libs/json-api-nestjs/src/lib/config/bindings.ts b/libs/json-api-nestjs/src/lib/config/bindings.ts
index 2713efd5..78a98b19 100644
--- a/libs/json-api-nestjs/src/lib/config/bindings.ts
+++ b/libs/json-api-nestjs/src/lib/config/bindings.ts
@@ -18,6 +18,7 @@ import {
queryTransformSchemaMixin,
bodyRelationshipPipeMixin,
bodyRelationshipPatchPipeMixin,
+ idPipeMixin,
} from '../mixin/pipes';
import { PARAMS_RELATION_NAME, PARAMS_RESOURCE_ID } from '../constants';
@@ -49,7 +50,7 @@ const Bindings: BindingsConfig = {
{
property: PARAMS_RESOURCE_ID,
decorator: Param,
- mixins: [() => ParseIntPipe],
+ mixins: [idPipeMixin],
},
{
decorator: Query,
@@ -71,7 +72,7 @@ const Bindings: BindingsConfig = {
{
property: PARAMS_RESOURCE_ID,
decorator: Param,
- mixins: [() => ParseIntPipe],
+ mixins: [idPipeMixin],
},
],
},
@@ -96,7 +97,7 @@ const Bindings: BindingsConfig = {
{
property: PARAMS_RESOURCE_ID,
decorator: Param,
- mixins: [() => ParseIntPipe],
+ mixins: [idPipeMixin],
},
{
decorator: Body,
@@ -113,7 +114,7 @@ const Bindings: BindingsConfig = {
{
property: PARAMS_RESOURCE_ID,
decorator: Param,
- mixins: [() => ParseIntPipe],
+ mixins: [idPipeMixin],
},
{
property: PARAMS_RELATION_NAME,
@@ -131,7 +132,7 @@ const Bindings: BindingsConfig = {
{
property: PARAMS_RESOURCE_ID,
decorator: Param,
- mixins: [() => ParseIntPipe],
+ mixins: [idPipeMixin],
},
{
property: PARAMS_RELATION_NAME,
@@ -153,7 +154,7 @@ const Bindings: BindingsConfig = {
{
property: PARAMS_RESOURCE_ID,
decorator: Param,
- mixins: [() => ParseIntPipe],
+ mixins: [idPipeMixin],
},
{
property: PARAMS_RELATION_NAME,
@@ -175,7 +176,7 @@ const Bindings: BindingsConfig = {
{
property: PARAMS_RESOURCE_ID,
decorator: Param,
- mixins: [() => ParseIntPipe],
+ mixins: [idPipeMixin],
},
{
property: PARAMS_RELATION_NAME,
diff --git a/libs/json-api-nestjs/src/lib/constants/defaults.ts b/libs/json-api-nestjs/src/lib/constants/defaults.ts
index e5a7bdf3..b3e07948 100644
--- a/libs/json-api-nestjs/src/lib/constants/defaults.ts
+++ b/libs/json-api-nestjs/src/lib/constants/defaults.ts
@@ -1,3 +1,4 @@
+import { ParseIntPipe } from '@nestjs/common';
import { ConfigParam } from '../types';
export const DEFAULT_QUERY_PAGE = 1;
@@ -8,4 +9,5 @@ export const ConfigParamDefault: ConfigParam = {
debug: true,
maxExecutionTime: 5000,
requiredSelectField: true,
+ pipeForId: ParseIntPipe,
};
diff --git a/libs/json-api-nestjs/src/lib/factory/ajv/schema/body-relationship-patch-schema.json b/libs/json-api-nestjs/src/lib/factory/ajv/schema/body-relationship-patch-schema.json
index 1c56b0dc..16274a6f 100644
--- a/libs/json-api-nestjs/src/lib/factory/ajv/schema/body-relationship-patch-schema.json
+++ b/libs/json-api-nestjs/src/lib/factory/ajv/schema/body-relationship-patch-schema.json
@@ -34,9 +34,7 @@
"type": "string"
},
"id": {
- "type": "string",
- "pattern": "^\\d+$",
- "description": "Use string should be as number string"
+ "type": "string"
}
},
"required": ["type", "id"]
diff --git a/libs/json-api-nestjs/src/lib/factory/ajv/schema/body-relationship-schema.json b/libs/json-api-nestjs/src/lib/factory/ajv/schema/body-relationship-schema.json
index ab2069c3..6235d9ce 100644
--- a/libs/json-api-nestjs/src/lib/factory/ajv/schema/body-relationship-schema.json
+++ b/libs/json-api-nestjs/src/lib/factory/ajv/schema/body-relationship-schema.json
@@ -30,9 +30,7 @@
"type": "string"
},
"id": {
- "type": "string",
- "pattern": "^\\d+$",
- "description": "Use string should be as number string"
+ "type": "string"
}
},
"required": ["type", "id"]
diff --git a/libs/json-api-nestjs/src/lib/factory/ajv/utils/input-body-patch-schema.ts b/libs/json-api-nestjs/src/lib/factory/ajv/utils/input-body-patch-schema.ts
index 660fcdb2..bd756f59 100644
--- a/libs/json-api-nestjs/src/lib/factory/ajv/utils/input-body-patch-schema.ts
+++ b/libs/json-api-nestjs/src/lib/factory/ajv/utils/input-body-patch-schema.ts
@@ -21,12 +21,18 @@ export function inputBodyPatchSchema(
schemaName,
arrayPropsConfig
);
+ const patternObject: Record = {};
+ if (
+ Reflect.getMetadata('design:type', entity['prototype'], 'id') === Number
+ ) {
+ patternObject.pattern = '^\\d+$';
+ patternObject.description = 'Use string should be as number string';
+ }
json.properties.data.properties = {
...{
id: {
type: 'string',
- pattern: '^\\d+$',
- description: 'Use string should be as number string',
+ ...patternObject,
},
},
...json.properties.data.properties,
diff --git a/libs/json-api-nestjs/src/lib/factory/ajv/utils/input-body-post-schema.ts b/libs/json-api-nestjs/src/lib/factory/ajv/utils/input-body-post-schema.ts
index 04b44a0e..a5d5819c 100644
--- a/libs/json-api-nestjs/src/lib/factory/ajv/utils/input-body-post-schema.ts
+++ b/libs/json-api-nestjs/src/lib/factory/ajv/utils/input-body-post-schema.ts
@@ -105,9 +105,15 @@ export function inputBodyPostSchema(
...relDataType.properties.data.properties,
type: {
...relDataType.properties.data.properties.type,
- enum: [
- camelToKebab(getEntityName(arrayPropsConfig.relationType[item])),
- ],
+ ...(arrayPropsConfig.relationType[item]
+ ? {
+ enum: [
+ camelToKebab(
+ getEntityName(arrayPropsConfig.relationType[item])
+ ),
+ ],
+ }
+ : {}),
},
},
};
diff --git a/libs/json-api-nestjs/src/lib/factory/ajv/utils/transform-query-schema.ts b/libs/json-api-nestjs/src/lib/factory/ajv/utils/transform-query-schema.ts
index 2e325754..8ed99ea7 100644
--- a/libs/json-api-nestjs/src/lib/factory/ajv/utils/transform-query-schema.ts
+++ b/libs/json-api-nestjs/src/lib/factory/ajv/utils/transform-query-schema.ts
@@ -93,8 +93,11 @@ export function transformQuerySchema(
filter: {},
}
);
-
- json.$defs['includeDefs'].items.enum.push(...Object.keys(relationsField));
+ if (Object.keys(relationsField).length === 0) {
+ delete json.$defs['includeDefs'].items.enum;
+ } else {
+ json.$defs['includeDefs'].items.enum.push(...Object.keys(relationsField));
+ }
json.$defs['sortDefs'].properties = {
...json.$defs['sortDefs'].properties,
diff --git a/libs/json-api-nestjs/src/lib/helper/bind-controller/index.ts b/libs/json-api-nestjs/src/lib/helper/bind-controller/index.ts
index 4a1b17a3..2f9a3016 100644
--- a/libs/json-api-nestjs/src/lib/helper/bind-controller/index.ts
+++ b/libs/json-api-nestjs/src/lib/helper/bind-controller/index.ts
@@ -8,24 +8,31 @@ import {
} from '@nestjs/common';
import { Bindings } from '../../config/bindings';
-import { NestController, Entity, DecoratorOptions } from '../../types';
+import {
+ NestController,
+ Entity,
+ DecoratorOptions,
+ ConfigParam,
+ MethodName,
+} from '../../types';
import { JSON_API_DECORATOR_OPTIONS } from '../../constants';
export function bindController(
controller: NestController,
entity: Entity,
- connectionName: string
+ connectionName: string,
+ config: ConfigParam
): void {
for (const methodName in Bindings) {
const { name, path, parameters, method, implementation } =
- Bindings[methodName];
+ Bindings[methodName as MethodName];
const decoratorOptions: DecoratorOptions = Reflect.getMetadata(
JSON_API_DECORATOR_OPTIONS,
controller
);
if (decoratorOptions) {
- const { allowMethod = [] } = decoratorOptions;
+ const { allowMethod = Object.keys(Bindings) } = decoratorOptions;
if (!allowMethod.includes(name)) continue;
}
@@ -35,6 +42,7 @@ export function bindController(
implementationResultFunction = controller.prototype[name];
}
controller.prototype[name] = function (...args) {
+ // @ts-ignore
return implementationResultFunction.call(this, ...args);
};
@@ -69,8 +77,14 @@ export function bindController(
for (const key in parameters) {
const parameter = parameters[key];
const { property, decorator, mixins } = parameter;
- const resultMixin = mixins.map((mixin) => mixin(entity, connectionName));
- decorator(property, ...resultMixin)(controller.prototype, name, key);
+ const resultMixin = mixins.map((mixin) =>
+ mixin(entity, connectionName, config)
+ );
+ decorator(property, ...resultMixin)(
+ controller.prototype,
+ name,
+ parseInt(key, 10)
+ );
}
}
}
diff --git a/libs/json-api-nestjs/src/lib/helper/swagger/index.ts b/libs/json-api-nestjs/src/lib/helper/swagger/index.ts
index e5a864d2..c9302ba4 100644
--- a/libs/json-api-nestjs/src/lib/helper/swagger/index.ts
+++ b/libs/json-api-nestjs/src/lib/helper/swagger/index.ts
@@ -35,7 +35,7 @@ export function setSwaggerDecorator(
for (const method in Bindings) {
if (decoratorOptions) {
- const { allowMethod = [] } = decoratorOptions;
+ const { allowMethod = Object.keys(Bindings) } = decoratorOptions;
if (!allowMethod.includes(method as MethodName)) {
continue;
diff --git a/libs/json-api-nestjs/src/lib/helper/swagger/method/get-all.ts b/libs/json-api-nestjs/src/lib/helper/swagger/method/get-all.ts
index 8c0a1922..5da9bb61 100644
--- a/libs/json-api-nestjs/src/lib/helper/swagger/method/get-all.ts
+++ b/libs/json-api-nestjs/src/lib/helper/swagger/method/get-all.ts
@@ -222,7 +222,10 @@ export function getAll(
schema: {
type: 'object',
},
- example: { target: currentField.join(','), [relationsFields[0]]: 'id' },
+ example: {
+ target: currentField.join(','),
+ ...(relationsFields.length > 0 ? { [relationsFields[0]]: 'id' } : {}),
+ },
description: `Object of field for select field from "${entityName}" resource`,
})(controller.prototype, binding.name, descriptor);
@@ -236,7 +239,9 @@ export function getAll(
},
example: {
[currentField[0]]: { eq: 'test' },
- [`${relationsFields[0]}.id`]: { ne: '1' },
+ ...(relationsFields.length > 0
+ ? { [`${relationsFields[0]}.id`]: { ne: '1' } }
+ : {}),
},
description: `Object of filter for select items from "${entityName}" resource`,
})(controller.prototype, binding.name, descriptor);
diff --git a/libs/json-api-nestjs/src/lib/helper/swagger/method/get-one.ts b/libs/json-api-nestjs/src/lib/helper/swagger/method/get-one.ts
index db1c4e0d..d8d2de3e 100644
--- a/libs/json-api-nestjs/src/lib/helper/swagger/method/get-one.ts
+++ b/libs/json-api-nestjs/src/lib/helper/swagger/method/get-one.ts
@@ -44,7 +44,10 @@ export function getOne(
ApiParam({
name: 'id',
required: true,
- type: 'integer',
+ type:
+ Reflect.getMetadata('design:type', entity['prototype'], 'id') === Number
+ ? 'integer'
+ : 'string',
description: `ID of resource "${entityName}"`,
})(controller.prototype, binding.name, descriptor);
@@ -64,7 +67,10 @@ export function getOne(
schema: {
type: 'object',
},
- example: { target: currentField.join(','), [relationsFields[0]]: 'id' },
+ example: {
+ target: currentField.join(','),
+ ...(relationsFields.length > 0 ? { [relationsFields[0]]: 'id' } : {}),
+ },
description: `Object of field for select field from "${entityName}" resource`,
})(controller.prototype, binding.name, descriptor);
diff --git a/libs/json-api-nestjs/src/lib/helper/swagger/method/get-relationship.ts b/libs/json-api-nestjs/src/lib/helper/swagger/method/get-relationship.ts
index fff95be3..826bbc89 100644
--- a/libs/json-api-nestjs/src/lib/helper/swagger/method/get-relationship.ts
+++ b/libs/json-api-nestjs/src/lib/helper/swagger/method/get-relationship.ts
@@ -25,7 +25,10 @@ export function getRelationship(
ApiParam({
name: 'id',
required: true,
- type: 'integer',
+ type:
+ Reflect.getMetadata('design:type', entity['prototype'], 'id') === Number
+ ? 'integer'
+ : 'string',
description: `ID of resource "${entityName}"`,
})(controller.prototype, binding.name, descriptor);
diff --git a/libs/json-api-nestjs/src/lib/helper/swagger/method/patch-one.ts b/libs/json-api-nestjs/src/lib/helper/swagger/method/patch-one.ts
index 5c601547..76cbd5e3 100644
--- a/libs/json-api-nestjs/src/lib/helper/swagger/method/patch-one.ts
+++ b/libs/json-api-nestjs/src/lib/helper/swagger/method/patch-one.ts
@@ -37,11 +37,14 @@ export function patchOne(
ApiParam({
name: 'id',
required: true,
- type: 'integer',
+ type:
+ Reflect.getMetadata('design:type', entity['prototype'], 'id') === Number
+ ? 'integer'
+ : 'string',
description: `ID of resource "${entityName}"`,
})(controller.prototype, binding.name, descriptor);
- const jsonSchemaProperty = jsonSchemaBody(entity, currentField);
+ const jsonSchemaProperty = jsonSchemaBody(entity, currentField, false);
jsonSchemaProperty.data.properties = {
...{
id: {
diff --git a/libs/json-api-nestjs/src/lib/helper/swagger/method/patch-relationship.ts b/libs/json-api-nestjs/src/lib/helper/swagger/method/patch-relationship.ts
index 098abef7..4f5d11e0 100644
--- a/libs/json-api-nestjs/src/lib/helper/swagger/method/patch-relationship.ts
+++ b/libs/json-api-nestjs/src/lib/helper/swagger/method/patch-relationship.ts
@@ -56,7 +56,10 @@ export function patchRelationship(
ApiParam({
name: 'id',
required: true,
- type: 'integer',
+ type:
+ Reflect.getMetadata('design:type', entity['prototype'], 'id') === Number
+ ? 'integer'
+ : 'string',
description: `ID of resource "${entityName}"`,
})(controller.prototype, binding.name, descriptor);
diff --git a/libs/json-api-nestjs/src/lib/helper/swagger/method/post-relationship.ts b/libs/json-api-nestjs/src/lib/helper/swagger/method/post-relationship.ts
index ca484064..fb608356 100644
--- a/libs/json-api-nestjs/src/lib/helper/swagger/method/post-relationship.ts
+++ b/libs/json-api-nestjs/src/lib/helper/swagger/method/post-relationship.ts
@@ -56,7 +56,10 @@ export function postRelationship(
ApiParam({
name: 'id',
required: true,
- type: 'integer',
+ type:
+ Reflect.getMetadata('design:type', entity['prototype'], 'id') === Number
+ ? 'integer'
+ : 'string',
description: `ID of resource "${entityName}"`,
})(controller.prototype, binding.name, descriptor);
diff --git a/libs/json-api-nestjs/src/lib/helper/swagger/utils.ts b/libs/json-api-nestjs/src/lib/helper/swagger/utils.ts
index b4a521d8..e63047ae 100644
--- a/libs/json-api-nestjs/src/lib/helper/swagger/utils.ts
+++ b/libs/json-api-nestjs/src/lib/helper/swagger/utils.ts
@@ -7,6 +7,7 @@ import { RelationTypeInFunction } from 'typeorm/metadata/types/RelationTypeInFun
import { Entity } from '../../types';
import { ColumnType } from 'typeorm/driver/types/ColumnTypes';
import { camelToKebab, getEntityName, nameIt } from '../utils';
+import { idPipeMixin } from '../../mixin/pipes';
export function getRelationsOptions(entity: Entity) {
return getMetadataArgsStorage()
@@ -40,7 +41,11 @@ export function getOptionsFiled(entity: Entity) {
}, {});
}
-export function jsonSchemaBody(entity: Entity, currentField: string[]) {
+export function jsonSchemaBody(
+ entity: Entity,
+ currentField: string[],
+ needRequired = true
+) {
const optionsFiled = getOptionsFiled(entity);
const relationsOptions = getRelationsOptions(entity);
return {
@@ -95,9 +100,9 @@ export function jsonSchemaBody(entity: Entity, currentField: string[]) {
acum[item] = value;
return acum;
}, {}),
- required: currentField.filter(
- (i) => optionsFiled[i] === IS_NOT_EMPTY
- ),
+ required: needRequired
+ ? currentField.filter((i) => optionsFiled[i] === IS_NOT_EMPTY)
+ : [],
},
relationships: {
type: 'object',
@@ -140,9 +145,11 @@ export function jsonSchemaBody(entity: Entity, currentField: string[]) {
};
return acum;
}, {}),
- required: Object.keys(relationsOptions).filter(
- (i) => optionsFiled[i] === IS_NOT_EMPTY
- ),
+ required: needRequired
+ ? Object.keys(relationsOptions).filter(
+ (i) => optionsFiled[i] === IS_NOT_EMPTY
+ )
+ : [],
},
},
required: ['type', 'attributes'],
diff --git a/libs/json-api-nestjs/src/lib/helper/utils/index.spec.ts b/libs/json-api-nestjs/src/lib/helper/utils/index.spec.ts
index 2d9d78ff..4269b420 100644
--- a/libs/json-api-nestjs/src/lib/helper/utils/index.spec.ts
+++ b/libs/json-api-nestjs/src/lib/helper/utils/index.spec.ts
@@ -18,9 +18,10 @@ describe('Test utils', () => {
it('snakeToCamel', () => {
const result = snakeToCamel('test_test');
const result1 = snakeToCamel('test-test');
-
+ const result2 = snakeToCamel('testTest');
expect(result).toBe('testTest');
expect(result1).toBe('testTest');
+ expect(result2).toBe('testTest');
});
it('isString', () => {
diff --git a/libs/json-api-nestjs/src/lib/helper/utils/index.ts b/libs/json-api-nestjs/src/lib/helper/utils/index.ts
index a4dda6c3..0de9a9ae 100644
--- a/libs/json-api-nestjs/src/lib/helper/utils/index.ts
+++ b/libs/json-api-nestjs/src/lib/helper/utils/index.ts
@@ -32,6 +32,9 @@ export function isString(value: T): value is P {
}
export function snakeToCamel(str: string): string {
+ if (!str.match(/[\s_-]/g)) {
+ return str;
+ }
return str
.toLowerCase()
.replace(/([-_][a-z])/g, (group) =>
diff --git a/libs/json-api-nestjs/src/lib/json-api-nestjs-common.module.ts b/libs/json-api-nestjs/src/lib/json-api-nestjs-common.module.ts
index 132a8bf4..df6f14ec 100644
--- a/libs/json-api-nestjs/src/lib/json-api-nestjs-common.module.ts
+++ b/libs/json-api-nestjs/src/lib/json-api-nestjs-common.module.ts
@@ -30,7 +30,7 @@ export class JsonApiNestJsCommonModule {
);
return {
module: JsonApiNestJsCommonModule,
- imports: [typeOrmModule],
+ imports: [typeOrmModule, ...(options.imports || [])],
providers: [
...(options.providers || []),
ajvFactory,
@@ -44,6 +44,7 @@ export class JsonApiNestJsCommonModule {
ajvFactory,
optionProvider,
ErrorInterceptors,
+ ...(options.imports || []),
],
};
}
diff --git a/libs/json-api-nestjs/src/lib/json-api.module.ts b/libs/json-api-nestjs/src/lib/json-api.module.ts
index c8f3e3ab..c4614524 100644
--- a/libs/json-api-nestjs/src/lib/json-api.module.ts
+++ b/libs/json-api-nestjs/src/lib/json-api.module.ts
@@ -5,9 +5,9 @@ import {
DEFAULT_CONNECTION_NAME,
JSON_API_DECORATOR_ENTITY,
ConfigParamDefault,
-} from '../lib/constants';
-import { BaseModuleClass } from '../lib/mixin';
-import { ModuleOptions } from '../lib/types';
+} from './constants';
+import { BaseModuleClass } from './mixin';
+import { ModuleOptions } from './types';
@Module({})
export class JsonApiModule {
@@ -22,7 +22,7 @@ export class JsonApiModule {
...ConfigParamDefault,
...options.options,
};
-
+ const commonModule = JsonApiNestJsCommonModule.forRoot(options);
const entityImport = options.entities.map((entity) => {
const controller = (options.controllers || []).find(
(item) =>
@@ -37,10 +37,7 @@ export class JsonApiModule {
...options.options,
},
});
- module.imports = [
- ...module.imports,
- JsonApiNestJsCommonModule.forRoot(options),
- ];
+ module.imports = [commonModule, ...module.imports];
return module;
});
diff --git a/libs/json-api-nestjs/src/lib/mixin/controller/json-base/json-base.controller.ts b/libs/json-api-nestjs/src/lib/mixin/controller/json-base/json-base.controller.ts
index b523f828..b29aa83b 100644
--- a/libs/json-api-nestjs/src/lib/mixin/controller/json-base/json-base.controller.ts
+++ b/libs/json-api-nestjs/src/lib/mixin/controller/json-base/json-base.controller.ts
@@ -18,7 +18,7 @@ export class JsonBaseController implements ControllerTypes {
}
getOne(
- id: number,
+ id: number | string,
query: QueryParams,
rest
): ReturnType['getOne']> {
@@ -31,7 +31,7 @@ export class JsonBaseController implements ControllerTypes {
}
deleteOne(
- id: number,
+ id: number | string,
rest
): ReturnType['deleteOne']> {
return this.serviceMixin.deleteOne({
@@ -51,7 +51,7 @@ export class JsonBaseController implements ControllerTypes {
}
patchOne(
- id: number,
+ id: number | string,
body: ResourceRequestObject['data'],
rest
): ReturnType['patchOne']> {
@@ -66,7 +66,7 @@ export class JsonBaseController implements ControllerTypes {
}
getRelationship(
- id: number,
+ id: number | string,
relName: string,
rest
): ReturnType['getRelationship']> {
@@ -76,7 +76,7 @@ export class JsonBaseController implements ControllerTypes {
}
deleteRelationship(
- id: number,
+ id: number | string,
relName: string,
body: Exclude['data'], 'links'>,
rest
@@ -88,7 +88,7 @@ export class JsonBaseController implements ControllerTypes {
}
patchRelationship(
- id: number,
+ id: number | string,
relName: string,
body: Exclude['data'], 'links'>,
rest
@@ -100,7 +100,7 @@ export class JsonBaseController implements ControllerTypes {
}
postRelationship(
- id: number,
+ id: number | string,
relName: string,
body: Exclude['data'], 'links'>,
rest
diff --git a/libs/json-api-nestjs/src/lib/mixin/module/module.mixin.ts b/libs/json-api-nestjs/src/lib/mixin/module/module.mixin.ts
index 8077d959..d93a0e08 100644
--- a/libs/json-api-nestjs/src/lib/mixin/module/module.mixin.ts
+++ b/libs/json-api-nestjs/src/lib/mixin/module/module.mixin.ts
@@ -83,7 +83,7 @@ BaseModuleClass.forRoot = function (options): DynamicModule {
...decoratorOptions,
};
- bindController(controllerClass, entity, connectionName);
+ bindController(controllerClass, entity, connectionName, moduleConfig);
setSwaggerDecorator(controllerClass, entity, moduleConfig);
const optionProvider = {
diff --git a/libs/json-api-nestjs/src/lib/mixin/pipes/body-relationship-patch/body-relationship-patch.pipe.spec.ts b/libs/json-api-nestjs/src/lib/mixin/pipes/body-relationship-patch/body-relationship-patch.pipe.spec.ts
index 08ea3778..5225bf3a 100644
--- a/libs/json-api-nestjs/src/lib/mixin/pipes/body-relationship-patch/body-relationship-patch.pipe.spec.ts
+++ b/libs/json-api-nestjs/src/lib/mixin/pipes/body-relationship-patch/body-relationship-patch.pipe.spec.ts
@@ -88,57 +88,6 @@ describe('BodyRelationshipPatchPipe', () => {
}
});
- it('Should be error, incorrect id is no number string', async () => {
- const data = {
- data: { type: 'type', id: 'sdfsf' },
- };
- expect.assertions(7);
- try {
- await pipe.transform(data as any);
- } catch (e) {
- expect(e).toBeInstanceOf(BadRequestException);
- expect(e.response.message[0].detail).toBe('Must be null');
- expect(e.response.message[1].detail).toBe('Must match pattern "^\\d+$"');
- expect(e.response.message[2].detail).toBe(
- 'Must match exactly one schema: "null" or "object"'
- );
- expect(e.response.message[3].detail).toBe('Must be array');
- expect(e.response.message[4].detail).toBe(
- 'Must match exactly one schema: "object" or "array"'
- );
- expect(e.response.message.length).toBeGreaterThan(0);
- }
- });
-
- it('Should be error, array with id no number', async () => {
- const data = {
- data: [
- { type: 'type', id: 'wsdf' },
- { type: 'type', id: '2' },
- ],
- };
- expect.assertions(9);
- try {
- await pipe.transform(data as any);
- } catch (e) {
- expect(e).toBeInstanceOf(BadRequestException);
- expect(e.response.message[0].detail).toBe('Must be null');
- expect(e.response.message[1].detail).toBe('Must be object');
- expect(e.response.message[2].detail).toBe(
- 'Must match exactly one schema: "null" or "object"'
- );
- expect(e.response.message[3].detail).toBe('Must be null');
- expect(e.response.message[4].detail).toBe('Must match pattern "^\\d+$"');
- expect(e.response.message[5].detail).toBe(
- 'Must match exactly one schema: "null" or "object"'
- );
- expect(e.response.message[6].detail).toBe(
- 'Must match exactly one schema: "object" or "array"'
- );
- expect(e.response.message.length).toBeGreaterThan(0);
- }
- });
-
it('Should be error, array with incorrect items', async () => {
const data = {
data: [
@@ -147,7 +96,7 @@ describe('BodyRelationshipPatchPipe', () => {
{ type: 'type', id: '2' },
],
};
- expect.assertions(14);
+ expect.assertions(13);
try {
await pipe.transform(data as any);
} catch (e) {
@@ -171,11 +120,10 @@ describe('BodyRelationshipPatchPipe', () => {
expect(e.response.message[8].detail).toBe(
"Must have required property 'type'"
);
- expect(e.response.message[9].detail).toBe('Must match pattern "^\\d+$"');
- expect(e.response.message[10].detail).toBe(
+ expect(e.response.message[9].detail).toBe(
'Must match exactly one schema: "null" or "object"'
);
- expect(e.response.message[11].detail).toBe(
+ expect(e.response.message[10].detail).toBe(
'Must match exactly one schema: "object" or "array"'
);
expect(e.response.message.length).toBeGreaterThan(0);
diff --git a/libs/json-api-nestjs/src/lib/mixin/pipes/body-relationship/body-relationship.pipe.spec.ts b/libs/json-api-nestjs/src/lib/mixin/pipes/body-relationship/body-relationship.pipe.spec.ts
index 8c2d4ae5..d0cf4f4c 100644
--- a/libs/json-api-nestjs/src/lib/mixin/pipes/body-relationship/body-relationship.pipe.spec.ts
+++ b/libs/json-api-nestjs/src/lib/mixin/pipes/body-relationship/body-relationship.pipe.spec.ts
@@ -82,24 +82,6 @@ describe('BodyRelationshipPipe', () => {
}
});
- it('Should be error, incorrect id is no number string', async () => {
- const data = {
- data: { type: 'type', id: 'sdfsf' },
- };
- expect.assertions(5);
- try {
- await pipe.transform(data as any);
- } catch (e) {
- expect(e).toBeInstanceOf(BadRequestException);
- expect(e.response.message[0].detail).toBe('Must match pattern "^\\d+$"');
- expect(e.response.message[1].detail).toBe('Must be array');
- expect(e.response.message[2].detail).toBe(
- 'Must match exactly one schema: "object" or "array"'
- );
- expect(e.response.message.length).toBeGreaterThan(0);
- }
- });
-
it('Should be error, array is empty', async () => {
const data = {
data: [],
@@ -120,27 +102,6 @@ describe('BodyRelationshipPipe', () => {
}
});
- it('Should be error, array with id no number', async () => {
- const data = {
- data: [
- { type: 'type', id: 'wsdf' },
- { type: 'type', id: '2' },
- ],
- };
- expect.assertions(5);
- try {
- await pipe.transform(data as any);
- } catch (e) {
- expect(e).toBeInstanceOf(BadRequestException);
- expect(e.response.message[0].detail).toBe('Must be object');
- expect(e.response.message[1].detail).toBe('Must match pattern "^\\d+$"');
- expect(e.response.message[2].detail).toBe(
- 'Must match exactly one schema: "object" or "array"'
- );
- expect(e.response.message.length).toBeGreaterThan(0);
- }
- });
-
it('Should be error, array with incorrect items', async () => {
const data = {
data: [
@@ -149,7 +110,7 @@ describe('BodyRelationshipPipe', () => {
{ type: 'type', id: '2' },
],
};
- expect.assertions(8);
+ expect.assertions(7);
try {
await pipe.transform(data as any);
} catch (e) {
@@ -164,8 +125,7 @@ describe('BodyRelationshipPipe', () => {
expect(e.response.message[3].detail).toBe(
"Must have required property 'type'"
);
- expect(e.response.message[4].detail).toBe('Must match pattern "^\\d+$"');
- expect(e.response.message[5].detail).toBe(
+ expect(e.response.message[4].detail).toBe(
'Must match exactly one schema: "object" or "array"'
);
expect(e.response.message.length).toBeGreaterThan(0);
diff --git a/libs/json-api-nestjs/src/lib/mixin/pipes/index.ts b/libs/json-api-nestjs/src/lib/mixin/pipes/index.ts
index d6df361e..77b0521e 100644
--- a/libs/json-api-nestjs/src/lib/mixin/pipes/index.ts
+++ b/libs/json-api-nestjs/src/lib/mixin/pipes/index.ts
@@ -10,7 +10,7 @@ import { BodyInputPatchPipe } from './body-input-patch/body-input-patch.pipe';
import { ParseRelationshipNamePipe } from './parse-relationship-name/parse-relationship-name.pipe';
import { BodyRelationshipPipe } from './body-relationship/body-relationship.pipe';
import { BodyRelationshipPatchPipe } from './body-relationship-patch/body-relationship-patch.pipe';
-import { Entity, PipeMixin } from '../../types';
+import { ConfigParam, Entity, PipeMixin } from '../../types';
import { nameIt } from '../../helper';
function factoryMixin(entity: Entity, connectionName: string, pipe: PipeMixin) {
@@ -94,3 +94,11 @@ export function bodyRelationshipPipeMixin(): PipeMixin {
export function bodyRelationshipPatchPipeMixin(): PipeMixin {
return BodyRelationshipPatchPipe;
}
+
+export function idPipeMixin(
+ entity: Entity,
+ connectionName: string,
+ config: ConfigParam
+): PipeMixin {
+ return config.pipeForId;
+}
diff --git a/libs/json-api-nestjs/src/lib/mixin/pipes/parse-relationship-name/parse-relationship-name.pipe.spec.ts b/libs/json-api-nestjs/src/lib/mixin/pipes/parse-relationship-name/parse-relationship-name.pipe.spec.ts
index fa3eea9b..13f95e38 100644
--- a/libs/json-api-nestjs/src/lib/mixin/pipes/parse-relationship-name/parse-relationship-name.pipe.spec.ts
+++ b/libs/json-api-nestjs/src/lib/mixin/pipes/parse-relationship-name/parse-relationship-name.pipe.spec.ts
@@ -69,7 +69,7 @@ describe('ParseRelationshipNamePipe', () => {
} catch (e) {
expect(e).toBeInstanceOf(BadRequestException);
expect(e.response.message[0].detail).toBe(
- "Relation 'rereerer' does not exist in resource 'users'"
+ `Relation 'rereerer' does not exist in resource 'Users'`
);
expect(e.response.message.length).toBeGreaterThan(0);
}
diff --git a/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/get-all/get-all.spec.ts b/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/get-all/get-all.spec.ts
index cc65e84d..1790f0ad 100644
--- a/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/get-all/get-all.spec.ts
+++ b/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/get-all/get-all.spec.ts
@@ -19,7 +19,7 @@ import {
} from '../../../../../types';
import { snakeToCamel, getProviderName } from '../../../../../helper';
import { transformMixin } from '../../../transform';
-import { typeormMixin } from '../../../typeorm';
+import { typeormMixin } from '../../index';
import { TypeormMixinService } from '../../typeorm.mixin';
describe('GetAll methode test', () => {
@@ -181,10 +181,12 @@ describe('GetAll methode test', () => {
let offsetSpy;
let limitSpy;
let orderBySpy;
+ let aliasString: string;
const createQueryBuilderSpy = jest
.spyOn(repository, 'createQueryBuilder')
.mockImplementationOnce((...alias) => {
const builder = repository.createQueryBuilder(...alias);
+ aliasString = builder.alias;
joinSpy = jest.spyOn(builder, 'leftJoin');
selectSpy = jest.spyOn(builder, 'select');
offsetSpy = jest.spyOn(builder, 'offset');
@@ -204,13 +206,13 @@ describe('GetAll methode test', () => {
);
expect(joinSpy).toBeCalledTimes(0);
expect(selectSpy).toBeCalledTimes(1);
- expect(selectSpy).toBeCalledWith(`users.id`, 'subQueryId');
+ expect(selectSpy).toBeCalledWith(`${aliasString}.id`, 'subQueryId');
expect(offsetSpy).toBeCalledTimes(1);
expect(offsetSpy).toBeCalledWith(0);
expect(limitSpy).toBeCalledTimes(1);
expect(limitSpy).toBeCalledWith(20);
expect(orderBySpy).toBeCalledTimes(1);
- expect(orderBySpy).toBeCalledWith({ ['users.id']: 'ASC' });
+ expect(orderBySpy).toBeCalledWith({ [`${aliasString}.id`]: 'ASC' });
expect(applyQueryFilterRelationSpy).not.toBeCalled();
expect(applyQueryFiltersTargetSpy).not.toBeCalled();
@@ -274,7 +276,7 @@ describe('GetAll methode test', () => {
let resultJoinSpy;
let resultSelectSpy;
let i = 0;
-
+ let aliasString: string;
const originalCreateQueryBuilder =
repository.createQueryBuilder.bind(repository);
const createQueryBuilderSpy = jest
@@ -282,6 +284,7 @@ describe('GetAll methode test', () => {
.mockImplementation((...alias) => {
const builder = originalCreateQueryBuilder(...alias);
if (i === 0) {
+ aliasString = builder.alias;
joinSpy = jest.spyOn(builder, 'leftJoin');
selectSpy = jest.spyOn(builder, 'select');
offsetSpy = jest.spyOn(builder, 'offset');
@@ -315,10 +318,18 @@ describe('GetAll methode test', () => {
});
expect(joinSpy).toBeCalledTimes(2);
- expect(joinSpy).toHaveBeenNthCalledWith(1, 'users.manager', 'manager');
- expect(joinSpy).toHaveBeenNthCalledWith(2, 'users.addresses', 'addresses');
+ expect(joinSpy).toHaveBeenNthCalledWith(
+ 1,
+ `${aliasString}.manager`,
+ 'manager'
+ );
+ expect(joinSpy).toHaveBeenNthCalledWith(
+ 2,
+ `${aliasString}.addresses`,
+ 'addresses'
+ );
expect(selectSpy).toBeCalledTimes(1);
- expect(selectSpy).toBeCalledWith(`users.id`, 'subQueryId');
+ expect(selectSpy).toBeCalledWith(`${aliasString}.id`, 'subQueryId');
expect(offsetSpy).toBeCalledTimes(1);
expect(offsetSpy).toBeCalledWith((page.number - 1) * page.size);
expect(limitSpy).toBeCalledTimes(1);
@@ -326,7 +337,7 @@ describe('GetAll methode test', () => {
expect(orderBySpy).toBeCalledTimes(1);
expect(orderBySpy).toBeCalledWith({
['addresses.country']: 'ASC',
- ['users.login']: 'DESC',
+ [`${aliasString}.login`]: 'DESC',
});
expect(applyQueryFilterRelationSpy).toBeCalledTimes(1);
expect(applyQueryFiltersTargetSpy).toBeCalledTimes(1);
@@ -345,17 +356,17 @@ describe('GetAll methode test', () => {
expect(resultJoinSpy).toBeCalledTimes(2);
expect(resultJoinSpy).toHaveBeenNthCalledWith(
1,
- `users.${include[0]}`,
+ `${aliasString}.${include[0]}`,
include[0]
);
expect(resultJoinSpy).toHaveBeenNthCalledWith(
2,
- `users.${include[1]}`,
+ `${aliasString}.${include[1]}`,
include[1]
);
expect(resultSelectSpy).toBeCalledTimes(1);
- expect(resultSelectSpy).toBeCalledWith([...include, 'users']);
+ expect(resultSelectSpy).toBeCalledWith([...include, aliasString]);
});
it('check query with param and select field', async () => {
@@ -416,7 +427,7 @@ describe('GetAll methode test', () => {
let resultJoinSpy;
let resultSelectSpy;
let i = 0;
-
+ let alisString: string;
const originalCreateQueryBuilder =
repository.createQueryBuilder.bind(repository);
const createQueryBuilderSpy = jest
@@ -424,6 +435,7 @@ describe('GetAll methode test', () => {
.mockImplementation((...alias) => {
const builder = originalCreateQueryBuilder(...alias);
if (i === 0) {
+ alisString = builder.alias;
joinSpy = jest.spyOn(builder, 'leftJoin');
selectSpy = jest.spyOn(builder, 'select');
offsetSpy = jest.spyOn(builder, 'offset');
@@ -458,10 +470,18 @@ describe('GetAll methode test', () => {
});
expect(joinSpy).toBeCalledTimes(2);
- expect(joinSpy).toHaveBeenNthCalledWith(1, 'users.manager', 'manager');
- expect(joinSpy).toHaveBeenNthCalledWith(2, 'users.addresses', 'addresses');
+ expect(joinSpy).toHaveBeenNthCalledWith(
+ 1,
+ `${alisString}.manager`,
+ 'manager'
+ );
+ expect(joinSpy).toHaveBeenNthCalledWith(
+ 2,
+ `${alisString}.addresses`,
+ 'addresses'
+ );
expect(selectSpy).toBeCalledTimes(1);
- expect(selectSpy).toBeCalledWith(`users.id`, 'subQueryId');
+ expect(selectSpy).toBeCalledWith(`${alisString}.id`, 'subQueryId');
expect(offsetSpy).toBeCalledTimes(1);
expect(offsetSpy).toBeCalledWith((page.number - 1) * page.size);
expect(limitSpy).toBeCalledTimes(1);
@@ -469,7 +489,7 @@ describe('GetAll methode test', () => {
expect(orderBySpy).toBeCalledTimes(1);
expect(orderBySpy).toBeCalledWith({
['addresses.country']: 'ASC',
- ['users.login']: 'DESC',
+ [`${alisString}.login`]: 'DESC',
});
expect(applyQueryFilterRelationSpy).toBeCalledTimes(1);
expect(applyQueryFiltersTargetSpy).toBeCalledTimes(1);
@@ -488,30 +508,30 @@ describe('GetAll methode test', () => {
expect(resultJoinSpy).toBeCalledTimes(4);
expect(resultJoinSpy).toHaveBeenNthCalledWith(
1,
- `users.${include[0]}`,
+ `${alisString}.${include[0]}`,
include[0]
);
expect(resultJoinSpy).toHaveBeenNthCalledWith(
2,
- `users.${include[1]}`,
+ `${alisString}.${include[1]}`,
include[1]
);
expect(resultJoinSpy).toHaveBeenNthCalledWith(
3,
- `users.${include[2]}`,
+ `${alisString}.${include[2]}`,
include[2]
);
expect(resultJoinSpy).toHaveBeenNthCalledWith(
4,
- `users.${include[3]}`,
+ `${alisString}.${include[3]}`,
include[3]
);
expect(resultSelectSpy).toBeCalledTimes(1);
expect(resultSelectSpy).toBeCalledWith([
...include.map((i) => `${i}.id`),
- ...fields.target.map((i) => `users.${i}`),
- 'users.id',
+ ...fields.target.map((i) => `${alisString}.${i}`),
+ `${alisString}.id`,
...fields.manager.map((i) => `manager.${i}`),
...fields.comments.map((i) => `comments.${i}`),
]);
diff --git a/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/get-one/get-one.spec.ts b/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/get-one/get-one.spec.ts
index 77933c59..2d8954e0 100644
--- a/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/get-one/get-one.spec.ts
+++ b/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/get-one/get-one.spec.ts
@@ -129,10 +129,12 @@ describe('GetOne methode test', () => {
it('Should be correct query', async () => {
let joinSpy;
let selectSpy;
+ let aliasString;
const createQueryBuilderSpy = jest
.spyOn(repository, 'createQueryBuilder')
.mockImplementationOnce((...alias) => {
const builder = repository.createQueryBuilder(...alias);
+ aliasString = builder.alias;
joinSpy = jest.spyOn(builder, 'leftJoin');
selectSpy = jest.spyOn(builder, 'select');
return builder;
@@ -145,16 +147,18 @@ describe('GetOne methode test', () => {
);
expect(joinSpy).toBeCalledTimes(0);
expect(selectSpy).toBeCalledTimes(1);
- expect(selectSpy).toBeCalledWith([`users`]);
+ expect(selectSpy).toBeCalledWith([aliasString]);
});
it('Should be correct query with include', async () => {
let joinSpy;
let selectSpy;
+ let aliasString;
const createQueryBuilderSpy = jest
.spyOn(repository, 'createQueryBuilder')
.mockImplementationOnce((...alias) => {
const builder = repository.createQueryBuilder(...alias);
+ aliasString = builder.alias;
joinSpy = jest.spyOn(builder, 'leftJoin');
selectSpy = jest.spyOn(builder, 'select');
return builder;
@@ -172,25 +176,27 @@ describe('GetOne methode test', () => {
expect(joinSpy).toBeCalledTimes(2);
expect(joinSpy).toHaveBeenNthCalledWith(
1,
- `users.${defaultField['include'][0]}`,
+ `${aliasString}.${defaultField['include'][0]}`,
defaultField['include'][0]
);
expect(joinSpy).toHaveBeenNthCalledWith(
2,
- `users.${defaultField['include'][1]}`,
+ `${aliasString}.${defaultField['include'][1]}`,
defaultField['include'][1]
);
expect(selectSpy).toBeCalledTimes(1);
- expect(selectSpy).toBeCalledWith([...defaultField['include'], `users`]);
+ expect(selectSpy).toBeCalledWith([...defaultField['include'], aliasString]);
});
it('Should be correct query with params', async () => {
let joinSpy;
let selectSpy;
+ let aliasString;
const createQueryBuilderSpy = jest
.spyOn(repository, 'createQueryBuilder')
.mockImplementationOnce((...alias) => {
const builder = repository.createQueryBuilder(...alias);
+ aliasString = builder.alias;
joinSpy = jest.spyOn(builder, 'leftJoin');
selectSpy = jest.spyOn(builder, 'select');
return builder;
@@ -208,14 +214,14 @@ describe('GetOne methode test', () => {
expect(joinSpy).toBeCalledTimes(1);
expect(joinSpy).toHaveBeenNthCalledWith(
1,
- `users.${defaultField['include'][0]}`,
+ `${aliasString}.${defaultField['include'][0]}`,
defaultField['include'][0]
);
expect(selectSpy).toBeCalledTimes(1);
expect(selectSpy).toBeCalledWith([
`${defaultField['include'][0]}.id`,
- ...defaultField['fields']['target'].map((i) => `users.${i}`),
- 'users.id',
+ ...defaultField['fields']['target'].map((i) => `${aliasString}.${i}`),
+ `${aliasString}.id`,
...defaultField['fields']['addresses'].map((i) => `addresses.${i}`),
]);
});
diff --git a/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/get-relationship/get-relationship.spec.ts b/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/get-relationship/get-relationship.spec.ts
index 42c156bd..683bfbf3 100644
--- a/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/get-relationship/get-relationship.spec.ts
+++ b/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/get-relationship/get-relationship.spec.ts
@@ -18,7 +18,6 @@ import {
} from '../../../../../constants';
import { typeormMixin } from '../../index';
import { getProviderName } from '../../../../../helper';
-import { ResourceRequestObject } from '../../../../../types-common/request';
describe('GetRelationship methode test', () => {
let typeormService: TypeormMixinService;
@@ -110,7 +109,7 @@ describe('GetRelationship methode test', () => {
} catch (e) {
expect(e).toBeInstanceOf(NotFoundException);
expect(e.response.detail).toBe(
- `Resource 'users' with id '2' does not exist`
+ `Resource 'Users' with id '2' does not exist`
);
}
});
diff --git a/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/patch-one/patch-one.spec.ts b/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/patch-one/patch-one.spec.ts
index 76103e8a..a201fa02 100644
--- a/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/patch-one/patch-one.spec.ts
+++ b/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/patch-one/patch-one.spec.ts
@@ -17,7 +17,7 @@ import {
import { typeormMixin } from '../../index';
import { getProviderName } from '../../../../../helper';
-import { ResourceRequestObject } from '../../../../../types-common/request';
+import { ResourceRequestObject } from '../../../../../types-common';
import {
NotFoundException,
UnprocessableEntityException,
@@ -157,7 +157,7 @@ describe('PostOne methode test', () => {
} catch (e) {
expect(e).toBeInstanceOf(NotFoundException);
expect(e.response.detail).toBe(
- `Resource 'users' with id '${body.id}' does not exist`
+ `Resource '${repository.metadata.targetName}' with id '${body.id}' does not exist`
);
}
});
diff --git a/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/patch-one/patch-one.ts b/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/patch-one/patch-one.ts
index 5f45bafe..bda62dc5 100644
--- a/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/patch-one/patch-one.ts
+++ b/libs/json-api-nestjs/src/lib/mixin/service/typeorm/methods/patch-one/patch-one.ts
@@ -23,7 +23,7 @@ export async function patchOne(
const body = options.body as ResourceRequestObject['data'];
const { id: idBody, attributes, relationships } = body;
- if (id !== parseInt(idBody, 10)) {
+ if (`${id}` !== idBody) {
throw new UnprocessableEntityException({
source: { pointer: '/data/id' },
detail: "Data 'id' must be equal to url param",
diff --git a/libs/json-api-nestjs/src/lib/mixin/service/typeorm/utils/utils-methode.spec.ts b/libs/json-api-nestjs/src/lib/mixin/service/typeorm/utils/utils-methode.spec.ts
index 8bb13d1d..1b43519f 100644
--- a/libs/json-api-nestjs/src/lib/mixin/service/typeorm/utils/utils-methode.spec.ts
+++ b/libs/json-api-nestjs/src/lib/mixin/service/typeorm/utils/utils-methode.spec.ts
@@ -13,7 +13,7 @@ import { UtilsMethode } from './utils-methode';
import { snakeToCamel } from '../../../../helper';
import { Filter, FilterOperand } from '../../../../types';
import { OperandsMap, OperandMapForNull } from '../../../../types-common';
-import { ResourceRequestObject } from '../../../../types-common/request';
+import { ResourceRequestObject } from '../../../../types-common';
import {
NotFoundException,
UnprocessableEntityException,
@@ -202,18 +202,18 @@ describe('Utils methode test', () => {
const commentQuery = repository.manager
.getRepository('comments')
- .createQueryBuilder('comments')
- .select('comments.createdBy')
- .where(`comments.createdBy = ${alias}.id`)
+ .createQueryBuilder('Comments')
+ .select('Comments.createdBy')
+ .where(`Comments.createdBy = ${alias}.id`)
.getQuery();
const rolesQuery = repository.manager
.getRepository('users_have_roles')
.createQueryBuilder('users_have_roles')
.select('users_have_roles.user_id', 'users_have_roles_user_id')
- .leftJoin('roles', 'roles', 'users_have_roles.role_id = roles.id')
+ .leftJoin('Roles', 'Roles', 'users_have_roles.role_id = Roles.id')
.where(`users_have_roles.user_id = ${alias}.id`)
.getQuery();
- expect(expression[0].expression).toBe('users.addresses IS NULL');
+ expect(expression[0].expression).toBe('Users.addresses IS NULL');
expect(expression[1].expression).toBe(`NOT EXISTS (${commentQuery})`);
expect(expression[2].expression).toBe(`NOT EXISTS (${rolesQuery})`);
expect(expression[0].params).toBe(null);
@@ -231,7 +231,7 @@ describe('Utils methode test', () => {
.getRepository('users_have_roles')
.createQueryBuilder('users_have_roles')
.select('users_have_roles.role_id', 'users_have_roles_role_id')
- .leftJoin('users', 'users', 'users_have_roles.user_id = users.id')
+ .leftJoin('Users', 'Users', 'users_have_roles.user_id = Users.id')
.where(`users_have_roles.role_id = ${alias1}.id`)
.getQuery();
const expression1 = UtilsMethode.applyQueryFiltersTarget(
@@ -387,7 +387,7 @@ describe('Utils methode test', () => {
.getRepository('users_have_roles')
.createQueryBuilder('users_have_roles')
.select('users_have_roles.user_id', 'users_have_roles_user_id')
- .leftJoin('roles', 'roles', 'users_have_roles.role_id = roles.id');
+ .leftJoin('Roles', 'roles', 'users_have_roles.role_id = Roles.id');
const expression = UtilsMethode.applyQueryFilterRelation(
queryBuilder,
@@ -433,8 +433,8 @@ describe('Utils methode test', () => {
const query = repository.manager
.getRepository('comments')
- .createQueryBuilder('comments')
- .select('comments.createdBy');
+ .createQueryBuilder('Comments')
+ .select('Comments.createdBy');
const expression = UtilsMethode.applyQueryFilterRelation(
queryBuilder,
@@ -465,7 +465,7 @@ describe('Utils methode test', () => {
);
const resultQuery = query
.where(
- `${relName}.${fieldName} ${OperandsMap[operand].replace(
+ `${query.alias}.${fieldName} ${OperandsMap[operand].replace(
'EXPRESSION',
paramsName
)}`
diff --git a/libs/json-api-nestjs/src/lib/mixin/service/typeorm/utils/utils-methode.ts b/libs/json-api-nestjs/src/lib/mixin/service/typeorm/utils/utils-methode.ts
index 8f452f88..d63e213e 100644
--- a/libs/json-api-nestjs/src/lib/mixin/service/typeorm/utils/utils-methode.ts
+++ b/libs/json-api-nestjs/src/lib/mixin/service/typeorm/utils/utils-methode.ts
@@ -102,7 +102,7 @@ export class UtilsMethode {
.select(selectQuery)
.from(joinTableName, joinTableName)
.leftJoin(resourceRelationName, resourceRelationName, onQuery)
- .where(`${selectQuery} = ${metadata.tableName}.${primaryColumn}`)
+ .where(`${selectQuery} = ${builder.alias}.${primaryColumn}`)
.getQuery();
resultExpression.push({
expression: OperandMapForNullRelation[operand].replace(
@@ -119,7 +119,7 @@ export class UtilsMethode {
.select(`${resourceRelationName}.${inverseSidePropertyPath}`)
.from(target, resourceRelationName)
.where(
- `${resourceRelationName}.${inverseSidePropertyPath} = ${metadata.tableName}.id`
+ `${resourceRelationName}.${inverseSidePropertyPath} = ${builder.alias}.id`
)
.getQuery();
resultExpression.push({
@@ -389,7 +389,7 @@ export class UtilsMethode {
public static async validateRelationRequestData(
repository: Repository,
- id: number,
+ id: number | string,
relName: string,
body: ServiceOptions['body']
): Promise<{
diff --git a/libs/json-api-nestjs/src/lib/types/binding.types.ts b/libs/json-api-nestjs/src/lib/types/binding.types.ts
index 46daca90..418d68a6 100644
--- a/libs/json-api-nestjs/src/lib/types/binding.types.ts
+++ b/libs/json-api-nestjs/src/lib/types/binding.types.ts
@@ -1,8 +1,8 @@
-import { RequestMethod } from '@nestjs/common';
-import { ObjectLiteral } from 'typeorm/common/ObjectLiteral';
+import { PipeTransform, RequestMethod } from '@nestjs/common';
import { PipeFabric } from './module.types';
import { ControllerTypes } from './controller.types';
+import { Type } from '@nestjs/common/interfaces';
export type MethodName =
| 'getAll'
@@ -37,7 +37,10 @@ export interface Binding {
name: T;
implementation: ControllerTypes[T];
parameters: {
- decorator: ParameterDecorator;
+ decorator: (
+ property: string,
+ ...pipes: (Type | PipeTransform)[]
+ ) => ParameterDecorator;
property?: string;
mixins: PipeFabric[];
}[];
diff --git a/libs/json-api-nestjs/src/lib/types/module.types.ts b/libs/json-api-nestjs/src/lib/types/module.types.ts
index be83e8fa..0cda32c1 100644
--- a/libs/json-api-nestjs/src/lib/types/module.types.ts
+++ b/libs/json-api-nestjs/src/lib/types/module.types.ts
@@ -5,13 +5,19 @@ import { DynamicModule, PipeTransform } from '@nestjs/common';
export type Entity = EntityClassOrSchema;
export type NestController = Type;
export type NestProvider = Type;
+export type NestImport = Type;
export type PipeMixin = Type;
-export type PipeFabric = (entity: Entity, connectionName?: string) => PipeMixin;
+export type PipeFabric = (
+ entity: Entity,
+ connectionName?: string,
+ config?: ConfigParam
+) => PipeMixin;
export interface ConfigParam {
requiredSelectField: boolean;
debug: boolean;
maxExecutionTime: number;
+ pipeForId: PipeMixin;
}
export interface ModuleOptions {
@@ -20,6 +26,7 @@ export interface ModuleOptions {
connectionName?: string;
providers?: NestProvider[];
options?: Partial;
+ imports?: NestImport[];
}
export interface BaseModuleOptions {
@@ -27,6 +34,7 @@ export interface BaseModuleOptions {
connectionName: string;
controller?: NestController;
config: ConfigParam;
+ imports?: NestImport[];
}
export interface BaseModuleStaticClass {
diff --git a/libs/json-api-nestjs/src/lib/types/params.type.ts b/libs/json-api-nestjs/src/lib/types/params.type.ts
index a112c40f..d406af97 100644
--- a/libs/json-api-nestjs/src/lib/types/params.type.ts
+++ b/libs/json-api-nestjs/src/lib/types/params.type.ts
@@ -1,5 +1,5 @@
export interface RouteParams {
- id?: number;
+ id?: number | string;
relName?: string;
relId?: number;
}
diff --git a/package-lock.json b/package-lock.json
index 8b209b75..04a509d2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,7 @@
"@angular/platform-browser": "~14.2.0",
"@angular/platform-browser-dynamic": "~14.2.0",
"@angular/router": "~14.2.0",
+ "@nestjs/axios": "^0.1.0",
"@nestjs/common": "^9.0.0",
"@nestjs/core": "^9.0.0",
"@nestjs/platform-express": "^9.0.0",
@@ -4703,6 +4704,41 @@
}
}
},
+ "node_modules/@nestjs/axios": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-0.1.0.tgz",
+ "integrity": "sha512-b2TT2X6BFbnNoeteiaxCIiHaFcSbVW+S5yygYqiIq5i6H77yIU3IVuLdpQkHq8/EqOWFwMopLN8jdkUT71Am9w==",
+ "dependencies": {
+ "axios": "0.27.2"
+ },
+ "peerDependencies": {
+ "@nestjs/common": "^7.0.0 || ^8.0.0 || ^9.0.0",
+ "reflect-metadata": "^0.1.12",
+ "rxjs": "^6.0.0 || ^7.0.0"
+ }
+ },
+ "node_modules/@nestjs/axios/node_modules/axios": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
+ "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
+ "dependencies": {
+ "follow-redirects": "^1.14.9",
+ "form-data": "^4.0.0"
+ }
+ },
+ "node_modules/@nestjs/axios/node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/@nestjs/common": {
"version": "9.1.4",
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.1.4.tgz",
@@ -8256,8 +8292,7 @@
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
- "devOptional": true
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/at-least-node": {
"version": "1.0.0",
@@ -9543,7 +9578,6 @@
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "devOptional": true,
"dependencies": {
"delayed-stream": "~1.0.0"
},
@@ -11067,7 +11101,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "devOptional": true,
"engines": {
"node": ">=0.4.0"
}
@@ -31107,6 +31140,35 @@
}
}
},
+ "@nestjs/axios": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-0.1.0.tgz",
+ "integrity": "sha512-b2TT2X6BFbnNoeteiaxCIiHaFcSbVW+S5yygYqiIq5i6H77yIU3IVuLdpQkHq8/EqOWFwMopLN8jdkUT71Am9w==",
+ "requires": {
+ "axios": "0.27.2"
+ },
+ "dependencies": {
+ "axios": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
+ "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
+ "requires": {
+ "follow-redirects": "^1.14.9",
+ "form-data": "^4.0.0"
+ }
+ },
+ "form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ }
+ }
+ }
+ },
"@nestjs/common": {
"version": "9.1.4",
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.1.4.tgz",
@@ -33765,8 +33827,7 @@
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
- "devOptional": true
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"at-least-node": {
"version": "1.0.0",
@@ -34724,7 +34785,6 @@
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "devOptional": true,
"requires": {
"delayed-stream": "~1.0.0"
}
@@ -35854,8 +35914,7 @@
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "devOptional": true
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
"delegates": {
"version": "1.0.0",
diff --git a/package.json b/package.json
index 19dc7ff7..e1ffd9c6 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"@angular/platform-browser": "~14.2.0",
"@angular/platform-browser-dynamic": "~14.2.0",
"@angular/router": "~14.2.0",
+ "@nestjs/axios": "^0.1.0",
"@nestjs/common": "^9.0.0",
"@nestjs/core": "^9.0.0",
"@nestjs/platform-express": "^9.0.0",