bondarenko_max_lab_3 is done
This commit is contained in:
parent
131dc39f6c
commit
9ff5b267bc
2
bondarenko_max_lab_3/README.md
Normal file
2
bondarenko_max_lab_3/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
# Лабораторная работа 3 - REST API, Gateway и синхронный обмен между микросервисами
|
||||
### ПИбд-42 || Бондаренко Максим
|
1
bondarenko_max_lab_3/authors/.env
Normal file
1
bondarenko_max_lab_3/authors/.env
Normal file
@ -0,0 +1 @@
|
||||
PORT=3000
|
20
bondarenko_max_lab_3/authors/Dockerfile
Normal file
20
bondarenko_max_lab_3/authors/Dockerfile
Normal file
@ -0,0 +1,20 @@
|
||||
# Используем базовый образ Node.js
|
||||
FROM node:14
|
||||
|
||||
# Создаем рабочую директорию в контейнере
|
||||
WORKDIR /app
|
||||
|
||||
# Копируем package.json и package-lock.json
|
||||
COPY package*.json ./
|
||||
|
||||
# Устанавливаем зависимости
|
||||
RUN npm install
|
||||
|
||||
# Копируем исходный код
|
||||
COPY . .
|
||||
|
||||
# Указываем порт, который будет слушать приложение
|
||||
EXPOSE 3000
|
||||
|
||||
# Команда для запуска приложения
|
||||
CMD ["npm", "start"]
|
14
bondarenko_max_lab_3/authors/package.json
Normal file
14
bondarenko_max_lab_3/authors/package.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "authors",
|
||||
"version": "1.0.0",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"start": "node src/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.17.1",
|
||||
"swagger-jsdoc": "^6.1.0",
|
||||
"swagger-ui-express": "^4.3.0",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
const { Author, authors } = require('../models/authorModel');
|
||||
|
||||
const getAuthors = (req, res) => {
|
||||
res.json(authors);
|
||||
};
|
||||
|
||||
const getAuthorById = (req, res) => {
|
||||
const author = authors.find(a => a.uuid === req.params.uuid);
|
||||
if (author) {
|
||||
res.json(author);
|
||||
} else {
|
||||
res.status(404).send('Author not found');
|
||||
}
|
||||
};
|
||||
|
||||
const createAuthor = (req, res) => {
|
||||
const { name, birthdate } = req.body;
|
||||
const newAuthor = new Author(name, birthdate);
|
||||
authors.push(newAuthor);
|
||||
res.status(201).json(newAuthor);
|
||||
};
|
||||
|
||||
const updateAuthor = (req, res) => {
|
||||
const author = authors.find(a => a.uuid === req.params.uuid);
|
||||
if (author) {
|
||||
author.name = req.body.name || author.name;
|
||||
author.birthdate = req.body.birthdate || author.birthdate;
|
||||
res.json(author);
|
||||
} else {
|
||||
res.status(404).send('Author not found');
|
||||
}
|
||||
};
|
||||
|
||||
const deleteAuthor = (req, res) => {
|
||||
const authorIndex = authors.findIndex(a => a.uuid === req.params.uuid);
|
||||
if (authorIndex !== -1) {
|
||||
authors.splice(authorIndex, 1);
|
||||
res.status(204).send();
|
||||
} else {
|
||||
res.status(404).send('Author not found');
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getAuthors,
|
||||
getAuthorById,
|
||||
createAuthor,
|
||||
updateAuthor,
|
||||
deleteAuthor
|
||||
};
|
15
bondarenko_max_lab_3/authors/src/index.js
Normal file
15
bondarenko_max_lab_3/authors/src/index.js
Normal file
@ -0,0 +1,15 @@
|
||||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const authorRoutes = require('./routes/authorRoutes');
|
||||
const setupSwagger = require('./swagger');
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT || 3000;
|
||||
|
||||
app.use(bodyParser.json());
|
||||
app.use('/authors', authorRoutes);
|
||||
setupSwagger(app);
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Authors service is running on port ${port}`);
|
||||
});
|
16
bondarenko_max_lab_3/authors/src/models/authorModel.js
Normal file
16
bondarenko_max_lab_3/authors/src/models/authorModel.js
Normal file
@ -0,0 +1,16 @@
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
|
||||
class Author {
|
||||
constructor(name, birthdate) {
|
||||
this.uuid = uuidv4();
|
||||
this.name = name;
|
||||
this.birthdate = birthdate;
|
||||
}
|
||||
}
|
||||
|
||||
const authors = [];
|
||||
|
||||
module.exports = {
|
||||
Author,
|
||||
authors
|
||||
};
|
166
bondarenko_max_lab_3/authors/src/routes/authorRoutes.js
Normal file
166
bondarenko_max_lab_3/authors/src/routes/authorRoutes.js
Normal file
@ -0,0 +1,166 @@
|
||||
const express = require('express');
|
||||
const {
|
||||
getAuthors,
|
||||
getAuthorById,
|
||||
createAuthor,
|
||||
updateAuthor,
|
||||
deleteAuthor
|
||||
} = require('../controllers/authorController');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* components:
|
||||
* schemas:
|
||||
* Author:
|
||||
* type: object
|
||||
* required:
|
||||
* - name
|
||||
* - birthdate
|
||||
* properties:
|
||||
* uuid:
|
||||
* type: string
|
||||
* description: The auto-generated UUID of the author
|
||||
* name:
|
||||
* type: string
|
||||
* description: The name of the author
|
||||
* birthdate:
|
||||
* type: string
|
||||
* format: date
|
||||
* description: The birthdate of the author
|
||||
* example:
|
||||
* uuid: d5fE_asz
|
||||
* name: J.K. Rowling
|
||||
* birthdate: 1965-07-31
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* tags:
|
||||
* name: Authors
|
||||
* description: The authors managing API
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /authors:
|
||||
* get:
|
||||
* summary: Returns the list of all the authors
|
||||
* tags: [Authors]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The list of the authors
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/Author'
|
||||
*/
|
||||
router.get('/', getAuthors);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /authors/{uuid}:
|
||||
* get:
|
||||
* summary: Get the author by id
|
||||
* tags: [Authors]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: uuid
|
||||
* schema:
|
||||
* type: string
|
||||
* required: true
|
||||
* description: The author id
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The author description by id
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Author'
|
||||
* 404:
|
||||
* description: The author was not found
|
||||
*/
|
||||
router.get('/:uuid', getAuthorById);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /authors:
|
||||
* post:
|
||||
* summary: Create a new author
|
||||
* tags: [Authors]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Author'
|
||||
* responses:
|
||||
* 201:
|
||||
* description: The author was successfully created
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Author'
|
||||
* 500:
|
||||
* description: Some server error
|
||||
*/
|
||||
router.post('/', createAuthor);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /authors/{uuid}:
|
||||
* put:
|
||||
* summary: Update the author by the id
|
||||
* tags: [Authors]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: uuid
|
||||
* schema:
|
||||
* type: string
|
||||
* required: true
|
||||
* description: The author id
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Author'
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The author was updated
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Author'
|
||||
* 404:
|
||||
* description: The author was not found
|
||||
* 500:
|
||||
* description: Some error happened
|
||||
*/
|
||||
router.put('/:uuid', updateAuthor);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /authors/{uuid}:
|
||||
* delete:
|
||||
* summary: Remove the author by id
|
||||
* tags: [Authors]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: uuid
|
||||
* schema:
|
||||
* type: string
|
||||
* required: true
|
||||
* description: The author id
|
||||
* responses:
|
||||
* 204:
|
||||
* description: The author was deleted
|
||||
* 404:
|
||||
* description: The author was not found
|
||||
*/
|
||||
router.delete('/:uuid', deleteAuthor);
|
||||
|
||||
module.exports = router;
|
22
bondarenko_max_lab_3/authors/src/swagger.js
Normal file
22
bondarenko_max_lab_3/authors/src/swagger.js
Normal file
@ -0,0 +1,22 @@
|
||||
const swaggerJSDoc = require('swagger-jsdoc');
|
||||
const swaggerUi = require('swagger-ui-express');
|
||||
|
||||
const options = {
|
||||
definition: {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'Authors API',
|
||||
version: '1.0.0',
|
||||
description: 'API for managing authors',
|
||||
},
|
||||
},
|
||||
apis: ['./src/routes/*.js'],
|
||||
};
|
||||
|
||||
const swaggerSpec = swaggerJSDoc(options);
|
||||
|
||||
const setupSwagger = (app) => {
|
||||
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
|
||||
};
|
||||
|
||||
module.exports = setupSwagger;
|
1
bondarenko_max_lab_3/books/.env
Normal file
1
bondarenko_max_lab_3/books/.env
Normal file
@ -0,0 +1 @@
|
||||
PORT=3001
|
20
bondarenko_max_lab_3/books/Dockerfile
Normal file
20
bondarenko_max_lab_3/books/Dockerfile
Normal file
@ -0,0 +1,20 @@
|
||||
# Используем базовый образ Node.js
|
||||
FROM node:14
|
||||
|
||||
# Создаем рабочую директорию в контейнере
|
||||
WORKDIR /app
|
||||
|
||||
# Копируем package.json и package-lock.json
|
||||
COPY package*.json ./
|
||||
|
||||
# Устанавливаем зависимости
|
||||
RUN npm install
|
||||
|
||||
# Копируем исходный код
|
||||
COPY . .
|
||||
|
||||
# Указываем порт, который будет слушать приложение
|
||||
EXPOSE 3001
|
||||
|
||||
# Команда для запуска приложения
|
||||
CMD ["npm", "start"]
|
16
bondarenko_max_lab_3/books/package.json
Normal file
16
bondarenko_max_lab_3/books/package.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "books",
|
||||
"version": "1.0.0",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"start": "node src/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.17.1",
|
||||
"swagger-jsdoc": "^6.1.0",
|
||||
"swagger-ui-express": "^4.3.0",
|
||||
"axios": "^0.21.1",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
}
|
||||
|
72
bondarenko_max_lab_3/books/src/controllers/bookController.js
Normal file
72
bondarenko_max_lab_3/books/src/controllers/bookController.js
Normal file
@ -0,0 +1,72 @@
|
||||
const axios = require('axios');
|
||||
const { Book, books } = require('../models/bookModel');
|
||||
|
||||
const getBooks = (req, res) => {
|
||||
res.json(books);
|
||||
};
|
||||
|
||||
const getBookById = async (req, res) => {
|
||||
const book = books.find(b => b.uuid === req.params.uuid);
|
||||
if (book) {
|
||||
try {
|
||||
const authorResponse = await axios.get(`http://authors:3000/authors/${book.authorUuid}`);
|
||||
book.authorInfo = authorResponse.data;
|
||||
res.json(book);
|
||||
} catch (error) {
|
||||
res.status(500).send('Error fetching author information');
|
||||
}
|
||||
} else {
|
||||
res.status(404).send('Book not found');
|
||||
}
|
||||
};
|
||||
|
||||
const createBook = async (req, res) => {
|
||||
const { author, title, year, authorUuid } = req.body;
|
||||
|
||||
try {
|
||||
const authorResponse = await axios.get(`http://authors:3000/authors/${authorUuid}`);
|
||||
if (!authorResponse.data) {
|
||||
return res.status(404).send('Author not found');
|
||||
}
|
||||
const newBook = new Book(author, title, year, authorUuid);
|
||||
books.push(newBook);
|
||||
res.status(201).json(newBook);
|
||||
} catch (error) {
|
||||
if (error.response && error.response.status === 404) {
|
||||
res.status(404).send('Author not found');
|
||||
} else {
|
||||
res.status(500).send('Error creating book');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const updateBook = (req, res) => {
|
||||
const book = books.find(b => b.uuid === req.params.uuid);
|
||||
if (book) {
|
||||
book.author = req.body.author || book.author;
|
||||
book.title = req.body.title || book.title;
|
||||
book.year = req.body.year || book.year;
|
||||
book.authorUuid = req.body.authorUuid || book.authorUuid;
|
||||
res.json(book);
|
||||
} else {
|
||||
res.status(404).send('Book not found');
|
||||
}
|
||||
};
|
||||
|
||||
const deleteBook = (req, res) => {
|
||||
const bookIndex = books.findIndex(b => b.uuid === req.params.uuid);
|
||||
if (bookIndex !== -1) {
|
||||
books.splice(bookIndex, 1);
|
||||
res.status(204).send();
|
||||
} else {
|
||||
res.status(404).send('Book not found');
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getBooks,
|
||||
getBookById,
|
||||
createBook,
|
||||
updateBook,
|
||||
deleteBook
|
||||
};
|
15
bondarenko_max_lab_3/books/src/index.js
Normal file
15
bondarenko_max_lab_3/books/src/index.js
Normal file
@ -0,0 +1,15 @@
|
||||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const bookRoutes = require('./routes/bookRoutes');
|
||||
const setupSwagger = require('./swagger');
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT || 3001;
|
||||
|
||||
app.use(bodyParser.json());
|
||||
app.use('/books', bookRoutes);
|
||||
setupSwagger(app);
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Books service is running on port ${port}`);
|
||||
});
|
18
bondarenko_max_lab_3/books/src/models/bookModel.js
Normal file
18
bondarenko_max_lab_3/books/src/models/bookModel.js
Normal file
@ -0,0 +1,18 @@
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
|
||||
class Book {
|
||||
constructor(author, title, year, authorUuid) {
|
||||
this.uuid = uuidv4();
|
||||
this.author = author;
|
||||
this.title = title;
|
||||
this.year = year;
|
||||
this.authorUuid = authorUuid;
|
||||
}
|
||||
}
|
||||
|
||||
const books = [];
|
||||
|
||||
module.exports = {
|
||||
Book,
|
||||
books
|
||||
};
|
175
bondarenko_max_lab_3/books/src/routes/bookRoutes.js
Normal file
175
bondarenko_max_lab_3/books/src/routes/bookRoutes.js
Normal file
@ -0,0 +1,175 @@
|
||||
const express = require('express');
|
||||
const {
|
||||
getBooks,
|
||||
getBookById,
|
||||
createBook,
|
||||
updateBook,
|
||||
deleteBook
|
||||
} = require('../controllers/bookController');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* components:
|
||||
* schemas:
|
||||
* Book:
|
||||
* type: object
|
||||
* required:
|
||||
* - author
|
||||
* - title
|
||||
* - year
|
||||
* - authorUuid
|
||||
* properties:
|
||||
* uuid:
|
||||
* type: string
|
||||
* description: The auto-generated UUID of the book
|
||||
* author:
|
||||
* type: string
|
||||
* description: The author of the book
|
||||
* title:
|
||||
* type: string
|
||||
* description: The title of the book
|
||||
* year:
|
||||
* type: integer
|
||||
* description: The year the book was published
|
||||
* authorUuid:
|
||||
* type: string
|
||||
* description: The UUID of the author
|
||||
* example:
|
||||
* uuid: d5fE_asz
|
||||
* author: J.K. Rowling
|
||||
* title: Harry Potter
|
||||
* year: 1997
|
||||
* authorUuid: d5fE_asz
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* tags:
|
||||
* name: Books
|
||||
* description: The books managing API
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /books:
|
||||
* get:
|
||||
* summary: Returns the list of all the books
|
||||
* tags: [Books]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The list of the books
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/Book'
|
||||
*/
|
||||
router.get('/', getBooks);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /books/{uuid}:
|
||||
* get:
|
||||
* summary: Get the book by id
|
||||
* tags: [Books]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: uuid
|
||||
* schema:
|
||||
* type: string
|
||||
* required: true
|
||||
* description: The book id
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The book description by id
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Book'
|
||||
* 404:
|
||||
* description: The book was not found
|
||||
*/
|
||||
router.get('/:uuid', getBookById);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /books:
|
||||
* post:
|
||||
* summary: Create a new book
|
||||
* tags: [Books]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Book'
|
||||
* responses:
|
||||
* 201:
|
||||
* description: The book was successfully created
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Book'
|
||||
* 500:
|
||||
* description: Some server error
|
||||
*/
|
||||
router.post('/', createBook);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /books/{uuid}:
|
||||
* put:
|
||||
* summary: Update the book by the id
|
||||
* tags: [Books]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: uuid
|
||||
* schema:
|
||||
* type: string
|
||||
* required: true
|
||||
* description: The book id
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Book'
|
||||
* responses:
|
||||
* 200:
|
||||
* description: The book was updated
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Book'
|
||||
* 404:
|
||||
* description: The book was not found
|
||||
* 500:
|
||||
* description: Some error happened
|
||||
*/
|
||||
router.put('/:uuid', updateBook);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /books/{uuid}:
|
||||
* delete:
|
||||
* summary: Remove the book by id
|
||||
* tags: [Books]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: uuid
|
||||
* schema:
|
||||
* type: string
|
||||
* required: true
|
||||
* description: The book id
|
||||
* responses:
|
||||
* 204:
|
||||
* description: The book was deleted
|
||||
* 404:
|
||||
* description: The book was not found
|
||||
*/
|
||||
router.delete('/:uuid', deleteBook);
|
||||
|
||||
module.exports = router;
|
22
bondarenko_max_lab_3/books/src/swagger.js
Normal file
22
bondarenko_max_lab_3/books/src/swagger.js
Normal file
@ -0,0 +1,22 @@
|
||||
const swaggerJSDoc = require('swagger-jsdoc');
|
||||
const swaggerUi = require('swagger-ui-express');
|
||||
|
||||
const options = {
|
||||
definition: {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'Books API',
|
||||
version: '1.0.0',
|
||||
description: 'API for managing books',
|
||||
},
|
||||
},
|
||||
apis: ['./src/routes/*.js'],
|
||||
};
|
||||
|
||||
const swaggerSpec = swaggerJSDoc(options);
|
||||
|
||||
const setupSwagger = (app) => {
|
||||
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
|
||||
};
|
||||
|
||||
module.exports = setupSwagger;
|
21
bondarenko_max_lab_3/docker-compose.yml
Normal file
21
bondarenko_max_lab_3/docker-compose.yml
Normal file
@ -0,0 +1,21 @@
|
||||
version: '3.7'
|
||||
|
||||
services:
|
||||
authors:
|
||||
build:
|
||||
context: ./authors
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
||||
books:
|
||||
build:
|
||||
context: ./books
|
||||
ports:
|
||||
- "3001:3001"
|
||||
|
||||
nginx:
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf
|
25
bondarenko_max_lab_3/nginx.conf
Normal file
25
bondarenko_max_lab_3/nginx.conf
Normal file
@ -0,0 +1,25 @@
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
upstream authors_service {
|
||||
server authors:3000;
|
||||
}
|
||||
|
||||
upstream books_service {
|
||||
server books:3001;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
location /authors {
|
||||
proxy_pass http://authors_service;
|
||||
}
|
||||
|
||||
location /books {
|
||||
proxy_pass http://books_service;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user