add swagger + catalog controller
This commit is contained in:
parent
171d670629
commit
d4423d9e33
|
|
@ -13,6 +13,8 @@
|
||||||
"@nestjs/core": "^11.0.1",
|
"@nestjs/core": "^11.0.1",
|
||||||
"@nestjs/mapped-types": "^2.1.0",
|
"@nestjs/mapped-types": "^2.1.0",
|
||||||
"@nestjs/platform-express": "^11.0.1",
|
"@nestjs/platform-express": "^11.0.1",
|
||||||
|
"@nestjs/swagger": "^11.2.3",
|
||||||
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.3",
|
"class-validator": "^0.14.3",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rxjs": "^7.8.1"
|
"rxjs": "^7.8.1"
|
||||||
|
|
@ -2054,6 +2056,12 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@microsoft/tsdoc": {
|
||||||
|
"version": "0.16.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.16.0.tgz",
|
||||||
|
"integrity": "sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@napi-rs/wasm-runtime": {
|
"node_modules/@napi-rs/wasm-runtime": {
|
||||||
"version": "0.2.12",
|
"version": "0.2.12",
|
||||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
|
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
|
||||||
|
|
@ -2509,6 +2517,39 @@
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@nestjs/swagger": {
|
||||||
|
"version": "11.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-11.2.3.tgz",
|
||||||
|
"integrity": "sha512-a0xFfjeqk69uHIUpP8u0ryn4cKuHdra2Ug96L858i0N200Hxho+n3j+TlQXyOF4EstLSGjTfxI1Xb2E1lUxeNg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@microsoft/tsdoc": "0.16.0",
|
||||||
|
"@nestjs/mapped-types": "2.1.0",
|
||||||
|
"js-yaml": "4.1.1",
|
||||||
|
"lodash": "4.17.21",
|
||||||
|
"path-to-regexp": "8.3.0",
|
||||||
|
"swagger-ui-dist": "5.30.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@fastify/static": "^8.0.0",
|
||||||
|
"@nestjs/common": "^11.0.1",
|
||||||
|
"@nestjs/core": "^11.0.1",
|
||||||
|
"class-transformer": "*",
|
||||||
|
"class-validator": "*",
|
||||||
|
"reflect-metadata": "^0.1.12 || ^0.2.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@fastify/static": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"class-transformer": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"class-validator": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@nestjs/testing": {
|
"node_modules/@nestjs/testing": {
|
||||||
"version": "11.1.9",
|
"version": "11.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.9.tgz",
|
||||||
|
|
@ -2638,6 +2679,13 @@
|
||||||
"url": "https://opencollective.com/pkgr"
|
"url": "https://opencollective.com/pkgr"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@scarf/scarf": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/@sinclair/typebox": {
|
"node_modules/@sinclair/typebox": {
|
||||||
"version": "0.34.41",
|
"version": "0.34.41",
|
||||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
|
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
|
||||||
|
|
@ -3981,7 +4029,6 @@
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
"dev": true,
|
|
||||||
"license": "Python-2.0"
|
"license": "Python-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/array-timsort": {
|
"node_modules/array-timsort": {
|
||||||
|
|
@ -4471,6 +4518,12 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/class-transformer": {
|
||||||
|
"version": "0.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
|
||||||
|
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/class-validator": {
|
"node_modules/class-validator": {
|
||||||
"version": "0.14.3",
|
"version": "0.14.3",
|
||||||
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.3.tgz",
|
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.3.tgz",
|
||||||
|
|
@ -7249,7 +7302,6 @@
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||||
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
|
|
@ -7432,7 +7484,6 @@
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/lodash.memoize": {
|
"node_modules/lodash.memoize": {
|
||||||
|
|
@ -9192,6 +9243,15 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/swagger-ui-dist": {
|
||||||
|
"version": "5.30.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.30.2.tgz",
|
||||||
|
"integrity": "sha512-HWCg1DTNE/Nmapt+0m2EPXFwNKNeKK4PwMjkwveN/zn1cV2Kxi9SURd+m0SpdcSgWEK/O64sf8bzXdtUhigtHA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@scarf/scarf": "=1.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/symbol-observable": {
|
"node_modules/symbol-observable": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@
|
||||||
"@nestjs/core": "^11.0.1",
|
"@nestjs/core": "^11.0.1",
|
||||||
"@nestjs/mapped-types": "^2.1.0",
|
"@nestjs/mapped-types": "^2.1.0",
|
||||||
"@nestjs/platform-express": "^11.0.1",
|
"@nestjs/platform-express": "^11.0.1",
|
||||||
|
"@nestjs/swagger": "^11.2.3",
|
||||||
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.3",
|
"class-validator": "^0.14.3",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rxjs": "^7.8.1"
|
"rxjs": "^7.8.1"
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,10 @@ import { Module } from '@nestjs/common';
|
||||||
import { AppController } from './app.controller';
|
import { AppController } from './app.controller';
|
||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
import { YachtModule } from './yacht/yacht.module';
|
import { YachtModule } from './yacht/yacht.module';
|
||||||
|
import { CatalogModule } from './catalog/catalog.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [YachtModule],
|
imports: [YachtModule, CatalogModule],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [AppService],
|
providers: [AppService],
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { CatalogController } from './catalog.controller';
|
||||||
|
|
||||||
|
describe('CatalogController', () => {
|
||||||
|
let controller: CatalogController;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [CatalogController],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
controller = module.get<CatalogController>(CatalogController);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { Controller, Get, Query } from '@nestjs/common';
|
||||||
|
import { CatalogService } from './catalog.service';
|
||||||
|
import { CatalogResponseDto } from './dto/catalog-response.dto';
|
||||||
|
import { CatalogItemDto } from './dto/catalog-item.dto';
|
||||||
|
import { CatalogParamsDto } from './dto/catalog-params.dto';
|
||||||
|
import { ApiQuery, ApiResponse, ApiOperation } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
@Controller('catalog')
|
||||||
|
export class CatalogController {
|
||||||
|
constructor(private readonly catalogService: CatalogService) {}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
@ApiOperation({ summary: 'Get catalog with filters, search and sorting' })
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'Catalog items with filters applied',
|
||||||
|
type: CatalogResponseDto,
|
||||||
|
})
|
||||||
|
@ApiQuery({
|
||||||
|
name: 'params',
|
||||||
|
required: false,
|
||||||
|
description: 'JSON string of filter parameters',
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
async getCatalog(
|
||||||
|
@Query('params') paramsString?: string,
|
||||||
|
): Promise<CatalogResponseDto> {
|
||||||
|
let params: CatalogParamsDto = {};
|
||||||
|
|
||||||
|
if (paramsString) {
|
||||||
|
try {
|
||||||
|
params = JSON.parse(decodeURIComponent(paramsString));
|
||||||
|
} catch (error) {
|
||||||
|
params = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.catalogService.getCatalog(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('all')
|
||||||
|
@ApiOperation({ summary: 'Get all catalog items without filters' })
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'All catalog items',
|
||||||
|
type: [CatalogItemDto],
|
||||||
|
})
|
||||||
|
async getAllCatalogItems(): Promise<CatalogItemDto[]> {
|
||||||
|
return this.catalogService.getAllCatalogItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('filtered')
|
||||||
|
@ApiOperation({ summary: 'Get catalog with explicit query parameters' })
|
||||||
|
async getFilteredCatalog(
|
||||||
|
@Query() params: CatalogParamsDto,
|
||||||
|
): Promise<CatalogResponseDto> {
|
||||||
|
return this.catalogService.getCatalog(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { CatalogController } from './catalog.controller';
|
||||||
|
import { CatalogService } from './catalog.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
controllers: [CatalogController],
|
||||||
|
providers: [CatalogService],
|
||||||
|
exports: [CatalogService],
|
||||||
|
})
|
||||||
|
export class CatalogModule {}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { CatalogService } from './catalog.service';
|
||||||
|
|
||||||
|
describe('CatalogService', () => {
|
||||||
|
let service: CatalogService;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [CatalogService],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<CatalogService>(CatalogService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { CatalogItemDto } from './dto/catalog-item.dto';
|
||||||
|
import { CatalogParamsDto } from './dto/catalog-params.dto';
|
||||||
|
import { CatalogResponseDto } from './dto/catalog-response.dto';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CatalogService {
|
||||||
|
private catalogItems: CatalogItemDto[] = [
|
||||||
|
// SAMPLE DATA
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Item 1',
|
||||||
|
length: 10,
|
||||||
|
speed: 100,
|
||||||
|
minCost: 50,
|
||||||
|
hasQuickRent: true,
|
||||||
|
pictureUrl: 'https://example.com/item1.jpg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'Item 2',
|
||||||
|
length: 10,
|
||||||
|
speed: 100,
|
||||||
|
minCost: 50,
|
||||||
|
hasQuickRent: false,
|
||||||
|
pictureUrl: 'https://example.com/item1.jpg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Item 3',
|
||||||
|
length: 10,
|
||||||
|
speed: 100,
|
||||||
|
minCost: 50,
|
||||||
|
hasQuickRent: true,
|
||||||
|
pictureUrl: 'https://example.com/item1.jpg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: 'Item 4',
|
||||||
|
length: 10,
|
||||||
|
speed: 100,
|
||||||
|
minCost: 50,
|
||||||
|
hasQuickRent: true,
|
||||||
|
pictureUrl: 'https://example.com/item1.jpg',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
async getCatalog(params?: CatalogParamsDto): Promise<CatalogResponseDto> {
|
||||||
|
let filteredItems = [...this.catalogItems];
|
||||||
|
|
||||||
|
if (params?.search) {
|
||||||
|
const searchTerm = params.search.toLowerCase();
|
||||||
|
|
||||||
|
filteredItems = filteredItems.filter((item) =>
|
||||||
|
item.name.toLowerCase().includes(searchTerm),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params?.filter?.price) {
|
||||||
|
const { minvalue, maxvalue } = params.filter.price;
|
||||||
|
|
||||||
|
filteredItems = filteredItems.filter((item) => {
|
||||||
|
if (minvalue !== undefined && item.minCost < minvalue) return false;
|
||||||
|
if (maxvalue !== undefined && item.minCost > maxvalue) return false;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params?.sort?.field) {
|
||||||
|
const { field, direction = 'asc' } = params.sort;
|
||||||
|
|
||||||
|
filteredItems.sort((a, b) => {
|
||||||
|
let valueA = a[field];
|
||||||
|
let valueB = b[field];
|
||||||
|
|
||||||
|
if (typeof valueA === 'string') valueA = valueA.toLowerCase();
|
||||||
|
if (typeof valueB === 'string') valueB = valueB.toLowerCase();
|
||||||
|
|
||||||
|
if (valueA < valueB) return direction === 'asc' ? -1 : 1;
|
||||||
|
if (valueA > valueB) return direction === 'asc' ? 1 : -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
items: filteredItems,
|
||||||
|
total: filteredItems.length,
|
||||||
|
filters: params?.filter,
|
||||||
|
sort: params?.sort,
|
||||||
|
search: params?.search,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllCatalogItems(): Promise<CatalogItemDto[]> {
|
||||||
|
return this.catalogItems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
export class CatalogItemDto {
|
||||||
|
id?: number;
|
||||||
|
name: string;
|
||||||
|
length: number;
|
||||||
|
speed: number;
|
||||||
|
minCost: number;
|
||||||
|
hasQuickRent: boolean;
|
||||||
|
pictureUrl: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
import {
|
||||||
|
IsOptional,
|
||||||
|
IsString,
|
||||||
|
IsNumber,
|
||||||
|
ValidateNested,
|
||||||
|
IsEnum,
|
||||||
|
} from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export enum SortDirection {
|
||||||
|
ASC = 'asc',
|
||||||
|
DESC = 'desc',
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SortParams {
|
||||||
|
@ApiProperty({ required: false, enum: SortDirection })
|
||||||
|
@IsOptional()
|
||||||
|
@IsEnum(SortDirection)
|
||||||
|
direction?: SortDirection;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
field?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PriceFilter {
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber()
|
||||||
|
minvalue?: number;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber()
|
||||||
|
maxvalue?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FilterParams {
|
||||||
|
@ApiProperty({ required: false, type: PriceFilter })
|
||||||
|
@IsOptional()
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => PriceFilter)
|
||||||
|
price?: PriceFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CatalogParamsDto {
|
||||||
|
@ApiProperty({ required: false })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
search?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false, type: SortParams })
|
||||||
|
@IsOptional()
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => SortParams)
|
||||||
|
sort?: SortParams;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false, type: FilterParams })
|
||||||
|
@IsOptional()
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => FilterParams)
|
||||||
|
filter?: FilterParams;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { CatalogItemDto } from './catalog-item.dto';
|
||||||
|
|
||||||
|
export class CatalogResponseDto {
|
||||||
|
items: CatalogItemDto[];
|
||||||
|
total: number;
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
filters?: any;
|
||||||
|
sort?: any;
|
||||||
|
search?: string;
|
||||||
|
}
|
||||||
13
src/main.ts
13
src/main.ts
|
|
@ -1,8 +1,19 @@
|
||||||
import { NestFactory } from '@nestjs/core';
|
import { NestFactory } from '@nestjs/core';
|
||||||
|
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
await app.listen(process.env.PORT ?? 3000);
|
|
||||||
|
const config = new DocumentBuilder()
|
||||||
|
.setTitle('Travelmarine backend')
|
||||||
|
.setDescription('Backend API for Travelmarine service')
|
||||||
|
.setVersion('0.1')
|
||||||
|
.build();
|
||||||
|
|
||||||
|
const documentFactory = () => SwaggerModule.createDocument(app, config);
|
||||||
|
SwaggerModule.setup('api', app, documentFactory);
|
||||||
|
|
||||||
|
await app.listen(process.env.PORT ?? 8001);
|
||||||
}
|
}
|
||||||
bootstrap();
|
bootstrap();
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
import { INestApplication } from '@nestjs/common';
|
|
||||||
import request from 'supertest';
|
|
||||||
import { App } from 'supertest/types';
|
|
||||||
import { AppModule } from './../src/app.module';
|
|
||||||
|
|
||||||
describe('AppController (e2e)', () => {
|
|
||||||
let app: INestApplication<App>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
const moduleFixture: TestingModule = await Test.createTestingModule({
|
|
||||||
imports: [AppModule],
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
app = moduleFixture.createNestApplication();
|
|
||||||
await app.init();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('/ (GET)', () => {
|
|
||||||
return request(app.getHttpServer())
|
|
||||||
.get('/')
|
|
||||||
.expect(200)
|
|
||||||
.expect('Hello World!');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"moduleFileExtensions": ["js", "json", "ts"],
|
|
||||||
"rootDir": ".",
|
|
||||||
"testEnvironment": "node",
|
|
||||||
"testRegex": ".e2e-spec.ts$",
|
|
||||||
"transform": {
|
|
||||||
"^.+\\.(t|j)s$": "ts-jest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue