Merge pull request 'morozov_vladimir_lab_3 is ready' (#175) from morozov_vladimir_lab_3 into main

Reviewed-on: #175
This commit is contained in:
Alexey 2024-11-29 15:47:09 +04:00
commit a171fb7572
10 changed files with 284 additions and 0 deletions

1
morozov_vladimir_lab_3/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.idea

View File

@ -0,0 +1,18 @@
version: '3'
# Объявляем сервисы
services:
artists_srv: # сервис приложения артистов
build: ./service_artists/
paints_srv: # сервис приложения картин
build: ./service_paints/
gateway: # сервис nginx
image: nginx:latest # назначаем его образ
ports: # пробрасываем порта
- 8080:8080
volumes: # перекидываем конфигурационный файл
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on: # ожидаем запуска предыдущих сервисов
- artists_srv
- paints_srv

View File

@ -0,0 +1,39 @@
events {
worker_connections 1024;
}
http
{
server {
listen 8080;
listen [::]:8080;
server_name localhost;
location /artists/ {
proxy_pass http://artists_srv:8001/artists/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /artists/docs {
proxy_pass http://artists_srv:8001/docs;
proxy_set_header Host $host;
}
location /paints/docs {
proxy_pass http://paints_srv:8002/docs;
proxy_set_header Host $host;
}
location /paints/ {
proxy_pass http://paints_srv:8002/paints/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}

View File

@ -0,0 +1,26 @@
# Лабораторная работа №3 - REST API, Gateway и синхронный обмен между микросервисами
## Разработанные приложения
В рамках л/р были разработаны 2 приложения:
1) Сервис для работы с сущностью художник(artist). Сущность имеет следующие поля:
1) uid (номер)
2) name (ФИО)
3) year (год рождения)
2) Сервис для работы с сущностью картина(paint). Сущность имеет следующие поля:
1) uid (номер)
2) title (название)
3) year (год создания)
4) author (номер художника)
Один художник(один) может создать несколько картин(многие)
## Приготовления
Для обеспечения нужной работоспособности нашего приложения был использован веб-сервер Nginx, который можем использовать в роли прокси сервера.
Для этого нужно было развернуть его в отдельном контейнере и настроить его конфигурационный файл, в которым мы описывали прослушиваемые адреса и куда нужно перенаправлять.
Сервисы развернули в обычном порядке: написали код приложения, создали докер-файл, записали в докер-композе.
## Запуск
Для запуска приложения используем команду:
```
docker-compose up --build
```
## Запись тестирования
Работа приложения представлена в [видео](https://disk.yandex.ru/i/8yuoSm0QSR9wGw)

View File

@ -0,0 +1,77 @@
import sys
import uuid
import uvicorn
from fastapi import FastAPI, Body
from fastapi.responses import JSONResponse
from fastapi.encoders import jsonable_encoder
app = FastAPI(title="Artists service")
# Сервис для работы с художниками
# класс сущности художник
class artist:
def __init__(self, name, year, uid=""):
if len(uid) == 0:
self.uid = str(uuid.uuid4())
else:
self.uid = uid
self.name = name
self.year = year
# Первоначальные данные
artists = [
artist("Vincent van Gogh","1853","d1c02854-76d8-4a35-be5c-076f091a67c0"),
artist("Claude Monet","1840","41e2dadc-1aa8-4f14-b1e8-7fc5664d1cdf"),
artist("Ilya Repin","1844", "591f8c2f-1937-44a1-b1f8-ff1f8b52cece")]
# Получение всех художников
@app.get("/artists/")
async def get_all():
json_data = jsonable_encoder(artists)
return JSONResponse(json_data)
# Получение конкретного художника
@app.get("/artists/{uid}")
def get_uid(uid):
for art in artists:
if art.uid == uid:
json_data = jsonable_encoder(art)
return JSONResponse(json_data)
return JSONResponse(content={"message": "Resource Not Found"}, status_code=404)
# Создание нового художника
@app.post("/artists/")
def create(name = Body(embed=True), year = Body(embed=True)):
for art in artists:
if art.name.lower() == name.lower():
return JSONResponse(content={"message": "Resource Not Found"}, status_code=404)
new_artist = artist(name,year)
artists.append(new_artist)
json_data = jsonable_encoder(new_artist)
return JSONResponse(json_data)
# Изменение данных о художники
@app.put("/artists/{uid}")
def update(uid, name = Body(embed=True), year = Body(embed=True)):
for art in artists:
if uid == art.uid:
art.name = name
art.year = year
json_data = jsonable_encoder(art)
return JSONResponse(json_data)
return JSONResponse(content={"message": "Resource Not Found"}, status_code=404)
# Удаление художника
@app.delete("/artists/{uid}")
def delete(uid):
ind = 0
find = False
for art in artists:
if art.uid == uid:
find = True
break
ind += 1
if find:
artists.pop(ind)
return JSONResponse(content={"message": "Resource Deleted"}, status_code=200)
else:
return JSONResponse(content={"message": "Resource Not Found"}, status_code=404)
if __name__ == '__main__' :
uvicorn.run("app:app",host="0.0.0.0", port=8001,)

View File

@ -0,0 +1,10 @@
# объявляем базовый образ, на основе которого будет все построено
FROM "python:3.9-slim"
# назначаем основную рабочую директорию
WORKDIR /usr/src/app
# копируем содержимое текущей папке (скрипт питона) в контейнер, в основную рабочую папку
COPY . .
# установка req
RUN pip install -r req.txt
# при запуске образа выполняем команду запуска приложения
CMD [ "python", "app.py"]

View File

@ -0,0 +1,4 @@
fastapi[all]
uuid
uvicorn
requests

View File

@ -0,0 +1,95 @@
import sys
import uuid
import requests
import uvicorn
from fastapi import FastAPI, Body
from fastapi.responses import JSONResponse
from fastapi.encoders import jsonable_encoder
app = FastAPI(title="Paints service")
# Сервис для работы с картинами
# Класс картины
class paint:
def __init__(self, title,year,author):
self.uid = str(uuid.uuid4())
self.title = title
self.year = year
self.author = author
# Первоначальные данные
paints = [
paint("Sunflowers","1887", "d1c02854-76d8-4a35-be5c-076f091a67c0"),
paint("Self-portrait with a severed ear and a tube","1889", "d1c02854-76d8-4a35-be5c-076f091a67c0"),
paint("Boatmen on the Volga","1873", "591f8c2f-1937-44a1-b1f8-ff1f8b52cece")]
# Получение всех картин
@app.get("/paints/")
async def get_all():
json_data = jsonable_encoder(paints)
return JSONResponse(json_data)
# Получение конкретной картины
@app.get("/paints/{uid}")
def get_uid(uid):
for art in paints:
if art.uid == uid:
response = requests.get(f"http://artists_srv:8001/artists/{art.author}")
author = response.json()
result = {
"uid":art.uid,
"title":art.title,
"year":art.year,
"authorUid":art.author,
"author":author
}
json_data = jsonable_encoder(result)
return JSONResponse(json_data)
return JSONResponse(content={"message": "Resource Not Found"}, status_code=404)
# Создание новой картины
@app.post("/paints/")
def create(title = Body(embed=True), year = Body(embed=True), author = Body(embed=True)):
for art in paints:
if art.title.lower() == title.lower():
return JSONResponse(content={"message": "Resource Not Found"}, status_code=404)
response = requests.get(f"http://artists_srv:8001/artists/{author}")
if response.status_code == 404:
return JSONResponse(content={"message": "Resource Not Found"}, status_code=404)
new_paint = paint(title,year, author)
paints.append(new_paint)
json_data = jsonable_encoder(new_paint)
return JSONResponse(json_data)
# Обновление данных о картине
@app.put("/paints/{uid}")
def update(uid, title = Body(embed=True), year = Body(embed=True), author = Body(embed=True)):
response = requests.get(f"http://artists_srv:8001/artists/{author}")
print(author)
print(response.status_code)
if response.status_code == 404:
return JSONResponse(content={"message": "Resource Not Found"}, status_code=404)
for art in paints:
if uid == art.uid:
art.title = title
art.year = year
art.author = author
json_data = jsonable_encoder(art)
return JSONResponse(json_data)
return JSONResponse(content={"message": "Resource Not Found"}, status_code=404)
# Удаление картины
@app.delete("/paints/{uid}")
def delete(uid):
ind = 0
find = False
for art in paints:
if art.uid == uid:
find = True
break
ind += 1
if find:
paints.pop(ind)
return JSONResponse(content={"message": "Resource Deleted"}, status_code=200)
else:
return JSONResponse(content={"message": "Resource Not Found"}, status_code=404)
if __name__ == '__main__' :
uvicorn.run("app:app", host="0.0.0.0", port=8002,)

View File

@ -0,0 +1,10 @@
# объявляем базовый образ, на основе которого будет все построено
FROM "python:3.9-slim"
# назначаем основную рабочую директорию
WORKDIR /usr/src/app
# копируем содержимое текущей папке (скрипт питона) в контейнер, в основную рабочую папку
COPY . .
# установка зависимостей
RUN pip install -r req.txt
# при запуске образа выполняем команду запуска приложения
CMD [ "python", "app.py"]

View File

@ -0,0 +1,4 @@
fastapi[all]
uuid
uvicorn
requests