klyushenkova_ksenia_lab_3 is ready

This commit is contained in:
Pineapple 2024-12-20 10:20:16 +04:00
parent 5dd9e26f07
commit a4d674af99
13 changed files with 375 additions and 0 deletions

View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyInterpreterInspection" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/lab_2.iml" filepath="$PROJECT_DIR$/.idea/lab_2.iml" />
</modules>
</component>
</project>

2
klyushenkova_ksenia_lab_3/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/.venv
/.idea

View File

@ -0,0 +1,27 @@
# Клюшенкова Ксения ПИбд-42
# Лабораторная работа №3 - REST API, Gateway и синхронный обмен между микросервисами
### Язык разработки приложений: Python
## Выбранные сущности:
- Режиссёр. Содержит Uuid, Name, Surname
- Фильм. Содержит Uuid, Title, Year, Director_id
## Описание:
Для каждой сущности были реализованы стандартные CRUD-операции: получение всех записей, получение конкретной записи,
создание записи, изменение записи, удаление записи.
Дополнительно для сущности Режиссёр:
1. Получение режиссёра со списком фильмов(с полной информацией). При этом сервис взаимодействует с другим сервисом,
чтобы получить список фильмов по идентификатору автора.
2. Операция проверка наличия режиссёра по идентификатору (для сервиса книг).
Дополнительно для сущности Фильм прописаны:
1. Получение списка записей с полной информацией о режиссёре (не только идентификатор).
2. Получение списка записей по идентификатору режиссёра (для сервиса режиссёров).
3. Получение конкретной записи с полной информацией о режиссёре.
## [Видео](https://disk.yandex.ru/i/TnsxOrHV9SuFLw)

View File

@ -0,0 +1,11 @@
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY director_service/director_service.py .
CMD ["python", "director_service.py"]

View File

@ -0,0 +1,122 @@
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from uuid import UUID, uuid4
import requests
from typing import List, Optional
import uvicorn
app = FastAPI(root_path="/director_service", title="Director API", description="API для управления режиссерами", version="1.0.0")
class Director:
def __init__(self, name: str, surname: str, uuid_: Optional[UUID] = None):
self.uuid_ = uuid_ if uuid_ else uuid4()
self.name: str = name
self.surname: str = surname
def to_dict(self):
return {
"uuid": str(self.uuid_),
"name": self.name,
"surname": self.surname
}
def to_dict_with_movies(self, movies: list):
return {
"uuid": str(self.uuid_),
"name": self.name,
"surname": self.surname,
"movies": movies
}
class CreateDirectorRequest(BaseModel):
name: str
surname: str
class UpdateDirectorRequest(BaseModel):
name: Optional[str]
surname: Optional[str]
directors: List[Director] = [
Director(name="Christopher", surname="Nolan", uuid_=UUID("997aa4c5-ebb2-4794-ba81-e742f9f1fa30")),
Director(name="Quentin", surname="Tarantino", uuid_=UUID("694827e4-0f93-45a5-8f75-bad7ef2d21fe")),
Director(name="Greta", surname="Gerwig", uuid_=UUID("eb815350-c7b9-4446-8434-4c0640c21995"))
]
movies_url = "http://movie_service:8081/"
@app.get("/", response_model=List[dict])
def get_all():
"""Получение списка всех режиссёров."""
return [director.to_dict() for director in directors]
@app.get("/{uuid_}", response_model=dict)
def get_one(uuid_: UUID):
"""Получение режиссёра по идентификатору."""
for director in directors:
if director.uuid_ == uuid_:
return director.to_dict()
raise HTTPException(status_code=404, detail="Режиссёр с таким uuid не был найден")
@app.get("/with-movies/{uuid_}", response_model=dict)
def get_one_with_movies(uuid_: UUID):
"""Получение режиссёра со списком его фильмов."""
for director in directors:
if director.uuid_ == uuid_:
response = requests.get(f"{movies_url}by-director/{uuid_}")
if response.status_code != 200:
raise HTTPException(status_code=404, detail="Не удалось получить фильмы режиссёра")
return director.to_dict_with_movies(response.json())
raise HTTPException(status_code=404, detail="Режиссёр с таким uuid не был найден")
@app.get("/check/{uuid_}", response_class=JSONResponse)
def check_exist(uuid_: UUID):
"""Проверка наличия режиссёра по идентификатору (для movie_service)."""
for director in directors:
if director.uuid_ == uuid_:
return JSONResponse(content="", status_code=200)
return JSONResponse(content="", status_code=404)
@app.post("/", response_model=dict)
def create(director: CreateDirectorRequest):
"""Создание нового режиссёра."""
new_director = Director(name=director.name, surname=director.surname)
directors.append(new_director)
return new_director.to_dict()
@app.put("/{uuid_}", response_model=dict)
def update_by_id(uuid_: UUID, director_update: UpdateDirectorRequest):
"""Изменение данных режиссёра по идентификатору."""
for director in directors:
if director.uuid_ == uuid_:
if director_update.name is not None:
director.name = director_update.name
if director_update.surname is not None:
director.surname = director_update.surname
return director.to_dict()
raise HTTPException(status_code=404, detail="Режиссёр с таким uuid не был найден")
@app.delete("/{uuid_}", response_class=JSONResponse)
def delete(uuid_: UUID):
"""Удаление режиссёра по идентификатору."""
for director in directors:
if director.uuid_ == uuid_:
directors.remove(director)
return JSONResponse(content="Режиссёр успешно удалён", status_code=200)
raise HTTPException(status_code=404, detail="Режиссёр с таким uuid не был найден")
if __name__ == "__main__":
uvicorn.run("director_service:app", host="0.0.0.0", port=8080, reload=True)

View File

@ -0,0 +1,27 @@
services:
director_service:
container_name: director_service
build:
context: .
dockerfile: ./director_service/Dockerfile
expose:
- 8080
movie_service:
container_name: movie_service
build:
context: .
dockerfile: ./movie_service/Dockerfile
expose:
- 8081
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- director_service
- movie_service

View File

@ -0,0 +1,11 @@
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY movie_service/movie_service.py .
CMD ["python", "movie_service.py"]

View File

@ -0,0 +1,97 @@
from fastapi import FastAPI, HTTPException, Request
from pydantic import BaseModel
from typing import List, Optional
from uuid import UUID, uuid4
import requests
import uvicorn
app = FastAPI(root_path="/movie_service", title="Movie Service", description="Service to manage movies and their directors", version="1.0.0")
directors_url = "http://director_service:8080/"
class Movie(BaseModel):
uuid: UUID
title: str
year: int
director_id: UUID
class MovieCreate(BaseModel):
title: str
year: int
director_id: UUID
movies: List[Movie] = [
Movie(uuid=UUID("89fa1e7a-7e88-445e-a4d8-6d4497ea8f19"), title="Inception", year=2010, director_id=UUID("997aa4c5-ebb2-4794-ba81-e742f9f1fa30")),
Movie(uuid=UUID("0351ee11-f11b-4d83-b2c8-1075b0c357dc"), title="Pulp Fiction", year=1994, director_id=UUID("694827e4-0f93-45a5-8f75-bad7ef2d21fe")),
Movie(uuid=UUID("dfc17619-7690-47aa-ae8e-6a5068f8ddec"), title="Lady Bird", year=2017, director_id=UUID("eb815350-c7b9-4446-8434-4c0640c21995")),
Movie(uuid=UUID("3fad0e6b-cefc-40dd-99c0-adc5ec0290d2"), title="Django Unchained", year=2012, director_id=UUID("694827e4-0f93-45a5-8f75-bad7ef2d21fe")),
Movie(uuid=UUID("cf0cf26e-c1c6-43ea-bf59-1f8edb180e41"), title="Interstellar", year=2014, director_id=UUID("997aa4c5-ebb2-4794-ba81-e742f9f1fa30")),
Movie(uuid=UUID("2ac3c734-21ad-4450-884d-7de1f5452b9d"), title="The Grand Budapest Hotel", year=2014, director_id=UUID("eb815350-c7b9-4446-8434-4c0640c21995"))
]
@app.get("/", response_model=List[Movie], summary="Get all movies", description="Retrieve a list of all movies.")
def get_all_movies():
return movies
@app.get("/full", summary="Get all movies with director info", description="Retrieve all movies with additional director information.")
def get_all_movies_with_directors():
directors = requests.get(directors_url).json()
response = []
for movie in movies:
director_info = next((d for d in directors if d["uuid"] == str(movie.director_id)), None)
if director_info:
response.append({**movie.dict(), "director_info": director_info})
return response
@app.get("/by-director/{director_uuid}", response_model=List[Movie], summary="Get movies by director", description="Retrieve all movies for a given director.")
def get_movies_by_director(director_uuid: UUID):
return [movie for movie in movies if movie.director_id == director_uuid]
@app.get("/{movie_uuid}", response_model=Movie, summary="Get a movie by ID", description="Retrieve a single movie by its ID.")
def get_movie_by_id(movie_uuid: UUID):
movie = next((movie for movie in movies if movie.uuid == movie_uuid), None)
if not movie:
raise HTTPException(status_code=404, detail="Movie not found")
return movie
@app.get("/full/{movie_uuid}", summary="Get movie with director info", description="Retrieve a movie with additional director information.")
def get_movie_with_director_info(movie_uuid: UUID):
movie = next((movie for movie in movies if movie.uuid == movie_uuid), None)
if not movie:
raise HTTPException(status_code=404, detail="Movie not found")
director_info = requests.get(f"{directors_url}{movie.director_id}").json()
return {**movie.dict(), "director_info": director_info}
@app.post("/", response_model=Movie, summary="Create a new movie", description="Add a new movie to the database.")
def create_movie(movie: MovieCreate):
# Check if director exists
response = requests.get(f"{directors_url}check/{movie.director_id}")
if response.status_code == 404:
raise HTTPException(status_code=404, detail="Director not found")
new_movie = Movie(uuid=uuid4(), **movie.dict())
movies.append(new_movie)
return new_movie
@app.put("/{movie_uuid}", response_model=Movie, summary="Update a movie", description="Update an existing movie by its ID.")
def update_movie(movie_uuid: UUID, movie_update: MovieCreate):
movie = next((movie for movie in movies if movie.uuid == movie_uuid), None)
if not movie:
raise HTTPException(status_code=404, detail="Movie not found")
movie.title = movie_update.title
movie.year = movie_update.year
movie.director_id = movie_update.director_id
return movie
@app.delete("/{movie_uuid}", summary="Delete a movie", description="Remove a movie by its ID.")
def delete_movie(movie_uuid: UUID):
global movies
movies = [movie for movie in movies if movie.uuid != movie_uuid]
return {"detail": "Movie deleted successfully"}
if __name__ == "__main__":
uvicorn.run("movie_service:app", host="0.0.0.0", port=8081, reload=True)

View File

@ -0,0 +1,49 @@
events { worker_connections 1024; }
http {
server {
listen 80;
listen [::]:80;
server_name localhost;
location /director_service/ {
proxy_pass http://director_service:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /movie_service/ {
proxy_pass http://movie_service:8081/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /director_service/docs {
proxy_pass http://director_service:8080/docs;
}
location /movie_service/docs {
proxy_pass http://movie_service:8081/docs;
}
location /director_service/openapi.json {
proxy_pass http://director_service:8080/openapi.json;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /movie_service/openapi.json {
proxy_pass http://movie_service:8081/openapi.json;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}

View File

@ -0,0 +1,3 @@
fastapi
uvicorn
requests