diff --git a/.idea/misc.xml b/.idea/misc.xml
index ae8ddd2..027c300 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,7 @@
-
+
+
+
+
\ No newline at end of file
diff --git a/ismailov_rovshan_lab_3/README.md b/ismailov_rovshan_lab_3/README.md
new file mode 100644
index 0000000..ada00c3
--- /dev/null
+++ b/ismailov_rovshan_lab_3/README.md
@@ -0,0 +1,42 @@
+# Лабораторная работа №3 - REST API, Gateway и синхронный обмен между микросервисами
+## ПИбд-42 || Исмаилов Ровшан
+
+### Описание:
+ рамках лабораторной работы были созданы две сущности со связью "один-ко-многим". Реализованы все CRUD-операции, включая:
+- Получение списка записей.
+- Получение одной записи.
+- Создание новой записи.
+- Редактирование существующей записи.
+- Удаление записи.
+
+Для сущности "Факультет" добавлена возможность получения записи вместе со списком всех связанных специальностей. Этот функционал предполагает взаимодействие с другим сервисом. Также реализована проверка существования факультета по его ID.
+
+Сущность "Специальность" дополнена следующими функциями:
+- Получение списка записей с информацией о факультетах.
+- Получение записей, связанных с конкретным факультетом (по ID факультета).
+- Получение одной записи с подробной информацией о факультете.
+
+### Цель лабораторной работы
+Овладение принципами проектирования шаблона Gateway, построения синхронного взаимодействия между микросервисами и разработкой RESTful API.
+### Выбранные сущности:
+- Факультет. Поля: Uuid, Name и Description
+- Специальность. Поля: Uuid, Name, CountPlaces и Faculty_Id
+
+### Инструкция для работы
+1. Клонирование репозитория:
+```
+git clone <ссылка-на-репозиторий>
+cd <папка репозитория>
+cd <папка лабораторной работы>
+```
+
+2. Запуск контейнеров:
+```
+docker compose up --build
+```
+
+3. Результаты:
+В результате можно будет применят CRUD операции к сущностям через http запросы. Для демонстрации был выбран знакомый инструмент Postman.
+
+### Видео с демонстрацией работы:
+https://cloud.mail.ru/public/ktx4/3dHDsNr7T
\ No newline at end of file
diff --git a/ismailov_rovshan_lab_3/docker-compose.yaml b/ismailov_rovshan_lab_3/docker-compose.yaml
new file mode 100644
index 0000000..6724b9e
--- /dev/null
+++ b/ismailov_rovshan_lab_3/docker-compose.yaml
@@ -0,0 +1,27 @@
+services:
+
+ faculty_service:
+ container_name: faculty_service
+ build:
+ context: .
+ dockerfile: ./faculty_service/Dockerfile
+ expose:
+ - 10001
+
+ speciality_service:
+ container_name: speciality_service
+ build:
+ context: .
+ dockerfile: ./speciality_service/Dockerfile
+ expose:
+ - 10002
+
+ nginx:
+ image: nginx:latest
+ ports:
+ - "80:80"
+ volumes:
+ - ./nginx.conf:/etc/nginx/nginx.conf
+ depends_on:
+ - faculty_service
+ - speciality_service
\ No newline at end of file
diff --git a/ismailov_rovshan_lab_3/faculty_service/Dockerfile b/ismailov_rovshan_lab_3/faculty_service/Dockerfile
new file mode 100644
index 0000000..677590a
--- /dev/null
+++ b/ismailov_rovshan_lab_3/faculty_service/Dockerfile
@@ -0,0 +1,11 @@
+FROM python:3.12
+
+WORKDIR /app
+
+COPY requirements.txt .
+
+RUN pip install --no-cache-dir -r requirements.txt
+
+COPY faculty_service/faculty_service.py .
+
+CMD ["python", "faculty_service.py"]
\ No newline at end of file
diff --git a/ismailov_rovshan_lab_3/faculty_service/faculty_service.py b/ismailov_rovshan_lab_3/faculty_service/faculty_service.py
new file mode 100644
index 0000000..9d26675
--- /dev/null
+++ b/ismailov_rovshan_lab_3/faculty_service/faculty_service.py
@@ -0,0 +1,129 @@
+from flask import Flask, jsonify, request
+from uuid import uuid4
+import uuid
+import requests
+
+
+class Faculty:
+ def __init__(self, name, description, uuid_: uuid):
+ if uuid_ is None:
+ self.uuid_: uuid = uuid4()
+ else:
+ self.uuid_: uuid = uuid.UUID(uuid_)
+ self.name: str = name
+ self.description: str = description
+
+ def to_dict(self):
+ return {
+ "uuid": self.uuid_,
+ "name": self.name,
+ "description": self.description
+ }
+
+ def to_dict_with_specialities(self, specialities: list):
+ return {
+ "uuid": self.uuid_,
+ "name": self.name,
+ "description": self.description,
+ "specialities": specialities
+ }
+
+
+app = Flask(__name__)
+
+faculties: list[Faculty] = [
+ Faculty(name='ФКИТ', description='Факультет компьютерных и информационных технологий', uuid_='3c87a9a1-1a3e-402d-8a53-6bbba478e644'),
+ Faculty(name='ФГН', description='Факультет гуманитарных наук', uuid_='a9e36307-02dc-4ee0-a771-e6d39cae9a75'),
+ Faculty(name='ФЭТ', description='Факультет электроники и телекоммуникаций', uuid_='3e7fc35d-f3bb-4657-bdcf-cf19191f3bc0'),
+ Faculty(name='ИУЭФ', description='Институт управления и экономики', uuid_='bb8571c4-f4a9-4d6e-b1f3-6efe4f54166e')
+]
+
+specialities_url = 'http://speciality_service:10002/'
+
+
+def list_jsonify():
+ return jsonify([faculty.to_dict() for faculty in faculties])
+
+
+# получение списка всех факультетов
+@app.route('/', methods=['GET'])
+def get_all():
+ return list_jsonify(), 200
+
+
+# получение факультета по id
+@app.route('/', methods=['GET'])
+def get_one(uuid_):
+ for faculty in faculties:
+ if faculty.uuid_ == uuid_:
+ return faculty.to_dict(), 200
+
+ return 'Факультет с указанным uuid не обнаружен', 404
+
+
+# получение факультета со списком специальностей
+@app.route('/with-specialities/', methods=['GET'])
+def get_one_with_specialities(uuid_):
+ for faculty in faculties:
+ if faculty.uuid_ == uuid_:
+ response = requests.get(specialities_url + f'by-faculty/{uuid_}')
+ print(response.json())
+ return faculty.to_dict_with_specialities(response.json()), 200
+
+ return 'Факультет с указанным uuid не обнаружен', 404
+
+
+# проверка наличия факультета по id (для специальности)
+@app.route('/check/', methods=['GET'])
+def check_exist(uuid_):
+ for faculty in faculties:
+ if faculty.uuid_ == uuid_:
+ return '', 200
+ return '', 404
+
+
+# создание факультета
+@app.route('/', methods=['POST'])
+def create():
+ data = request.json
+ name = data.get('name', None)
+ description = data.get('description', None)
+ if name is None or description is None:
+ return 'Не хватает данных для создания нового факультета', 404
+
+ new_faculty = Faculty(name, description, None)
+ faculties.append(new_faculty)
+ return get_one(new_faculty.uuid_)
+
+
+# изменение факультета по id
+@app.route('/', methods=['PUT'])
+def update_by_id(uuid_):
+ data = request.json
+ new_name = data.get('name', None)
+ new_description = data.get('description', None)
+
+ for faculty in faculties:
+ if faculty.uuid_ == uuid_:
+ if new_name is not None:
+ faculty.name = new_name
+ if new_description is not None:
+ faculty.description = new_description
+ return get_one(faculty.uuid_)
+
+ return 'Факультет с указанным uuid не обнаружен', 404
+
+
+# удаление факультета по id
+@app.route('/', methods=['DELETE'])
+def delete(uuid_):
+ for faculty in faculties:
+ if faculty.uuid_ == uuid_:
+ faculties.remove(faculty)
+ return 'Факультет был удален', 200
+
+ return 'Факультет с указанным uuid не обнаружен', 404
+
+
+if __name__ == '__main__':
+ app.run(host='0.0.0.0', port=10001, debug=True)
diff --git a/ismailov_rovshan_lab_3/gitignore b/ismailov_rovshan_lab_3/gitignore
new file mode 100644
index 0000000..eb53ea0
--- /dev/null
+++ b/ismailov_rovshan_lab_3/gitignore
@@ -0,0 +1,2 @@
+/.venv
+/.idea
\ No newline at end of file
diff --git a/ismailov_rovshan_lab_3/nginx.conf b/ismailov_rovshan_lab_3/nginx.conf
new file mode 100644
index 0000000..75c0926
--- /dev/null
+++ b/ismailov_rovshan_lab_3/nginx.conf
@@ -0,0 +1,26 @@
+
+events { worker_connections 1024; }
+
+http {
+ server {
+ listen 80;
+ listen [::]:80;
+ server_name localhost;
+
+ location /faculty_service/ {
+ proxy_pass http://faculty_service:10001/;
+ 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 /speciality_service/ {
+ proxy_pass http://speciality_service:10002/;
+ 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ismailov_rovshan_lab_3/requirements.txt b/ismailov_rovshan_lab_3/requirements.txt
new file mode 100644
index 0000000..41917d8
Binary files /dev/null and b/ismailov_rovshan_lab_3/requirements.txt differ
diff --git a/ismailov_rovshan_lab_3/speciality_service/Dockerfile b/ismailov_rovshan_lab_3/speciality_service/Dockerfile
new file mode 100644
index 0000000..44b959d
--- /dev/null
+++ b/ismailov_rovshan_lab_3/speciality_service/Dockerfile
@@ -0,0 +1,11 @@
+FROM python:3.12
+
+WORKDIR /app
+
+COPY requirements.txt .
+
+RUN pip install --no-cache-dir -r requirements.txt
+
+COPY speciality_service/speciality_service.py .
+
+CMD ["python", "speciality_service.py"]
\ No newline at end of file
diff --git a/ismailov_rovshan_lab_3/speciality_service/speciality_service.py b/ismailov_rovshan_lab_3/speciality_service/speciality_service.py
new file mode 100644
index 0000000..19c1715
--- /dev/null
+++ b/ismailov_rovshan_lab_3/speciality_service/speciality_service.py
@@ -0,0 +1,154 @@
+from flask import Flask, jsonify, request
+import requests
+from uuid import uuid4
+import uuid
+
+
+class Speciality:
+ def __init__(self, name, countPlaces, uuid_: uuid, faculty_id: uuid):
+ if uuid_ is None:
+ self.uuid_: uuid = uuid4()
+ else:
+ self.uuid_: uuid = uuid.UUID(uuid_)
+ self.name: str = name
+ self.countPlaces: int = countPlaces
+ self.faculty_id: uuid = uuid.UUID(faculty_id)
+
+ def to_dict(self):
+ return {
+ 'name': self.name,
+ 'countPlaces': self.countPlaces,
+ 'faculty_id': self.faculty_id,
+ 'uuid': self.uuid_
+ }
+
+ def to_dict_for_faculties(self):
+ return {
+ 'name': self.name,
+ 'countPlaces': self.countPlaces,
+ 'uuid': self.uuid_
+ }
+
+ def to_dict_with_info(self, faculty: dict):
+ return {
+ 'name': self.name,
+ 'countPlaces': self.countPlaces,
+ 'faculty_id': self.faculty_id,
+ 'faculty_info': faculty,
+ 'uuid': self.uuid_
+ }
+
+
+app = Flask(__name__)
+
+specialities: list[Speciality] = [
+ Speciality(name='Разработка программного обеспечения', countPlaces=39, uuid_='a6233a8e-7b54-4927-954a-cafbdbf142fe',
+ faculty_id='3c87a9a1-1a3e-402d-8a53-6bbba478e644'),
+ Speciality(name='Информационная аналитика', countPlaces=53, uuid_='c1863dee-7b27-4252-9327-9226dd10eebe',
+ faculty_id='3c87a9a1-1a3e-402d-8a53-6bbba478e644'),
+ Speciality(name='Перевод и межкультурная коммуникация', countPlaces=23, uuid_='da1f1594-39c7-4407-8c54-883e9a8565ea',
+ faculty_id='a9e36307-02dc-4ee0-a771-e6d39cae9a75'),
+ Speciality(name='Системы связи', countPlaces=46, uuid_='a7156dbf-b102-40bd-9eb9-d53c110cfe0d',
+ faculty_id='3e7fc35d-f3bb-4657-bdcf-cf19191f3bc0'),
+ Speciality(name='Контроль качества и управление', countPlaces=17, uuid_='1a24d9b7-72d2-4918-8a86-b80608c855f6',
+ faculty_id='3e7fc35d-f3bb-4657-bdcf-cf19191f3bc0')
+]
+
+facuties_url = 'http://faculty_service:10001/'
+
+
+def list_jsonify():
+ return jsonify([speciality.to_dict() for speciality in specialities])
+
+
+@app.route('/', methods=['GET'])
+def get_all():
+ return list_jsonify(), 200
+
+
+@app.route('/full', methods=['GET'])
+def get_all_full():
+ faculties: list[dict] = requests.get(facuties_url).json()
+ response = []
+ for speciality in specialities:
+ for faculty in faculties:
+ if speciality.faculty_id == uuid.UUID(faculty.get('uuid')):
+ response.append(speciality.to_dict_with_info(faculty))
+
+ return response, 200
+
+
+@app.route('/by-faculty/', methods=['GET'])
+def get_by_faculty_id(faculty_uuid):
+ return [speciality.to_dict_for_faculties() for speciality in specialities if speciality.faculty_id == faculty_uuid], 200
+
+
+# получение специальности по id
+@app.route('/', methods=['GET'])
+def get_one(uuid_):
+ for speciality in specialities:
+ if speciality.uuid_ == uuid_:
+ return speciality.to_dict(), 200
+
+ return 'Специальность с указанным uuid не обнаружена', 404
+
+
+@app.route('/full/', methods=['GET'])
+def get_one_full(uuid_):
+ for speciality in specialities:
+ if speciality.uuid_ == uuid_:
+ response = requests.get(facuties_url + str(speciality.faculty_id))
+ return speciality.to_dict_with_info(response.json()), 200
+
+ return 'Специальность с указанным uuid не обнаружена', 404
+
+
+@app.route('/', methods=['POST'])
+def create():
+ data = request.json
+ name = data.get('name', None)
+ countPlaces = data.get('countPlaces', None)
+ faculty_id = data.get('faculty_id', None)
+ checking = requests.get(facuties_url + f'/check/{faculty_id}')
+ print(checking)
+ if checking.status_code == 200:
+ new_speciality = Speciality(name, countPlaces, None, faculty_id)
+ specialities.append(new_speciality)
+ return get_one(new_speciality.uuid_)
+ if checking.status_code == 404:
+ return 'Факультета с таким uuid не существует', 404
+
+ return 'Неизвестная ошибка', 500
+
+
+@app.route('/', methods=['PUT'])
+def update_by_id(uuid_):
+ data = request.json
+ new_name = data.get('name', None)
+ new_countPlaces = data.get('countPlaces', None)
+
+ for speciality in specialities:
+ print(speciality.uuid_)
+
+ if speciality.uuid_ == uuid_:
+ if new_name is not None:
+ speciality.name = new_name
+ if new_countPlaces is not None:
+ speciality.countPlaces = new_countPlaces
+ return get_one(speciality.uuid_)
+
+ return 'Специальность с указанным uuid не обнаружена', 404
+
+
+@app.route('/', methods=['DELETE'])
+def delete(uuid_):
+ for speciality in specialities:
+ if speciality.uuid_ == uuid_:
+ specialities.remove(speciality)
+ return 'Специальность была удалена', 200
+
+ return 'Специальность с указанным uuid не обнаружена', 404
+
+
+if __name__ == '__main__':
+ app.run(host='0.0.0.0', port=10002, debug=True)