Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] [backend] Set up Swagger #25

Merged
merged 8 commits into from
Nov 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@
"@nestjs/core": "^10.0.0",
"@nestjs/mapped-types": "*",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/swagger": "^7.1.14",
"@prisma/client": "5.5.0",
"bcrypt": "^5.1.1",
"pg-promise": "^11.5.4",
"prisma": "^5.5.0",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1"
"rxjs": "^7.8.1",
"swagger-ui-express": "^5.0.0"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
Expand Down
3 changes: 2 additions & 1 deletion backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './user/user.module';
import { PrismaModule } from './prisma/prisma.module';

@Module({
imports: [UserModule],
imports: [UserModule, PrismaModule],
controllers: [AppController],
providers: [AppService],
})
Expand Down
11 changes: 11 additions & 0 deletions backend/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors(); // enable CORS
app.setGlobalPrefix('api');

const config = new DocumentBuilder()
.setTitle('Pong API')
.setDescription('The Pong API description')
.setVersion('0.1')
.build();

const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);

await app.listen(process.env.PORT);
}
bootstrap();
Comment on lines 5 to 21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bootstrap function is correctly set up and the Swagger documentation is correctly configured and set up. However, it's a good practice to add error handling for the app.listen() function. This will help catch and handle any errors that might occur when the application tries to listen on the specified port.

- await app.listen(process.env.PORT);
+ try {
+   await app.listen(process.env.PORT);
+ } catch (error) {
+   console.error(`Failed to bind port ${process.env.PORT}`, error);
+ }

Commitable suggestion

[!IMPORTANT]
Carefully review the code before committing. Make sure it correctly replaces the highlighted code, has no missing lines and indentaion issues.

Suggested change
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors(); // enable CORS
app.setGlobalPrefix('api');
const config = new DocumentBuilder()
.setTitle('Pong API')
.setDescription('The Pong API description')
.setVersion('0.1')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
await app.listen(process.env.PORT);
}
bootstrap();
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors(); // enable CORS
app.setGlobalPrefix('api');
const config = new DocumentBuilder()
.setTitle('Pong API')
.setDescription('The Pong API description')
.setVersion('0.1')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
try {
await app.listen(process.env.PORT);
} catch (error) {
console.error(`Failed to bind port ${process.env.PORT}`, error);
}
}
bootstrap();

9 changes: 0 additions & 9 deletions backend/src/prisma.service.ts

This file was deleted.

8 changes: 8 additions & 0 deletions backend/src/prisma/prisma.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';

@Module({
providers: [PrismaService],
exports: [PrismaService],
})
export class PrismaModule {}
18 changes: 18 additions & 0 deletions backend/src/prisma/prisma.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { PrismaService } from './prisma.service';

describe('PrismaService', () => {
let service: PrismaService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [PrismaService],
}).compile();

service = module.get<PrismaService>(PrismaService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
5 changes: 5 additions & 0 deletions backend/src/prisma/prisma.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Injectable } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient {}
13 changes: 12 additions & 1 deletion backend/src/user/dto/create-user.dto.ts
Original file line number Diff line number Diff line change
@@ -1 +1,12 @@
export class CreateUserDto {}
import { ApiProperty } from '@nestjs/swagger';

export class CreateUserDto {
@ApiProperty()
email: string;

@ApiProperty({ required: false })
name?: string;

@ApiProperty()
password: string;
}
2 changes: 1 addition & 1 deletion backend/src/user/dto/update-user.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PartialType } from '@nestjs/mapped-types';
import { PartialType } from '@nestjs/swagger';
import { CreateUserDto } from './create-user.dto';

export class UpdateUserDto extends PartialType(CreateUserDto) {}
16 changes: 15 additions & 1 deletion backend/src/user/entities/user.entity.ts
Original file line number Diff line number Diff line change
@@ -1 +1,15 @@
export class User {}
import { User } from '@prisma/client';
import { ApiProperty } from '@nestjs/swagger';

export class UserEntity implements User {
@ApiProperty()
id: number;

@ApiProperty()
email: string;

@ApiProperty({ required: false, nullable: true })
name: string | null;

password: string;
}
2 changes: 1 addition & 1 deletion backend/src/user/user.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { PrismaService } from 'src/prisma.service';
import { PrismaService } from 'src/prisma/prisma.service';

describe('UserController', () => {
let controller: UserController;
Expand Down
27 changes: 18 additions & 9 deletions backend/src/user/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,48 @@ import {
Delete,
} from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { User as UserModel } from '@prisma/client';
import {
ApiCreatedResponse,
ApiOkResponse,
ApiNoContentResponse,
ApiTags,
} from '@nestjs/swagger';
import { UserEntity } from './entities/user.entity';

@Controller('user')
@ApiTags('user')
export class UserController {
constructor(private readonly userService: UserService) {}

@Post()
create(
@Body() userData: { name?: string; email: string; password: string },
): Promise<UserModel> {
return this.userService.create(userData);
@ApiCreatedResponse({ type: UserEntity })
create(@Body() createUserDto: CreateUserDto) {
return this.userService.create(createUserDto);
}

@Get()
@ApiOkResponse({ type: [UserEntity] })
findAll() {
return this.userService.findAll();
}

@Get(':id')
@ApiOkResponse({ type: UserEntity })
findOne(@Param('id') id: string) {
return this.userService.findOne(+id);
}
Comment on lines 39 to 43
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The findOne method is correctly decorated with @ApiOkResponse({ type: UserEntity }) to indicate the response schema in the Swagger UI. However, the +id operation is used to convert the id from a string to a number. If the id is not a number, this operation will return NaN, which could lead to unexpected behavior. If the id is expected to be a number, it would be better to parse it with parseInt(id, 10) and handle the case where id is not a number. If the id is not expected to be a number, the + operation should be removed.

- return this.userService.findOne(+id);
+ return this.userService.findOne(parseInt(id, 10));

Commitable suggestion

[!IMPORTANT]
Carefully review the code before committing. Make sure it correctly replaces the highlighted code, has no missing lines and indentaion issues.

Suggested change
@Get(':id')
@ApiOkResponse({ type: UserEntity })
findOne(@Param('id') id: string) {
return this.userService.findOne(+id);
}
@Get(':id')
@ApiOkResponse({ type: UserEntity })
findOne(@Param('id') id: string) {
return this.userService.findOne(parseInt(id, 10));
}

Comment on lines 41 to 43
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The +id operation is used to convert the id from a string to a number. If the id is not a number, this operation will return NaN, which could lead to unexpected behavior. If the id is expected to be a number, it would be better to parse it with parseInt(id, 10) and handle the case where id is not a number. If the id is not expected to be a number, the + operation should be removed.

- return this.userService.findOne(+id);
+ return this.userService.findOne(parseInt(id, 10));

Commitable suggestion

[!IMPORTANT]
Carefully review the code before committing. Make sure it correctly replaces the highlighted code, has no missing lines and indentaion issues.

Suggested change
findOne(@Param('id') id: string) {
return this.userService.findOne(+id);
}
findOne(@Param('id') id: string) {
return this.userService.findOne(parseInt(id, 10));
}


@Patch(':id')
update(
@Param('id') id: string,
@Body() userData: { name?: string; email?: string; password?: string },
) {
return this.userService.update(+id, userData);
@ApiOkResponse({ type: UserEntity })
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.userService.update(+id, updateUserDto);
}
Comment on lines 45 to 49
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The update method is correctly decorated with @ApiOkResponse({ type: UserEntity }) to indicate the response schema in the Swagger UI. The method signature is updated to accept updateUserDto of type UpdateUserDto. The same issue with the +id operation as in the findOne method applies here.

- return this.userService.update(+id, updateUserDto);
+ return this.userService.update(parseInt(id, 10), updateUserDto);

Commitable suggestion

[!IMPORTANT]
Carefully review the code before committing. Make sure it correctly replaces the highlighted code, has no missing lines and indentaion issues.

Suggested change
@Patch(':id')
update(
@Param('id') id: string,
@Body() userData: { name?: string; email?: string; password?: string },
) {
return this.userService.update(+id, userData);
@ApiOkResponse({ type: UserEntity })
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.userService.update(+id, updateUserDto);
}
@Patch(':id')
@ApiOkResponse({ type: UserEntity })
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.userService.update(parseInt(id, 10), updateUserDto);
}

Comment on lines +47 to 49
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same issue with the +id operation as in the findOne method applies here.

- return this.userService.update(+id, updateUserDto);
+ return this.userService.update(parseInt(id, 10), updateUserDto);

Commitable suggestion

[!IMPORTANT]
Carefully review the code before committing. Make sure it correctly replaces the highlighted code, has no missing lines and indentaion issues.

Suggested change
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.userService.update(+id, updateUserDto);
}
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.userService.update(parseInt(id, 10), updateUserDto);
}


@Delete(':id')
@ApiNoContentResponse()
remove(@Param('id') id: string) {
return this.userService.remove(+id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The +id operation is used to convert the id from a string to a number. If the id is not a number, this operation will return NaN, which could lead to unexpected behavior. If the id is expected to be a number, it would be better to parse it with parseInt(id, 10) and handle the case where id is not a number. If the id is not expected to be a number, the + operation should be removed.

- return this.userService.findOne(+id);
+ return this.userService.findOne(parseInt(id, 10));

Commitable suggestion

[!IMPORTANT]
Carefully review the code before committing. Make sure it correctly replaces the highlighted code, has no missing lines and indentaion issues.

Suggested change
return this.userService.remove(+id);
return this.userService.findOne(parseInt(id, 10));

}
Comment on lines 51 to 55
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The remove method is correctly decorated with @ApiNoContentResponse() to indicate that no content is returned in the response. The same issue with the +id operation as in the findOne method applies here.

- return this.userService.remove(+id);
+ return this.userService.remove(parseInt(id, 10));

Commitable suggestion

[!IMPORTANT]
Carefully review the code before committing. Make sure it correctly replaces the highlighted code, has no missing lines and indentaion issues.

Suggested change
@Delete(':id')
@ApiNoContentResponse()
remove(@Param('id') id: string) {
return this.userService.remove(+id);
}
@Delete(':id')
@ApiNoContentResponse()
remove(@Param('id') id: string) {
return this.userService.remove(parseInt(id, 10));
}

Comment on lines 53 to 55
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same issue with the +id operation as in the findOne method applies here.

- return this.userService.remove(+id);
+ return this.userService.remove(parseInt(id, 10));

Commitable suggestion

[!IMPORTANT]
Carefully review the code before committing. Make sure it correctly replaces the highlighted code, has no missing lines and indentaion issues.

Suggested change
remove(@Param('id') id: string) {
return this.userService.remove(+id);
}
remove(@Param('id') id: string) {
return this.userService.remove(parseInt(id, 10));
}

Expand Down
5 changes: 3 additions & 2 deletions backend/src/user/user.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { PrismaService } from 'src/prisma.service';
import { PrismaModule } from 'src/prisma/prisma.module';

@Module({
controllers: [UserController],
providers: [UserService, PrismaService],
providers: [UserService],
imports: [PrismaModule],
})
export class UserModule {}
2 changes: 1 addition & 1 deletion backend/src/user/user.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UserService } from './user.service';
import { PrismaService } from 'src/prisma.service';
import { PrismaService } from 'src/prisma/prisma.service';

describe('UserService', () => {
let service: UserService;
Expand Down
57 changes: 38 additions & 19 deletions backend/src/user/user.service.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,57 @@
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { PrismaService } from 'src/prisma.service';
import { PrismaService } from 'src/prisma/prisma.service';
import { User, Prisma } from '@prisma/client';
import bcrypt from 'bcrypt';
import { hash } from 'bcrypt';

type UserWithoutPassword = Omit<User, 'password'>;

function excludePassword(user: User): Omit<User, 'password'> {
const { password, ...userWithoutPassword } = user;
return userWithoutPassword;
}

@Injectable()
export class UserService {
constructor(private prisma: PrismaService) {}

async create(data: Prisma.UserCreateInput): Promise<User> {
async create(createUserDto: CreateUserDto): Promise<UserWithoutPassword> {
const saltRounds = 10;
const hashedPassword = await bcrypt.hash(data.password, saltRounds);
data.password = hashedPassword;
return this.prisma.user.create({ data });
const hashedPassword = await hash(createUserDto.password, saltRounds);
const userData = { ...createUserDto, password: hashedPassword };
return this.prisma.user.create({ data: userData }).then(excludePassword);
}

findAll() {
return this.prisma.user.findMany();
findAll(): Promise<UserWithoutPassword[]> {
return this.prisma.user
.findMany()
.then((users) => users.map(excludePassword));
}

findOne(id: number) {
return this.prisma.user.findFirst({ where: { id: id } });
findOne(id: number): Promise<UserWithoutPassword> {
return this.prisma.user
.findUnique({ where: { id: id } })
.then(excludePassword);
}

update(id: number, data: Prisma.UserUpdateInput) {
return this.prisma.user.update({
data,
where: { id: id },
});
update(
id: number,
updateUserDto: UpdateUserDto,
): Promise<UserWithoutPassword> {
return this.prisma.user
.update({
where: { id: id },
data: updateUserDto,
})
.then(excludePassword);
}
Comment on lines +38 to 48
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the update function, if the updateUserDto contains a new password, it should be hashed before being stored in the database. This is not currently being done. Here's a proposed fix:

  update(
    id: number,
    updateUserDto: UpdateUserDto,
  ): Promise<UserWithoutPassword> {
+   if (updateUserDto.password) {
+     const saltRounds = 10;
+     updateUserDto.password = await hash(updateUserDto.password, saltRounds);
+   }
    return this.prisma.user
      .update({
        where: { id: id },
        data: updateUserDto,
      })
      .then(excludePassword);
  }

Commitable suggestion

[!IMPORTANT]
Carefully review the code before committing. Make sure it correctly replaces the highlighted code, has no missing lines and indentaion issues.

Suggested change
update(
id: number,
updateUserDto: UpdateUserDto,
): Promise<UserWithoutPassword> {
return this.prisma.user
.update({
where: { id: id },
data: updateUserDto,
})
.then(excludePassword);
}
update(
id: number,
updateUserDto: UpdateUserDto,
): Promise<UserWithoutPassword> {
if (updateUserDto.password) {
const saltRounds = 10;
updateUserDto.password = await hash(updateUserDto.password, saltRounds);
}
return this.prisma.user
.update({
where: { id: id },
data: updateUserDto,
})
.then(excludePassword);
}


remove(id: number) {
return this.prisma.user.delete({
where: { id: id },
});
remove(id: number): Promise<UserWithoutPassword> {
return this.prisma.user
.delete({
where: { id: id },
})
.then(excludePassword);
}
}
46 changes: 37 additions & 9 deletions backend/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@
path-to-regexp "3.2.0"
tslib "2.6.2"

"@nestjs/mapped-types@*":
"@nestjs/mapped-types@*", "@nestjs/[email protected]":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-2.0.2.tgz#c8a090a8d22145b85ed977414c158534210f2e4f"
integrity sha512-V0izw6tWs6fTp9+KiiPUbGHWALy563Frn8X6Bm87ANLRuE46iuBMD5acKBDP5lKL/75QFvrzSJT7HkCbB0jTpg==
Expand All @@ -770,6 +770,17 @@
jsonc-parser "3.2.0"
pluralize "8.0.0"

"@nestjs/swagger@^7.1.14":
version "7.1.14"
resolved "https://registry.yarnpkg.com/@nestjs/swagger/-/swagger-7.1.14.tgz#492b3816308264472b3619f5c0336f378f1c9995"
integrity sha512-2Ol4S6qHeYVVmkshkWBM8E/qkmEqEOUj2QIewr0jLSyo30H7f3v81pJyks6pTLy4PK0LGUXojMvIfFIE3mmGQQ==
dependencies:
"@nestjs/mapped-types" "2.0.2"
js-yaml "4.1.0"
lodash "4.17.21"
path-to-regexp "3.2.0"
swagger-ui-dist "5.9.0"

"@nestjs/testing@^10.0.0":
version "10.2.7"
resolved "https://registry.yarnpkg.com/@nestjs/testing/-/testing-10.2.7.tgz#50408ccb4c809d216a12d60ac7932fd6ad7fedf4"
Expand Down Expand Up @@ -3589,6 +3600,13 @@ js-tokens@^4.0.0:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==

[email protected], js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"

js-yaml@^3.13.1:
version "3.14.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
Expand All @@ -3597,13 +3615,6 @@ js-yaml@^3.13.1:
argparse "^1.0.7"
esprima "^4.0.0"

js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"

jsesc@^2.5.1:
version "2.5.2"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
Expand Down Expand Up @@ -3712,7 +3723,7 @@ lodash.merge@^4.6.2:
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==

lodash@^4.17.21:
lodash@4.17.21, lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
Expand Down Expand Up @@ -4955,6 +4966,23 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==

[email protected]:
version "5.9.0"
resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.9.0.tgz#d52b6cf52fd0a8e6930866c402aaa793fe4e3f76"
integrity sha512-NUHSYoe5XRTk/Are8jPJ6phzBh3l9l33nEyXosM17QInoV95/jng8+PuSGtbD407QoPf93MH3Bkh773OgesJpA==

swagger-ui-dist@>=5.0.0:
version "5.9.1"
resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.9.1.tgz#d0bcd614e3752da02df141846348f84468ae815e"
integrity sha512-5zAx+hUwJb9T3EAntc7TqYkV716CMqG6sZpNlAAMOMWkNXRYxGkN8ADIvD55dQZ10LxN90ZM/TQmN7y1gpICnw==

swagger-ui-express@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/swagger-ui-express/-/swagger-ui-express-5.0.0.tgz#7a00a18dd909574cb0d628574a299b9ba53d4d49"
integrity sha512-tsU9tODVvhyfkNSvf03E6FAk+z+5cU3lXAzMy6Pv4av2Gt2xA0++fogwC4qo19XuFf6hdxevPuVCSKFuMHJhFA==
dependencies:
swagger-ui-dist ">=5.0.0"

[email protected]:
version "4.0.0"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205"
Expand Down