Commit c8515eeb authored by Kulpybaev Ilyas's avatar Kulpybaev Ilyas

Webinar-swagger

parent 84aa15f2
This diff is collapsed.
{ {
"name": "node_template", "name": "node_template",
"version": "1.0.0", "version": "2.1.5",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"mysql2": "^3.9.4", "mysql2": "^3.9.4",
"reflect-metadata": "^0.2.1", "reflect-metadata": "^0.2.1",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.0",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"tslib": "^2.6.0", "tslib": "^2.6.0",
"typeorm": "^0.3.20", "typeorm": "^0.3.20",
...@@ -32,6 +34,8 @@ ...@@ -32,6 +34,8 @@
"@types/express": "^4.17.17", "@types/express": "^4.17.17",
"@types/multer": "^1.4.11", "@types/multer": "^1.4.11",
"@types/node": "^20.4.2", "@types/node": "^20.4.2",
"@types/swagger-jsdoc": "^6.0.4",
"@types/swagger-ui-express": "^4.1.6",
"@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0", "@typescript-eslint/parser": "^6.0.0",
"eslint": "^8.45.0", "eslint": "^8.45.0",
......
...@@ -3,6 +3,8 @@ import { Application, RequestHandler } from 'express'; ...@@ -3,6 +3,8 @@ import { Application, RequestHandler } from 'express';
import { AppInit } from './interfaces/AppInit.interface'; import { AppInit } from './interfaces/AppInit.interface';
import { IRoute } from './interfaces/IRoute.interface'; import { IRoute } from './interfaces/IRoute.interface';
import { appDataSource } from '@/config/dataSource'; import { appDataSource } from '@/config/dataSource';
import swaggerUi from 'swagger-ui-express';
import { specs } from '@/config/swagger';
class App { class App {
public app: Application; public app: Application;
...@@ -28,6 +30,8 @@ class App { ...@@ -28,6 +30,8 @@ class App {
private initAssets() { private initAssets() {
this.app.use(express.json()); this.app.use(express.json());
this.app.use(express.static('public')); this.app.use(express.static('public'));
this.app.use('/api-docs', swaggerUi.serve);
this.app.get('/api-docs', swaggerUi.setup(specs));
} }
public async listen() { public async listen() {
await appDataSource.initialize(); await appDataSource.initialize();
......
import swaggerJsdoc from 'swagger-jsdoc';
import {version} from '../../package.json';
const options = {
swaggerDefinition: {
openapi: '3.0.0',
info: {
title: 'Shop-API',
version: version,
description: 'Shop REST API'
},
servers: [
{
url: 'http://localhost:8000'
}
],
components: {
schemas: {
ProductDto: {
type: 'object',
properties: {
title: {
type: 'string',
description: 'Название продукта'
},
description: {
type: 'string',
description: 'Описание продукта'
},
price: {
type: 'number',
description: 'Цена продукта'
},
image: {
type: 'file',
description: 'Картинка продукта',
format: 'binary'
},
categoryId: {
type: 'number',
description: 'ID категории продукта'
}
},
required: ['title', 'price', 'categoryId']
},
CategoryDto: {
type: 'object',
properties: {
title: {
type: 'string',
description: 'Название категории'
},
description: {
type: 'string',
description: 'Описание категории'
},
},
required: ['title']
},
StatusEnum: {
type: 'string',
enum: ['success', 'error', 'loading'],
description: 'Статус оплаты'
}
}
}
},
apis: ['src/controllers/*.ts']
};
export const specs = swaggerJsdoc(options);
\ No newline at end of file
...@@ -3,6 +3,8 @@ import { RequestHandler } from 'express'; ...@@ -3,6 +3,8 @@ import { RequestHandler } from 'express';
import { plainToInstance } from 'class-transformer'; import { plainToInstance } from 'class-transformer';
import { RegisterUserDto } from '@/dto/register-user.dto'; import { RegisterUserDto } from '@/dto/register-user.dto';
import { SignInUserDto } from '@/dto/sign-in-user.dto'; import { SignInUserDto } from '@/dto/sign-in-user.dto';
import { validate } from 'class-validator';
import { formatErrors } from '@/helpers/formatErrors';
export class AuthController { export class AuthController {
private service: AuthService; private service: AuthService;
...@@ -14,6 +16,7 @@ export class AuthController { ...@@ -14,6 +16,7 @@ export class AuthController {
signIn: RequestHandler = async (req, res): Promise<void> => { signIn: RequestHandler = async (req, res): Promise<void> => {
try { try {
const signInUserDto = plainToInstance(SignInUserDto, req.body); const signInUserDto = plainToInstance(SignInUserDto, req.body);
const user = await this.service.signIn(signInUserDto); const user = await this.service.signIn(signInUserDto);
res.send(user); res.send(user);
} catch (e) { } catch (e) {
...@@ -24,6 +27,15 @@ export class AuthController { ...@@ -24,6 +27,15 @@ export class AuthController {
register: RequestHandler = async (req, res): Promise<void> => { register: RequestHandler = async (req, res): Promise<void> => {
try { try {
const registerUserDto = plainToInstance(RegisterUserDto, req.body); const registerUserDto = plainToInstance(RegisterUserDto, req.body);
const errors = await validate(registerUserDto, {
whitelist: true,
validationError: { target: false, value: false },
});
if (errors.length > 0) {
res.status(400).send(formatErrors(errors));
return;
}
const user = await this.service.register(registerUserDto); const user = await this.service.register(registerUserDto);
res.send(user); res.send(user);
} catch (e) { } catch (e) {
......
...@@ -10,11 +10,43 @@ export class CategoryController { ...@@ -10,11 +10,43 @@ export class CategoryController {
this.service = new CategoryService(); this.service = new CategoryService();
} }
/**
* @swagger
* /categories:
* get:
* summary: Получить список категорий
* tags:
* - Categories
* responses:
* '200':
* description: Успешный запрос, получаем список категорий
* '500':
* description: Внутренняя ошибка сервера
*/
getCategories: RequestHandler = async (req, res): Promise<void> => { getCategories: RequestHandler = async (req, res): Promise<void> => {
const categories = await this.service.getCategories(); const categories = await this.service.getCategories();
res.send(categories); res.send(categories);
}; };
/**
* @swagger
* /categories:
* post:
* summary: Создать новую категорию
* tags:
* - Categories
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/CategoryDto'
* responses:
* '200':
* description: Успешный запрос, получаем список категорий
* '500':
* description: Внутренняя ошибка сервера
*/
createCategory: RequestHandler = async (req, res): Promise<void> => { createCategory: RequestHandler = async (req, res): Promise<void> => {
const categoryDto = plainToInstance(CategoryDto, req.body); const categoryDto = plainToInstance(CategoryDto, req.body);
const category = await this.service.createCategory(categoryDto); const category = await this.service.createCategory(categoryDto);
......
...@@ -10,11 +10,44 @@ export class ProductController { ...@@ -10,11 +10,44 @@ export class ProductController {
this.service = new ProductService(); this.service = new ProductService();
} }
/**
* @swagger
* /products:
* get:
* summary: Получить список продуктов
* tags:
* - Products
* responses:
* '200':
* description: Успешный запрос, получаем список продуктов
* '500':
* description: Внутренняя ошибка сервера
*/
getProducts: RequestHandler = async (req, res): Promise<void> => { getProducts: RequestHandler = async (req, res): Promise<void> => {
const products = await this.service.getProducts(); const products = await this.service.getProducts();
res.send(products); res.send(products);
}; };
/**
* @swagger
* /products/{id}:
* get:
* summary: Получить один продукт
* tags:
* - Products
* parameters:
* - in: path
* name: id
* required: true
* description: ID продукта
* schema:
* type: integer
* responses:
* '200':
* description: Успешный запрос, получаем продукт
* '400':
* description: Неверный запрос, продукт с указанным ID не найден
*/
getProduct: RequestHandler = async (req, res): Promise<void> => { getProduct: RequestHandler = async (req, res): Promise<void> => {
try { try {
const product = await this.service.getProduct(Number(req.params.id)); const product = await this.service.getProduct(Number(req.params.id));
...@@ -24,6 +57,28 @@ export class ProductController { ...@@ -24,6 +57,28 @@ export class ProductController {
} }
}; };
/**
* @swagger
* /products:
* post:
* summary: Создать новый продукт
* tags:
* - Products
* requestBody:
* required: true
* content:
* multipart/form-data:
* schema:
* $ref: '#/components/schemas/ProductDto'
* responses:
* '200':
* description: Успешный запрос, создаем новый продукт
* '400':
* description: Ошибка в запросе, сообщение об ошибке
* '500':
* description: Внутренняя ошибка сервера
*/
createProduct: RequestHandler = async (req, res): Promise<void> => { createProduct: RequestHandler = async (req, res): Promise<void> => {
try { try {
const productDto = plainToInstance(ProductDto, req.body); const productDto = plainToInstance(ProductDto, req.body);
......
...@@ -15,4 +15,8 @@ export class ProductDto { ...@@ -15,4 +15,8 @@ export class ProductDto {
@IsOptional() @IsOptional()
image!: string; image!: string;
@IsNotEmpty({ message: 'Укажите категорию продукта' })
@IsNumberString({}, { message: 'Укажите корректную категорию' })
categoryId!: number;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment