diff --git a/nest-cli.json b/nest-cli.json index 579ca35..da38101 100644 --- a/nest-cli.json +++ b/nest-cli.json @@ -5,6 +5,7 @@ "compilerOptions": { "deleteOutDir": true, "builder": "swc", - "typeCheck": true + "typeCheck": true, + "plugins": [ "@nestjs/swagger" ] } } diff --git a/package.json b/package.json index 1cecf98..58072b8 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@nestjs/mapped-types": "*", "@nestjs/platform-express": "^10.0.0", "@nestjs/schedule": "^4.0.1", + "@nestjs/swagger": "^7.3.1", "@types/cors": "^2.8.17", "axios": "^1.6.7", "class-transformer": "^0.5.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cc7ae72..61158f1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ dependencies: '@nestjs/schedule': specifier: ^4.0.1 version: 4.0.1(@nestjs/common@10.3.0)(@nestjs/core@10.3.0) + '@nestjs/swagger': + specifier: ^7.3.1 + version: 7.3.1(@nestjs/common@10.3.0)(@nestjs/core@10.3.0)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14) '@types/cors': specifier: ^2.8.17 version: 2.8.17 @@ -902,6 +905,10 @@ packages: resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} engines: {node: '>=8'} + /@microsoft/tsdoc@0.14.2: + resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} + dev: false + /@mole-inc/bin-wrapper@8.0.1: resolution: {integrity: sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1101,6 +1108,36 @@ packages: - chokidar dev: true + /@nestjs/swagger@7.3.1(@nestjs/common@10.3.0)(@nestjs/core@10.3.0)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14): + resolution: {integrity: sha512-LUC4mr+5oAleEC/a2j8pNRh1S5xhKXJ1Gal5ZdRjt9XebQgbngXCdW7JTA9WOEcwGtFZN9EnKYdquzH971LZfw==} + peerDependencies: + '@fastify/static': ^6.0.0 || ^7.0.0 + '@nestjs/common': ^9.0.0 || ^10.0.0 + '@nestjs/core': ^9.0.0 || ^10.0.0 + 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 + dependencies: + '@microsoft/tsdoc': 0.14.2 + '@nestjs/common': 10.3.0(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/core': 10.3.0(@nestjs/common@10.3.0)(@nestjs/platform-express@10.3.0)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/mapped-types': 2.0.5(@nestjs/common@10.3.0)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14) + class-transformer: 0.5.1 + class-validator: 0.14.1 + js-yaml: 4.1.0 + lodash: 4.17.21 + path-to-regexp: 3.2.0 + reflect-metadata: 0.1.14 + swagger-ui-dist: 5.11.2 + dev: false + /@nestjs/testing@10.3.0(@nestjs/common@10.3.0)(@nestjs/core@10.3.0)(@nestjs/platform-express@10.3.0): resolution: {integrity: sha512-8DM+bw1qASCvaEnoHUQhypCOf54+G5R21MeFBMvnSk5DtKaWVZuzDP2GjLeYCpTH19WeP6LrrjHv3rX2LKU02A==} peerDependencies: @@ -1995,7 +2032,6 @@ packages: /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true /array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} @@ -4212,7 +4248,6 @@ packages: hasBin: true dependencies: argparse: 2.0.1 - dev: true /jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} @@ -5466,6 +5501,10 @@ packages: engines: {node: '>= 0.4'} dev: true + /swagger-ui-dist@5.11.2: + resolution: {integrity: sha512-jQG0cRgJNMZ7aCoiFofnoojeSaa/+KgWaDlfgs8QN+BXoGMpxeMVY5OEnjq4OlNvF3yjftO8c9GRAgcHlO+u7A==} + dev: false + /symbol-observable@4.0.0: resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} engines: {node: '>=0.10'} diff --git a/src/main.ts b/src/main.ts index 913e890..f1d4355 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,9 +1,21 @@ import { NestFactory } from '@nestjs/core' +import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger' import { AppModule } from '@/app.module' +import metadata from './metadata' async function bootstrap() { const app = await NestFactory.create(AppModule, { cors: true, snapshot: true }) app.enableShutdownHooks() + + const openApiConfig = new DocumentBuilder() + .setTitle('Irrigation Events API') + .setDescription('API to manage irrigation events and programs') + .setVersion('1.0') + .build() + await SwaggerModule.loadPluginMetadata(metadata) + const document = SwaggerModule.createDocument(app, openApiConfig) + SwaggerModule.setup('api', app, document) + await app.listen(3000) } bootstrap() diff --git a/src/metadata.ts b/src/metadata.ts new file mode 100644 index 0000000..59dfca4 --- /dev/null +++ b/src/metadata.ts @@ -0,0 +1,8 @@ +/* eslint-disable */ +export default async () => { + const t = { + ["./irrigation-events/dto/irrigation-event-viewmodel.dto"]: await import("./irrigation-events/dto/irrigation-event-viewmodel.dto"), + ["./irrigation-programs/dto/irrigation-program.dto"]: await import("./irrigation-programs/dto/irrigation-program.dto") + }; + return { "@nestjs/swagger": { "models": [[import("./irrigation-events/entities/irrigation-event.entity"), { "IrrigationEventDocument": { _id: { required: true, type: () => String }, deviceName: { required: true, type: () => String }, deviceId: { required: true, type: () => Number }, state: { required: true, type: () => Object } } }], [import("./irrigation-events/dto/maker-api-event.dto"), { "MakerApiEventDto": { name: { required: true, type: () => String }, displayName: { required: true, type: () => String }, deviceId: { required: true, type: () => Number }, value: { required: true, type: () => Object } } }], [import("./irrigation-events/dto/irrigation-event-viewmodel.dto"), { "IrrigationEventViewmodelDto": { startTimestamp: { required: true, type: () => String }, endTimestamp: { required: false, type: () => String }, title: { required: true, type: () => String }, deviceId: { required: true, type: () => Number, minimum: 1 }, warning: { required: false, type: () => Object }, currentlyOn: { required: false, type: () => Boolean } } }], [import("./sunrise-sunset/entities/sunrise-sunset.entity"), { "SunriseSunsetEntity": { _id: { required: true, type: () => String }, sunrise: { required: true, type: () => String }, sunset: { required: true, type: () => String } } }], [import("./irrigation-programs/entities/irrigation-program.entity"), { "IrrigationProgramEntity": {} }], [import("./irrigation-programs/dto/create-irrigation-program.dto"), { "CreateIrrigationProgramDto": { name: { required: true, type: () => String, minLength: 1, maxLength: 255 }, duration: { required: true, type: () => Number, minimum: 1 }, wateringPeriod: { required: true, type: () => Number, minimum: 1 }, startTimes: { required: true, type: () => [String], pattern: "/^(?:[01]\\d|2[0-3]):(?:[0-5]\\d)$|^(?:sunset|sunrise)(?:[+-]?\\d+)?$/" }, deviceIds: { required: true, type: () => [Number], minimum: 1 }, simultaneousIrrigation: { required: true, type: () => Boolean }, nextRunDate: { required: false, type: () => String, nullable: true, pattern: "/^\\d{4}-\\d{2}-\\d{2}$/" } } }], [import("./irrigation-programs/dto/irrigation-program.dto"), { "IrrigationProgramDto": { id: { required: true, type: () => String } } }], [import("./irrigation-programs/dto/update-irrigation-program.dto"), { "UpdateIrrigationProgramDto": {} }]], "controllers": [[import("./app.controller"), { "AppController": { "getOk": { type: String } } }], [import("./irrigation-events/irrigation-events.controller"), { "IrrigationEventsController": { "create": {}, "get": { type: [t["./irrigation-events/dto/irrigation-event-viewmodel.dto"].IrrigationEventViewmodelDto] } } }], [import("./sunrise-sunset/sunrise-sunset.controller"), { "SunriseSunsetController": { "get": {}, "getOne": { type: Object } } }], [import("./irrigation-programs/irrigation-programs.controller"), { "IrrigationProgramsController": { "create": { type: t["./irrigation-programs/dto/irrigation-program.dto"].IrrigationProgramDto }, "findAll": { type: [t["./irrigation-programs/dto/irrigation-program.dto"].IrrigationProgramDto] }, "findOne": { type: t["./irrigation-programs/dto/irrigation-program.dto"].IrrigationProgramDto }, "update": { type: t["./irrigation-programs/dto/irrigation-program.dto"].IrrigationProgramDto }, "remove": {} } }]] } }; +}; \ No newline at end of file