Разработка веб-приложения на Python с использованием FastAPI и Docker

d70d1066671bfe4294d81cd78f84ec07

Целью данной лабораторной работы является создание веб-приложения для работы с абстрактными элементами (items). Для достижения этой цели мы будем использовать язык программирования Python, веб-фреймворк FastAPI и контейнеризацию с помощью Docker. Работа включает в себя установку необходимых инструментов, написание кода приложения, и контейнеризацию для обеспечения удобства развертывания.

Теоретическая база

Python и FastAPI

Python выбран в качестве основного языка программирования из-за его простоты и мощности. FastAPI был выбран как веб-фреймворк благодаря высокой производительности и интуитивно понятному синтаксису.

Docker

Docker используется для контейнеризации приложения, что позволяет упаковать все зависимости и окружение в один контейнер. Это обеспечивает переносимость и упрощает развертывание приложения.

Цели и задачи

  1. Установка Python и Docker.

  2. Создание виртуального окружения и установка зависимостей.

  3. Написание кода веб-приложения с использованием FastAPI.

  4. Тестирование приложения.

  5. Создание Docker-образа и запуск контейнера.

  6. Проверка работоспособности приложения в контейнере.

Технические требования

Ожидаемые результаты

  1. Виртуальное окружение с установленными зависимостями.

  2. Работающее веб-приложение с возможностью добавления, изменения, удаления и получения элементов.

  3. Docker-образ, готовый для развертывания приложения.

  4. Проверка работоспособности приложения в контейнере.

Выполнение лабораторной работы

Настройка виртуального окружения и зависимостей:

  1. Склонируйте данный репозиторий

  2. Перейдите в него

  3. Создайте виртуальное окружение

    python3 -m venv venv

  4. Активируйте его

    source venv/bin/activate

  5. Установите pip-tools

    pip install pip-tools

  6. Создайте файл requirements.in и откройте его

  7. Запишите в данный файл следующие строки

    fastapi

    uvicorn

  8. Далее в консоли с активированным виртуальным окружением пишем

    pip-compile

  9. У нас автоматически создаться requirements.txt, в котором будут библиотеки и фреймворки совместимых версий. Далее данной командой все библиотеки установятся в наше виртуальное окружение.

    pip-sync

Написание веб-приложения:

Мы разработаем простое веб-приложение, которое будет работать с абстрактными элементами (назовем их items). Наше приложение сможет хранить items, также по запросу пользователя приложение сможет добавлять новые items, изменять их и удалять. В item будут лежать данные о его названии, цене и наличии.

1. Создать файл main.py и запустить его

2. Далее импортируем классы FastAPI, HTTPException, status для дальнейшей работы с ними

from fastapi import FastAPI, HTTPException, status

3. Создаем экземпляр класса FastAPI для создания нашего приложения. Также
нам потребуется создать список items для хранения данных и переменную
items_id для идентификации items

app = FastAPI()
items = []
items_id = 1

4. Создадим первый endpoint, который будет возвращать сообщение «Hello World»

@app.get('/')
def root():
    return {'message': 'Hello World'}

5. Далее создадим endpoint '/items', который будет обрабатывать GET-запросы и возвращать требуемый item, если он существует

@app.get('/items')
def get_item(item_id: int):
    try:
        return items[item_id - 1]
    except IndexError:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='item does not exists')

Проверка существования item происходит за счёт блока try except. Если элемента с переданным id не существует, будет вызвано исключение IndexError, так как мы выйдем за границы нашего списка. Если элемента не существует, мы оповещаем об этом пользователя статус-кодом 400 и сообщением «item does not exists»

6. Теперь создадим endpoint '/items', который будет обрабатывать POST-запросы, создавать item и добавлять его в список items

@app.post('/items')
def create_item(name: str, coast: float, in_stock: bool):
    global items_id
    item = {
        'id': items_id,
        'name': name,
        'coast': coast,
        'in_stock': in_stock
    }
    items.append(item)
    items_id += 1
    return item

Мы работаем с глобальной переменной items_id, так как у каждого item должен быть уникальный id, поэтому перед return увеличиваем её на 1

7. По этому же endpoint будем обрабатывать PATCH-запросы для частичного изменения требуемого item

@app.patch('/items')
def patch_item(item_id: int, new_name: str = None, new_coast: float = None, new_in_stock: bool = None):
    try:
        if new_name:
            items[item_id - 1]['name'] = new_name
            return items[item_id - 1]
        elif new_coast:
            items[item_id - 1]['coast'] = new_coast
            return items[item_id - 1]
        elif new_in_stock:
            items[item_id - 1]['in_stock'] = new_in_stock
            return items[item_id - 1]
    except IndexError:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='item does not exists')

Так же, как и при обработке GET-запросов будем проверять, существует ли требуемый item

8. Теперь будем обрабатывать PUT-запросы для полного изменения требуемого item

@app.put('/items')
def patch_item(item_id: int, new_name: str, new_coast: float, new_in_stock: bool):
    try:
        items[item_id - 1]['name'] = new_name
        items[item_id - 1]['coast'] = new_coast
        items[item_id - 1]['in_stock'] = new_in_stock
        return items[item_id - 1]
    except IndexError:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='item does not exists')

Все так же, как и в прошлом пункте, только требуемый item изменяется полностью

9. Создадим обработчик DELETE-запросов для удаления требуемого item

@app.delete('/items')
def delete_item(item_id: int):
    global items_id
    try:
        if item_id != len(items):
            for index in range(item_id, len(items)):
                items[index]['id'] -= 1
        item = items.pop(item_id - 1)
        items_id -= 1
        return item
    except IndexError:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='item does not exists')

Наше приложение готово. Теперь можно запустить его и проверить работоспособность.

Запуск веб-приложения:

Теперь мы можем запустить наше веб-приложение, для этого введем команду

uvicorn main:app

Теперь мы можем перейти по ссылке localhost:8000/docs и делать запросы к нашему приложению

Контейнеризация приложения:

1. Создать Dockerfile и запустить его

2. Сначала импортируем образ python

FROM python:yourversion

Вместо yourversion напишите вашу версию python

3. Теперь сделаем рабочую директорию app

WORKDIR /app

4. Далее скопируем файлы, необходимые для работы нашего приложения

COPY ./main.py /app
COPY ./requirements.txt /app

5. Установим зависимости внутри образа

RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt

6. Наконец, напишем последнюю команду, которая будет исполняться при запуске контейнера

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]

Флаг --host 0.0.0.0 отвечает за то, чтобы наше веб-приложение работало на всех сетевых интерфейсах контейнера на порту 80.

7. Теперь создадим образ. Впишем в консоли

docker build -t fastapiapp .

8. Запустим контейнер, используя образ fastapiapp

docker run -d --name fastapiapp -p 8000:80 fastapiapp

Флаг -d отвечает за запуск контейнера в фоновом режиме. Флагом --name задаем имя нашему контейнеру. Флагом -p мы пробрасываем 80 порт контейнера на 8000 порт хоста

Проверка работоспособности:

Теперь можем перейти по ссылке localhost:8000/docs и проверить работоспособность нашего веб-приложения

Чтобы остановить работу контейнера, надо прописать данную команду в консоль

docker stop fastapiapp

Выводы

Лабораторная работа предоставила ценный опыт в области разработки backend-приложений, особенно в использовании веб-фреймворка FastAPI. Этот опыт оказывается крайне полезным для студентов и профессионалов, стремящихся погрузиться в мир веб-разработки и создания надежных серверных приложений.

Кроме того, работа с Docker в контексте данного проекта предоставила понимание принципов контейнеризации и умения упаковывать приложения со всеми их зависимостями в единый контейнер. Этот подход обеспечивает переносимость и удобство развертывания приложений в различных средах.

Особое внимание уделялось работе с портами в контейнере, что является важным навыком при создании масштабируемых и безопасных веб-приложений. Практика работы с портами в контейнере предоставляет необходимые навыки для эффективного управления входящими и исходящими сетевыми соединениями.

Таким образом, лабораторная работа не только дала практический опыт в создании веб-приложений с использованием FastAPI, но также подготовила к важным аспектам контейнеризации и управлению сетевыми портами в контейнеризированных приложениях.

Список использованных источников:

  1. Документация FastAPI

  2. Документация Docker

  3. Примеры кода и руководства по созданию веб-приложений с FastAPI.

  4. Официальные ресурсы Python и pip-tools

© Habrahabr.ru