REST API на Python с Flask, Connexion и SQLAlchemy. Часть 1

Оглавление

Введение

Большинство современных веб-приложений работают на основе REST API. Это позволяет разработчикам отделить код фронтенда от внутренней логики, а пользователям — динамически взаимодействовать с интерфейсом.

В этой серии статей, состоящей из трех частей, мы создадим REST API на базе веб-фреймворка Flask.

Мы сделаем базовый проект Flask, добавим к нему конечные точки и подключим к базе данных SQLite. Далее мы протестируем наш проект при помощи документации API от Swagger UI , которую создадим по ходу дела.

Из первой части данной серии статей вы узнаете, как:

  • создавать проект Flask при помощи REST API
  • обрабатывать HTTP-запросы при помощи Connexion
  • определять конечные точки API при помощи спецификации OpenAPI
  • взаимодействовать с API для управления данными
  • создавать пользовательскую документацию по API при помощи Swagger UI.

Затем мы перейдем ко второй части. В ней мы рассмотрим использование базы данных для постоянного хранения информации (вместо использования для этого оперативной памяти).

Эта серия статей представляет собой практическое руководство по созданию REST API при помощи фреймворка Flask и взаимодействию с ним при помощи CRUD-операций. Вы можете скачать код первой части данного проекта по данной ссылке.

Краткое содержание

В этой серии статей мы построим REST API, с помощью которого сможем оставлять записки-напоминания для вымышленных персонажей. Это те сущности, которые могут посещать нас в течение года. В этой части мы создадим следующих персонажей: Зубную фею, Пасхального кролика и кнехта Рупрехта.

Понятно, что мы хотим быть с ними в хороших отношениях. Поэтому, чтобы увеличить шансы на хорошие подарки, мы будем отправлять им всем записки.

Взаимодействовать со своим приложением мы сможем при помощи документации API. По ходу дела мы создадим базовый фронтенд, отражающий содержимое нашей базы данных.

В этой статье мы создадим базовый проект Flask и подключим к нему свои первые конечные точки API. В итоге мы сможем увидеть список персонажей во фронтенде и управлять всеми ими в бэкенде.

Используя Swagger UI, мы создадим удобную документацию для нашего API. Это даст нам возможность проверять работу API на каждом этапе данной статьи и отслеживать все наши конечные точки.

План первой части

Помимо создания основы для нашего проекта Flask мы собираемся создать REST API, который будет обеспечивать доступ к группе персонажей и отдельным лицам в этой группе. Вот дизайн API для такой группы людей:

ДействиеHTTP-запросURL-путьОписание
ЧтениеGET/api/peopleСчитываем группу персонажей
СозданиеPOST/api/peopleСоздаем нового персонажа
ЧтениеGET/api/people/<lname>Считываем конкретного персонажа
ОбновлениеPUT/api/people/<lname>Обновляем существующего персонажа
УдалениеDELETE/api/people/<lname>Удаляем персонажа

REST API, который мы будем создавать, должен обслуживать простую структуру данных персонажей, где ключами будут выступать их «фамилии» а любые обновления будут помечаться новой отметкой времени.

Набор данных, с которым мы будем работать, выглядит следующим образом:

PEOPLE = {
    "Fairy": {
        "fname": "Tooth",
        "lname": "Fairy",
        "timestamp": "2022-10-08 09:15:10",
    },
    "Ruprecht": {
        "fname": "Knecht",
        "lname": "Ruprecht",
        "timestamp": "2022-10-08 09:15:13",
    },
    "Bunny": {
        "fname": "Easter",
        "lname": "Bunny",
        "timestamp": "2022-10-08 09:15:27",
    }
}

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

Начало

В этом разделе мы подготовим среду разработки для нашего Flask-проекта. Начнем с создания виртуальной среды и установки всех необходимых зависимостей.

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

В этом разделе мы создадим структуру проекта. Корневую папку нашего проекта можно назвать как угодно. Например, назовем ее rp_flask_api/. Итак, создадим папку и перейдем в нее:

$ mkdir rp_flask_api
$ cd rp_flask_api

Мы создали корневую папку проекта rp_flask_api/. Файлы и папки, которые мы создадим в ходе этой серии статей, будут расположены либо в этой папке, либо в ее подпапках.

После перехода в папку проекта рекомендуется создать и активировать виртуальную среду. Это позволит устанавливать любые зависимости не для всей системы, а только в виртуальной среде нашего проекта.

Настроить виртуальную среду можно следующим образом:

# Для Windows

PS> python -m venv venv
PS> .\venv\Scripts\activate
(venv) PS>

# Для Linux или macOS

$ python -m venv venv
$ source venv/bin/activate
(venv) $

С помощью этих команд мы создаем и активируем виртуальную среду с именем venv, используя встроенный в Python модуль venv.

Запись (venv) перед приглашением командной строки показывает, что мы успешно создали и активировали виртуальную среду.

Добавляем зависимости

После создания и активации виртуальной среды настало время установить Flask при помощи менеджера pip:

(venv) $ python -m pip install Flask==2.2.2

Микрофреймворк Flask — это основная зависимость, которая требуется нашему проекту. Поверх Flask установим Connexion для обработки HTTP-запросов:

(venv) $ python -m pip install "connexion[swagger-ui]==2.14.1"

Чтобы использовать автоматически создаваемую документацию по API, мы устанавливаем Connexion с добавленной поддержкой Swagger UI. Со всеми этими пакетами мы познакомимся чуть позже.

Инициализируем Flask-проект

Основным файлом Flask-проекта будет app.py. Создаем файл его в директории rp_flask_api/ и добавляем в него следующий код:

# app.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def home():
    return render_template("home.html")

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000, debug=True)

Мы импортируем Flask, предоставляя приложению доступ к функциям данного модуля. После этого создаем экземпляр приложения Flask с именем app.

Далее, при помощи декоратора @app.route("/"), мы подключаем маршрут URL «/» к функции home(). Эта функция вызывает функцию Flask render_template(), чтобы получить файл home.html из каталога шаблонов и вернуть его в браузер.

Если вкратце, этот код создает и запускает базовый веб-сервер и заставляет его возвращать шаблон home.html, который будет отображаться в браузере при переходе по URL-адресу «/».

Примечание: Сервер разработки Flask по умолчанию использует порт 5000. В более новых версиях macOS этот порт уже используется macOS AirPlay. Выше мы изменили порт своего приложения Flask на порт 8000. При желании можно вместо этого изменить настройки AirPlay на своем Mac.

Сервер Flask ожидает, что файл home.html находится в каталоге шаблонов с именем templates/. Создадим каталог templates/ и добавим в него файл home.html со следующим содержанием:

<!-- templates/home.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>RP Flask REST API</title>
</head>
<body>
    <h1>
        Hello, World!
    </h1>
</body>
</html>

Flask поставляется с движком шаблонов Jinja, который позволяет существенно совершенствовать шаблоны. Но наш шаблон home.html представляет собой простой HTML-файл без каких-либо функций Jinja. На данный момент это нормально, потому что первая цель home.html — убедиться, что наш проект Flask работает так, как задумано.

Когда созданная нами виртуальная среда Python активна, мы можем запустить свое приложение при помощи следующей команды (при этом нужно находиться в каталоге, содержащем файл app.py):

(venv) $ python app.py

Когда вы запускаете app.py, веб-сервер запускается через порт 8000. Если вы откроете браузер и перейдете по адресу http://localhost:8000, вы должны увидеть фразу Hello, World!:

Поздравляем, наш веб-сервер запущен! Позже мы расширим файл home.html для работы с нашим REST API.

На данный момент структура нашего проекта Flask имеет следующий вид:

rp_flask_api/
│
├── templates/
│   └── home.html
│
└── app.py

Это отличная структура для запуска любого проекта Flask. 

В следующих разделах мы расширим данный проект и добавим в него первые конечные точки REST API.

Добавляем первую конечную точку REST API

Теперь, имея работающий веб-сервер, мы можем добавить первую конечную точку REST API. Для этого мы применим Connexion, который установили в предыдущем разделе.

Модуль Connexion позволяет программе на Python использовать со Swagger спецификацию OpenAPI .

Спецификация OpenAPI представляет собой формат описания API для REST API и предоставляет множество функций, в том числе:

  • проверку входных и выходных данных вашего API
  • настройку URL-адресов конечных точек API и ожидаемых параметров.

При использовании OpenAPI вместе со Swagger можно создать пользовательский интерфейс для работы с API. Для этого необходимо создать конфигурационный файл, к которому наше Flask-приложение будет иметь доступ.

Создаем конфигурационный файл нашего API

Конфиг Swagger — это файл YAML или JSON, содержащий наши определения OpenAPI. Этот файл содержит всю информацию, необходимую для настройки сервера.

Создадим файл с именем swagger.yml и начнем добавлять в него метаданные:

# swagger.yml

openapi: 3.0.0
info:
  title: "RP Flask REST API"
  description: "An API about people and notes"
  version: "1.0.0"

При определении API мы должны установить версию определения OpenAPI. Для этого используется ключевое слово openapi. Строка версии важна, так как некоторые части структуры OpenAPI могут со временем измениться.

Кроме того, точно так же, как каждая новая версия Python включает новые функции, в спецификации OpenAPI могут быть добавлены или исключены ключевые слова.

Ключевое слово info начинает область действия информационного блока API:

  • title: заголовок, включенный в систему пользовательского интерфейса, сгенерированную Connexion
  • description: описание того, что API дает возможность сделать
  • version: значение версии API

Затем добавьте серверы и URL-адреса, которые определяют корневой путь вашего API:

# swagger.yml

# ...

servers:
  - url: "/api"

Указав «/api» в качестве значения URL-адреса, мы сможем получить доступ ко всем путям API относительно http://localhost:8000/api.

Конечные точки API мы определим в блоке путей paths:

# swagger.yml

# ...

paths:
  /people:
    get:
      operationId: "people.read_all"
      tags:
        - "People"
      summary: "Read the list of people"
      responses:
        "200":
          description: "Successfully read people list"

Блок paths определяет конфигурацию URL-адреса для каждой конечной точки API:

  • /people: относительный URL-адрес вашей конечной точки API
  • get: HTTP-метод, которому будет отвечать конечная точка по этому URL-адресу

Вместе с определением url в servers это создает URL-адрес конечной точки GET /api/peoplehttp://localhost:8000/api/people.

Блок get определяет конфигурацию URL-адреса отдельной конечной точки /api/people:

  • operationId: функция Python, которая отвечает на запрос
  • tags: теги, связанные с данной конечной точкой; они позволяют группировать операции в пользовательском интерфейсе
  • summary: отображаемый текст пользовательского интерфейса для данной конечной точки
  • responses: коды состояния, которые посылает данная конечная точка

OperationId должен содержать строку. Connexion будет использовать форму people.read_all, чтобы найти функцию Python с именем read_all() в модуле people нашего проекта. Позже в данной статье мы создадим соответствующий код.

Блок responses определяет конфигурацию возможных кодов состояния. Здесь мы определяем успешный ответ для кода состояния 200, содержащий некоторый текст описания description.

Ниже файл swagger.yml приведен полностью:

# swagger.yml

openapi: 3.0.0
info:
  title: "RP Flask REST API"
  description: "An API about people and notes"
  version: "1.0.0"

servers:
  - url: "/api"

paths:
  /people:
    get:
      operationId: "people.read_all"
      tags:
        - "People"
      summary: "Read the list of people"
      responses:
        "200":
          description: "Successfully read people list"

Мы организовали этот файл в иерархическом порядке. Каждый уровень отступа представляет собой уровень владения или область действия.

Например, paths отмечает начало блока, где определены все URL-адреса конечных точек API. Значение /people представляет собой начало блока, где будут определены все конечные точки по URL-адресу /api/people. Область get в разделе /people содержит определения, связанные с HTTP-запросом GET к конечной точке по URL-адресу /api/people. Этот шаблон действует для всего конфига.

Файл swagger.yml похож на план нашего API. С помощью спецификаций, включенных в этот файл, мы определяем, какие данные может ожидать наш веб-сервер и как сервер должен отвечать на запросы. Но пока наш проект Flask ничего не знает о файле swagger.yml. Для соединения OpenAPI с Flask-приложением мы будем использовать Connexion.

Связываем Connexion c приложением

Чтобы добавить URL-адрес конечной точки REST API в наше Flask-приложение при помощи Connexion, нужно выполнить два шага:

  1. Добавить конфигурационный файл API в наш проект.
  2. Связать Flask-приложение с этим файлом.

В предыдущем разделе мы уже добавили файл под именем swagger.yml. Чтобы подключить его к нашему Flask-приложнию, нужно прописать его в файле app.py:

# app.py

from flask import render_template # Remove: import Flask
import connexion

app = connexion.App(__name__, specification_dir="./")
app.add_api("swagger.yml")

@app.route("/")
def home():
    return render_template("home.html")

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000, debug=True)

Выражение import connexion добавляет модуль в программу. Следующий шаг — это создание экземпляра класса Connexion вместо Flask. Flask-приложение по прежнему будет создано, но теперь у него появятся дополнительные функции.

Одним из параметров данного приложения является specification_dir (6 строка). Он сообщает классу Connexion, в какой директории искать конфигурационный файл. В данном случае он находится в той же папке, что и файл app.py.

В следующей строке мы читаем файл swagger.yml и настраиваем систему для обеспечения функциональности класса Connexion.

Получаем данные от конечной точки people

В файле swagger.yml мы настроили Connexion со значением operationId "people.read_all". Поэтому, когда API получает HTTP-запрос для GET /api/people, наше приложение Flask вызывает функцию read_all() в модуле people.

Чтобы это заработало, надо создать файл people.py с функцией read_all():

# people.py

from datetime import datetime

def get_timestamp():
    return datetime.now().strftime(("%Y-%m-%d %H:%M:%S"))

PEOPLE = {
    "Fairy": {
        "fname": "Tooth",
        "lname": "Fairy",
        "timestamp": get_timestamp(),
    },
    "Ruprecht": {
        "fname": "Knecht",
        "lname": "Ruprecht",
        "timestamp": get_timestamp(),
    },
    "Bunny": {
        "fname": "Easter",
        "lname": "Bunny",
        "timestamp": get_timestamp(),
    }
}

def read_all():
    return list(PEOPLE.values())

В строке 5 мы создаем вспомогательную функцию с именем get_timestamp(), которая генерирует строковое представление текущей метки времени.

Затем мы определяем структуру данных словаря PEOPLE (в строке 8), с которой и будем работать в этой статье.

Словарь PEOPLE заменяет нам базу данных. Поскольку PEOPLE является переменной модуля, ее состояние сохраняется между вызовами REST API. Однако любые данные, которые мы изменим, будут потеряны при перезапуске веб-приложения. Это, разумеется не идеально, но пока сойдет и так.

Затем мы создаем функцию read_all() (строка 26). Наш сервер запустит эту функцию, когда получит HTTP-запрос на GET /api/people. Возвращаемое значение функции read_all() — это список словарей с информацией о персонаже.

Запустив код нашего сервера и перейдя в браузере по адресу http://localhost:8000/api/people, мы увидим список персонажей на экране:

Поздравляем, вы только что создали свою первую конечную точку API! Прежде чем продолжить создание REST API с несколькими конечными точками, давайте потратим еще немного времени и изучим API немного подробнее.

Изучаем документацию API

На данный момент у нас есть REST API, работающий только с одной конечной точкой. Наше приложение Flask знает, что обслуживать, на основе нашей спецификации API в файле swagger.yml. Кроме того, класс Connexion использует swagger.yml для создания для нас документации по API.

Перейдём по адресу localhost:8000/api/ui, чтобы увидеть документацию по API в действии:

Это первоначальный интерфейс Swagger. Он показывает список URL конечных точек, поддерживаемых нашей конечной точкой http://localhost:8000/api. Класс Connexion создает его автоматически при анализе файла swagger.yml.

Нажав на конечную точку /people в интерфейсе, вы увидите больше информации о вашем API.

Будет выведена структура ожидаемого ответа, тип содержимого этого ответа и введенный нами текст описания конечной точки в файле swagger.yml. При любом изменении файла конфигурации меняется и пользовательский интерфейс Swagger.

Мы даже можем проверить конечную точку, нажав кнопку «Try it out». Эта функция может быть чрезвычайно полезна, когда наш API быстро растет. Документация API, сгенерированная Swagger UI, дает вам возможность исследовать API и экспериментировать с ним без необходимости писать для этого какой-либо код.

Использование OpenAPI со Swagger UI обеспечивает удобный и понятный способ создания URL-адресов конечных точек API. Пока что мы создали только одну конечную точку для обслуживания всех персонажей сразу. В следующем разделе мы добавим дополнительные конечные точки для создания, обновления и удаления персонажей в нашем словаре.

Создание полноценного API

Пока у нашего REST API есть только одна конечная точка. Пора создать API, обеспечивающий полный CRUD-доступ к нашей структуре персонажей. Как вы помните, определение нашего API выглядит следующим образом:

ДействиеHTTP-запросURL-путьОписание
ЧтениеGET/api/peopleСчитываем группу персонажей
СозданиеPOST/api/peopleСоздаем нового персонажа
ЧтениеGET/api/people/<lname>Считываем конкретного персонажа
ОбновлениеPUT/api/people/<lname>Обновляем существующего персонажа
УдалениеDELETE/api/people/<lname>Удаляем персонажа

Чтобы реализовать это, нам надо расширить файлы swagger.yml и people.py соответствующим образом.

Работа с компонентами

Прежде чем определять новые пути API в файле swagger.yml, нам нужно добавить новый блок для компонентов.

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

Добавьте блок components вместе с блоком schemas для одного персонажа:

# swagger.yml

openapi: 3.0.0
info:
  title: "RP Flask REST API"
  description: "An API about people and notes"
  version: "1.0.0"

servers:
  - url: "/api"

components:
  schemas:
    Person:
      type: "object"
      required:
        - lname
      properties:
        fname:
          type: "string"
        lname:
          type: "string"
# ...

Мы создаем эти блоки во избежание дублирования кода. На данный момент в блоке schemas мы сохраняем только модель Person:

  • type: тип данных
  • required: требуемые свойства

Дефис (-) перед -lname указывает, что required может содержать список свойств. Любое свойство, которое мы определяем как обязательное, также должно существовать в properties, включая следующие:

  • fname: имя персонажа
  • lname: его «фамилия»

Ключ type определяет значение, связанное с его родительским ключом. Для Person все свойства являются строками. Позже в этом руководстве мы представим эту схему в виде словаря Python.

Создание нового персонажа

Расширим конечные точки API, добавив новый блок для запроса POST в блоке /people:

# swagger.yml

# ...

paths:
  /people:
    get:
        # ...
    post:
      operationId: "people.create"
      tags:
        - People
      summary: "Create a person"
      requestBody:
          description: "Person to create"
          required: True
          content:
            application/json:
              schema:
                x-body-name: "person"
                $ref: "#/components/schemas/Person"
      responses:
        "201":
          description: "Successfully created person"

Структура запроса post похожа на существующую схему запроса get. Первое отличие состоит в том, что на сервер мы также отправляем requestBody. В конце концов, нам нужно сообщить Flask информацию, необходимую для создания нового персонажа. Второе отличие — это operationId, для которого мы устанавливаем значение people.create.

Внутри content мы определяем application/json как формат обмена данными нашего API.

В своих запросах к API и ответах API мы можем использовать различные типы данных. В настоящее время в качестве формата обмена данными обычно используют JSON. Это хорошая новость для нас как Python-разработчиков, поскольку объекты JSON очень похожи на словари Python. Например:

{
    "fname": "Tooth",
    "lname": "Fairy"
}

Этот объект JSON напоминает компонент Person, который мы определили ранее в файле swagger.yml и на который мы ссылаемся с помощью $ref в блоке schema.

Мы также используем код состояния HTTP 201, который является успешным ответом, указывающим на создание нового ресурса.

Примечание: Если вы хотите узнать больше о кодах состояния HTTP, то можете ознакомиться с документацией Mozilla на эту тему.

При помощи выражения people.create мы говорим серверу искать функцию create() в модуле people. Откроем файл people.py и добавим туда функцию create():

# people.py

from datetime import datetime
from flask import abort

# ...

def create(person):
    lname = person.get("lname")
    fname = person.get("fname", "")

    if lname and lname not in PEOPLE:
        PEOPLE[lname] = {
            "lname": lname,
            "fname": fname,
            "timestamp": get_timestamp(),
        }
        return PEOPLE[lname], 201
    else:
        abort(
            406,
            f"Person with last name {lname} already exists",
        )

В строке 4 мы импортируем функцию Abort() из модуля Flask. Использование этой функции помогает нам отправить сообщение об ошибке в строке 20. Мы вызываем сообщение об ошибке, когда тело запроса не содержит фамилии или когда персонаж с такой фамилией уже существует.

Примечание: Фамилия персонажа должна быть уникальной, потому что мы используем lname в качестве ключа словаря PEOPLE. Это означает, что в вашем проекте пока не может быть двух персонажей с одинаковой фамилией.

Если данные в теле запроса валидны, мы обновляем словарь PEOPLE в строке 13 и возвращаем новый объект и HTTP-код 201 в строке 18.

Обработка персонажа

На данный момент мы можем создать нового персонажа и получить их полный список. В этом разделе мы обновим файлы swagger.yml и people.py, чтобы они работали с новым путем, который будет обрабатывать одного существующего пользователя.

Откроем файл swagger.yml и добавим следующий код:

# swagger.yml

# ...

components:
  schemas:
    # ...
  parameters:
    lname:
      name: "lname"
      description: "Last name of the person to get"
      in: path
      required: True
      schema:
        type: "string"

paths:
  /people:
    # ...
  /people/{lname}:
    get:
      operationId: "people.read_one"
      tags:
        - People
      summary: "Read one person"
      parameters:
        - $ref: "#/components/parameters/lname"
      responses:
        "200":
          description: "Successfully read person"

Как и в случае с нашим путем /people, мы начинаем с операции get для пути /people/{lname}. Подстрока {lname} является заполнителем для фамилии, которую мы должны передать в качестве параметра URL. Так, например, URL-путь api/people/Ruprecht содержит имя Рупрехта (Ruprecht) в качестве lname.

Примечание: URL-параметры чувствительны к регистру. Это означает, что мы должны ввести фамилию, например Ruprecht, с заглавной буквой R.

Параметр lname мы будем использовать и в других операциях. Поэтому имеет смысл создать для него отдельный компонент и ссылаться на него там, где это необходимо.

operationId указывает на функцию read_one() в файле people.py, поэтому снова перейдём к этому файлу и создадим отсутствующую функцию:

# people.py

# ...

def read_one(lname):
    if lname in PEOPLE:
        return PEOPLE.get[lname]
    else:
        abort(
            404, f"Person with last name {lname} not found"
        )

Когда наше приложение Flask находит данную фамилию в словаре PEOPLE, оно возвращает данные для этого конкретного персонажа. В противном случае сервер вернет код ответа HTTP 404 (ошибка).

Чтобы иметь возможность обновлять существующего персонажа, изменим файл swagger.yml:

# swagger.yml

# ...

paths:
  /people:
    # ...
  /people/{lname}:
    get:
        # ...
    put:
      tags:
        - People
      operationId: "people.update"
      summary: "Update a person"
      parameters:
        - $ref: "#/components/parameters/lname"
      responses:
        "200":
          description: "Successfully updated person"
      requestBody:
        content:
          application/json:
            schema:
              x-body-name: "person"
              $ref: "#/components/schemas/Person"

При таком определении операции put наш сервер ожидает функцию update() в файле people.py:

# people.py

# ...

def update(lname, person):
    if lname in PEOPLE:
        PEOPLE[lname]["fname"] = person.get("fname", PEOPLE[lname]["fname"])
        PEOPLE[lname]["timestamp"] = get_timestamp()
        return PEOPLE[lname]
    else:
        abort(
            404,
            f"Person with last name {lname} not found"
        )

Функция update() принимает аргументы lname и person. Если персонаж с данной фамилией уже существует, то мы просто обновляем соответствующие значения в словаре PEOPLE.

Чтобы удалить персонажа из нашего набора данных, нужно использовать операцию delete:

# swagger.yml

# ...

paths:
  /people:
    # ...
  /people/{lname}:
    get:
        # ...
    put:
        # ...
    delete:
      tags:
        - People
      operationId: "people.delete"
      summary: "Delete a person"
      parameters:
        - $ref: "#/components/parameters/lname"
      responses:
        "204":
          description: "Successfully deleted person"

Добавим соответствующую функцию delete() в файл person.py:

# people.py

from flask import abort, make_response

# ...

def delete(lname):
    if lname in PEOPLE:
        del PEOPLE[lname]
        return make_response(
            f"{lname} successfully deleted", 200
        )
    else:
        abort(
            404,
            f"Person with last name {lname} not found"
        )

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

Итак, мы закончили работу над фалами people.py и swagger.yml.

Когда созданы все конечные точки для управления пользователями, пришло время опробовать наш API. Поскольку мы использовали Connexion для подключения нашего проекта Flask к Swagger, документация по API будет готова после перезапуска сервера.

Изучаем документацию API

После обновления файлов swagger.yml и people.py система Swagger UI также обновится.

Этот UI (пользовательский интерфейс) позволяет просматривать всю документацию, которую мы включили в файл swagger.yml, и взаимодействовать со всеми конечными точками по заданным URL-адресам для осуществления CRUD-операций.

К сожалению, любые внесенные вами изменения не сохранятся после перезапуска приложения Flask. Вот почему в следующей части этого руководства мы подключим к своему проекту базу данных.

Заключение

В первой части нашей серии статей мы создали REST API с помощью веб-фреймворка Flask на Python. При помощи модуля Connexion и дополнительной настройки мы создали полезную документацию и интерактивную систему. Это делает создание REST API очень приятным занятием.

Мы разобрали, как:

  • создать базовый проект Flask с REST API.
  • обрабатывать HTTP-запросы при помощи модуля Connexion.
  • задать конечные точки API, используя спецификацию OpenAPI
  • взаимодействовать с API для управления данными
  • создать документацию по API при помощи Swagger UI.

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

Перевод статьи Филиппа Аксани «Python REST APIs With Flask, Connexion, and SQLAlchemy – Part 1».