You are currently viewing API Python и REST: Взаимодействие с Веб-службами

API Python и REST: Взаимодействие с Веб-службами

В Интернете доступно огромное количество данных. Многие веб-сервисы, такие как YouTube и GitHub, предоставляют доступ к своим данным сторонним приложениям через интерфейс прикладного программирования (API). Один из самых популярных способов создания API-интерфейсов-это стиль архитектуры REST. Python предоставляет несколько замечательных инструментов не только для получения данных из API-интерфейсов REST, но и для создания собственных API-интерфейсов Python REST.

В этом уроке вы узнаете:

  • Что такое архитектура REST
  • Как API REST предоставляют доступ к веб-данным
  • Как использовать данные из API-интерфейсов REST с помощью requests библиотеки
  • Какие шаги необходимо предпринять для создания REST API
  • Каковы некоторые популярные инструменты Python для создания API REST

Используя API Python и REST, вы можете извлекать, анализировать, обновлять и манипулировать данными, предоставляемыми любой веб-службой, которая вас интересует.

Бесплатный бонус: Нажмите здесь, чтобы загрузить копию руководства «Примеры REST API» и получить практическое введение в принципы Python + REST API с практическими примерами.

Архитектура ОТДЫХА

REST расшифровывается как representational state transfer и представляет собой стиль архитектуры программного обеспечения, который определяет шаблон для взаимодействия клиента и сервера по сети. REST предоставляет набор ограничений для архитектуры программного обеспечения для повышения производительности, масштабируемости, простоты и надежности системы.

REST определяет следующие архитектурные ограничения:

  • Без гражданства: Сервер не будет поддерживать какое-либо состояние между запросами от клиента.
  • Клиент-сервер: Клиент и сервер должны быть отделены друг от друга, позволяя каждому развиваться независимо.
  • Можно кэшировать: Данные, полученные с сервера, должны быть доступны для кэширования либо клиентом, либо сервером.
  • Единый интерфейс: Сервер обеспечит единый интерфейс для доступа к ресурсам без определения их представления.
  • Многоуровневая система: Клиент может получить доступ к ресурсам на сервере косвенно через другие уровни, такие как прокси-сервер или балансировщик нагрузки.
  • Код по запросу (необязательно): Сервер может передавать клиенту код, который он может запускать, например JavaScript для одностраничного приложения.

Обратите внимание, что REST-это не спецификация, а набор рекомендаций по проектированию программной системы, подключенной к сети.

API-интерфейсы REST и веб-службы

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

Например, вот один из URL-адресов для API REST GitHub:

https://api.github.com/users/<username>

Этот URL-адрес позволяет вам получить доступ к информации о конкретном пользователе GitHub. Вы получаете доступ к данным из REST API, отправляя HTTP-запрос по определенному URL-адресу и обрабатывая ответ.

Методы HTTP

API-интерфейсы REST прослушивают HTTP — методы, такие как GET, POST, и DELETE чтобы знать, какие операции следует выполнять с ресурсами веб-службы. Ресурс-это любые данные, доступные в веб-службе, к которым можно получить доступ и которыми можно управлять с помощью HTTP-запросов к REST API. Метод HTTP сообщает API, какое действие следует выполнить над ресурсом.

Несмотря на то, что существует множество методов HTTP, пять методов, перечисленных ниже, наиболее часто используются с API REST:

Метод HTTPОписание
GETИзвлеките существующий ресурс.
POSTСоздайте новый ресурс.
PUTОбновите существующий ресурс.
PATCHЧастично обновите существующий ресурс.
DELETEУдалите ресурс.

Клиентское приложение REST API может использовать эти пять методов HTTP для управления состоянием ресурсов в веб-службе.

Коды состояния

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

Ниже приведен список наиболее распространенных кодов состояния, возвращаемых API REST:

КодЗначениеОписание
200ОКЗапрошенное действие было успешным.
201СозданныйБыл создан новый ресурс.
202ПринятоЗапрос был получен, но никаких изменений пока внесено не было.
204Никакого КонтентаЗапрос был выполнен успешно, но ответ не содержит содержимого.
400Неверный ЗапросЗапрос был искажен.
401НеавторизованныйКлиент не уполномочен выполнять запрошенное действие.
404не найденоЗапрошенный ресурс не был найден.
415Неподдерживаемый Тип НосителяФормат данных запроса не поддерживается сервером.
422Необработанная СущностьДанные запроса были правильно отформатированы, но содержали неверные или отсутствующие данные.
500внутренняя ошибка сервераСервер выдал ошибку при обработке запроса.

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

Диапазон кодовКатегория
2xxУспешная операция
3xxПеренаправление
4xxОшибка клиента
5xxОшибка сервера

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

Конечные точки API

API REST предоставляет набор общедоступных URL-адресов, которые клиентские приложения используют для доступа к ресурсам веб-службы. Эти URL-адреса в контексте API называются конечными точками.

Чтобы прояснить это, взгляните на таблицу ниже. В этой таблице вы увидите конечные точки API для гипотетической CRM-системы. Эти конечные точки предназначены для ресурса клиента, который представляет потенциал customers в системе:

Метод HTTPКонечная точка APIОписание
GET/customersПолучите список клиентов.
GET/customers/<customer_id>Получите одного клиента.
POST/customersСоздайте нового клиента.
PUT/customers/<customer_id>Обновите клиента.
PATCH/customers/<customer_id>Частично обновите клиента.
DELETE/customers/<customer_id>Удалите клиента.

Каждая из указанных выше конечных точек выполняет различные действия на основе метода HTTP.

Примечание: Базовый URL-адрес для конечных точек был опущен для краткости. На самом деле вам понадобится полный URL-адрес для доступа к конечной точке API:

https://api.example.com/customers

Это полный URL-адрес, который вы использовали бы для доступа к этой конечной точке. Базовый URL — адрес-это все, кроме /customers того .

Вы заметите, что некоторые конечные точки имеют <customer_id> в конце. Это обозначение означает, что вам нужно добавить числовое customer_id значение к URL-адресу, чтобы сообщить API REST, с которым customer вы хотели бы работать.

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

REST и Python: Использование API

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

Чтобы начать использовать requests, вам нужно сначала установить его. Вы можете использовать pip его для установки:

$ python -m pip install requests

Теперь, когда вы requests установили, вы можете начать отправлять HTTP-запросы.

получить

GET это один из наиболее распространенных методов HTTP, который вы будете использовать при работе с API REST. Этот метод позволяет извлекать ресурсы из данного API. GET это операция только для чтения, поэтому вы не должны использовать ее для изменения существующего ресурса.

Для тестирования GET и других методов, описанных в этом разделе, вы будете использовать службу под названием JSON Placeholder. Эта бесплатная услуга предоставляет поддельные конечные точки API, которые отправляют ответы, которые requests могут быть обработаны.

Чтобы попробовать это, запустите Python REPL и выполните следующие команды для отправки GET запроса в конечную точку JSONPlaceholder:>>>

>>> import requests
>>> api_url = "https://jsonplaceholder.typicode.com/todos/1"
>>> response = requests.get(api_url)
>>> response.json()
{'userId': 1, 'id': 1, 'title': 'delectus aut autem', 'completed': False}

Этот код вызывает requests.get() отправку GET запроса /todos/1, на который отвечает todo элемент с идентификатором 1. Затем вы можете вызвать .json()response объект для просмотра данных, полученных из API.

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

Помимо просмотра данных JSON из API, вы также можете просмотреть другие сведения о response:>>>

>>> response.status_code
200

>>> response.headers["Content-Type"]
'application/json; charset=utf-8'

Здесь вы response.status_code можете просмотреть код состояния HTTP. Вы также можете просмотреть HTTP-заголовки ответа с response.headers помощью . Этот словарь содержит метаданные об ответе, такие как Content-Type ответ.

Публикация

Теперь взгляните на то, как вы используете requests POST данные для API REST для создания нового ресурса. Вы снова будете использовать JSON Placeholder, но на этот раз вы включите данные JSON в запрос. Вот данные, которые вы отправите:

{
    "userId": 1,
    "title": "Buy milk",
    "completed": false
}

Этот JSON содержит информацию для нового todo элемента. Вернувшись в РЕПЛ Python, запустите следующий код, чтобы создать новый todo:>>>

>>> import requests
>>> api_url = "https://jsonplaceholder.typicode.com/todos"
>>> todo = {"userId": 1, "title": "Buy milk", "completed": False}
>>> response = requests.post(api_url, json=todo)
>>> response.json()
{'userId': 1, 'title': 'Buy milk', 'completed': False, 'id': 201}

>>> response.status_code
201

Здесь вы вызываете requests.post(), чтобы создать новое todo в системе.

Во-первых, вы создаете словарь, содержащий данные для вашего todo. Затем вы передаете этот словарь в аргумент json ключевого слова of requests.post(). При этом requests.post()автоматически устанавливается значение HTTP-заголовка запроса Content-Typeapplication/json. Он также сериализуется todo в строку JSON, которую он добавляет в тело запроса.

Если вы не используете аргумент json ключевого слова для предоставления данных JSON, вам необходимо Content-Type соответствующим образом настроить и стерилизовать JSON вручную. Вот эквивалентная версия предыдущего кода:>>>

>>> import requests
>>> import json
>>> api_url = "https://jsonplaceholder.typicode.com/todos"
>>> todo = {"userId": 1, "title": "Buy milk", "completed": False}
>>> headers =  {"Content-Type":"application/json"}
>>> response = requests.post(api_url, data=json.dumps(todo), headers=headers)
>>> response.json()
{'userId': 1, 'title': 'Buy milk', 'completed': False, 'id': 201}

>>> response.status_code
201

В этом коде вы добавляете headers словарь, содержащий один Content-Type набор заголовков application/json. Это сообщает REST API, что вы отправляете данные JSON вместе с запросом.

Затем вы вызываете requests.post(), но вместо того, чтобы переходить todo к json аргументу, вы сначала вызываете json.dumps(todo) его для сериализации. После его сериализации вы передаете его в аргумент data ключевого слова. data Аргумент указывает requests, какие данные следует включить в запрос. Вы также передаете headers словарь requests.post(), чтобы вручную задать заголовки HTTP.

Когда вы вызываете requests.post() подобным образом, это имеет тот же эффект, что и предыдущий код, но дает вам больше контроля над запросом.

Примечание: json.dumps() поставляется из json пакета стандартной библиотеки. Этот пакет предоставляет полезные методы для работы с JSON в Python.

Как только API ответит, вы позвоните response.json(), чтобы просмотреть JSON. JSON включает в себя сгенерированный id для нового todo. Код 201 состояния сообщает вам, что был создан новый ресурс.

класть

Помимо GET и POSTrequests обеспечивает поддержку всех других методов HTTP, которые вы могли бы использовать с REST API. Следующий код отправляет PUT запрос на обновление существующих todo с новыми данными. Любые данные, отправленные с PUT запросом, полностью заменят существующие значения todo.

Вы будете использовать ту же конечную точку JSON Placeholder , которую использовали с GET и POST, но на этот раз вы добавите 10 ее в конец URL-адреса. Это сообщает API REST, который todo вы хотели бы обновить:>>>

>>> import requests
>>> api_url = "https://jsonplaceholder.typicode.com/todos/10"
>>> response = requests.get(api_url)
>>> response.json()
{'userId': 1, 'id': 10, 'title': 'illo est ... aut', 'completed': True}

>>> todo = {"userId": 1, "title": "Wash car", "completed": True}
>>> response = requests.put(api_url, json=todo)
>>> response.json()
{'userId': 1, 'title': 'Wash car', 'completed': True, 'id': 10}

>>> response.status_code
200

Здесь вы сначала звоните requests.get(), чтобы просмотреть содержимое существующего todo. Затем вы вызываете requests.put() новые данные JSON, чтобы заменить существующие значения задач. Вы можете видеть новые значения при вызове response.json(). Успешные PUT запросы всегда будут возвращаться 200, а 201 не потому, что вы не создаете новый ресурс, а просто обновляете существующий.

заплатка

Далее вы будете использовать requests.patch() для изменения значения определенного поля в существующем todoPATCH отличается от PUT этого тем, что он не полностью заменяет существующий ресурс. Он изменяет только значения, заданные в JSON, отправленном вместе с запросом.

Вы будете использовать то же todo самое из последнего примера, чтобы попробовать requests.patch(). Вот текущие значения:

{'userId': 1, 'title': 'Wash car', 'completed': True, 'id': 10}

Теперь вы можете обновить значение title с новым значением:>>>

>>> import requests
>>> api_url = "https://jsonplaceholder.typicode.com/todos/10"
>>> todo = {"title": "Mow lawn"}
>>> response = requests.patch(api_url, json=todo)
>>> response.json()
{'userId': 1, 'id': 10, 'title': 'Mow lawn', 'completed': True}

>>> response.status_code
200

Когда вы звоните response.json(), вы можете видеть, что title было обновлено до Mow lawn.

Удалить

И последнее, но не менее важное: если вы хотите полностью удалить ресурс, то вы его используете DELETE. Вот код для удаления todo:>>>

>>> import requests
>>> api_url = "https://jsonplaceholder.typicode.com/todos/10"
>>> response = requests.delete(api_url)
>>> response.json()
{}

>>> response.status_code
200

Вы вызываете requests.delete()с помощью URL-адреса API, содержащего идентификатор todo, который вы хотели бы удалить. Это отправляет DELETE запрос в REST API, который затем удаляет соответствующий ресурс. После удаления ресурса API отправляет обратно пустой объект JSON, указывающий, что ресурс удален.

requests Библиотека-это потрясающий инструмент для работы с API REST и незаменимая часть вашего пояса инструментов Python. В следующем разделе вы переключите передачу и рассмотрите, что требуется для создания REST API.

REST и Python: Создание API

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

Определение Ресурсов

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

При этом обязательно учитывайте любые вложенные ресурсы. Например, customers может иметь sales или events может содержать guests. Создание этих иерархий ресурсов поможет при определении конечных точек API.

Определите свои конечные точки

Как только вы определили ресурсы в своей веб-службе, вы захотите использовать их для определения конечных точек API. Вот несколько примеров конечных точек для transactions ресурса, которые вы можете найти в API для службы обработки платежей:

Метод HTTPКонечная точка APIОписание
GET/transactionsПолучите список транзакций.
GET/transactions/<transaction_id>Получите одну транзакцию.
POST/transactionsСоздайте новую транзакцию.
PUT/transactions/<transaction_id>Обновите транзакцию.
PATCH/transactions/<transaction_id>Частично обновите транзакцию.
DELETE/transactions/<transaction_id>Удалите транзакцию.

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

Примечание: Конечная точка не должна содержать глаголов. Вместо этого вы должны выбрать соответствующие методы HTTP для передачи действия конечной точки. Например, конечная точка ниже содержит ненужный глагол:

GET /getTransactions

Здесь get включается в конечную точку, когда это не нужно. Метод HTTP GET уже предоставляет семантическое значение для конечной точки, указывая действие. Вы можете удалить get из конечной точки:

GET /transactions

Эта конечная точка содержит только существительное во множественном числе, и метод HTTP GET передает действие.

Теперь взгляните на пример конечных точек для вложенного ресурса. Здесь вы увидите конечные guests точки, вложенные в events ресурсы:

Метод HTTPКонечная точка APIОписание
GET/events/<event_id>/guestsСоставьте список гостей.
GET/events/<event_id>/guests/<guest_id>Возьмите одного гостя.
POST/events/<event_id>/guestsСоздайте нового гостя.
PUT/events/<event_id>/guests/<guest_id>Обновите гостя.
PATCH/events/<event_id>/guests/<guest_id>Частично обновите гостя.
DELETE/events/<event_id>/guests/<guest_id>Удалите гостя.

С помощью этих конечных точек вы можете управлять guests определенным событием в системе.

Это не единственный способ определить конечную точку для вложенных ресурсов. Некоторые люди предпочитают использовать строки запроса для доступа к вложенному ресурсу. Строка запроса позволяет отправлять дополнительные параметры вместе с вашим HTTP-запросом. В следующей конечной точке вы добавляете строку запроса guests для получения определенного event_id:

GET /guests?event_id=23

Эта конечная точка отфильтрует все guests, что не ссылается на данный event_id. Как и во многих других аспектах проектирования API, вам нужно решить, какой метод лучше всего подходит для вашей веб-службы.

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

Существует широкий спектр стратегий управления версиями. Выбор правильного варианта зависит от требований вашего API. Ниже приведены некоторые из наиболее популярных вариантов управления версиями API:

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

Теперь, когда вы рассмотрели конечные точки, в следующем разделе вы рассмотрите некоторые параметры форматирования данных в вашем REST API.

Выберите формат обмена данными

Двумя популярными вариантами форматирования данных веб-службы являются XML и JSON. Традиционно XML был очень популярен в API SOAP, но JSON более популярен в API REST. Чтобы сравнить их, взгляните на пример book ресурса, отформатированного как XML и JSON.

Вот книга в формате XML:

<?xml version="1.0" encoding="UTF-8" ?>
<book>
    <title>Python Basics</title>
    <page_count>635</page_count>
    <pub_date>2021-03-16</pub_date>
    <authors>
        <author>
            <name>David Amos</name>
        </author>
        <author>
            <name>Joanna Jablonski</name>
        </author>
        <author>
            <name>Dan Bader</name>
        </author>
        <author>
            <name>Fletcher Heisler</name>
        </author>
    </authors>
    <isbn13>978-1775093329</isbn13>
    <genre>Education</genre>
</book>

XML использует ряд элементов для кодирования данных. Каждый элемент имеет открывающий и закрывающий тег с данными между ними. Элементы могут быть вложены в другие элементы. Вы можете видеть это выше, где <author> внутри вложено несколько тегов <authors>.

Теперь взгляните на то же book самое в JSON:

{
    "title": "Python Basics",
    "page_count": 635,
    "pub_date": "2021-03-16",
    "authors": [
        {"name": "David Amos"},
        {"name": "Joanna Jablonski"},
        {"name": "Dan Bader"},
        {"name": "Fletcher Heisler"}
    ],
    "isbn13": "978-1775093329",
    "genre": "Education"
}

JSON хранит данные в парах ключ-значение, подобных словарю Python. Как и XML, JSON поддерживает вложение данных на любом уровне, поэтому вы можете моделировать сложные данные.

Ни JSON, ни XML по своей сути не лучше других, но среди разработчиков REST API предпочтение отдается JSON. Это особенно верно, когда вы соединяете REST API с интерфейсной платформой, такой как React или Vue.

Ответы на Успешные Проекты

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

В этом разделе вы рассмотрите некоторые примеры HTTP-ответов для гипотетического API, который управляет инвентаризацией cars. Эти примеры дадут вам представление о том, как следует форматировать ответы API. Чтобы прояснить ситуацию, вы будете просматривать необработанные HTTP-запросы и ответы вместо использования такой HTTP-библиотеки, как requests.

Для начала взгляните на GET запрос /cars, который возвращает список cars:

GET /cars HTTP/1.1
Host: api.example.com

Этот HTTP-запрос состоит из четырех частей:

  1. GET является типом метода HTTP.
  2. /cars является конечной точкой API.
  3. HTTP/1.1 является версией HTTP.
  4. Host: api.example.com является хостом API.

Эти четыре части-все, что вам нужно для отправки GET запроса /cars. Теперь взгляните на ответ. Этот API использует JSON в качестве формата обмена данными:

HTTP/1.1 200 OK
Content-Type: application/json
...

[
    {
        "id": 1,
        "make": "GMC",
        "model": "1500 Club Coupe",
        "year": 1998,
        "vin": "1D7RV1GTXAS806941",
        "color": "Red"
    },
    {
        "id": 2,
        "make": "Lamborghini",
        "model":"Gallardo",
        "year":2006,
        "vin":"JN1BY1PR0FM736887",
        "color":"Mauve"
    },
    {
        "id": 3,
        "make": "Chevrolet",
        "model":"Monte Carlo",
        "year":1996,
        "vin":"1G4HP54K714224234",
        "color":"Violet"
    }
]

API возвращает ответ, содержащий список cars. Вы знаете, что ответ был успешным из 200 OK— за кода состояния. В ответе также установлен Content-Type заголовок на application/json. Это говорит пользователю проанализировать ответ как JSON.

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

Важно всегда указывать правильный Content-Type заголовок в своем ответе. Если вы отправляете JSON, установите Content-Type значение application/json. Если XML, то установите для него значение application/xml. Этот заголовок сообщает пользователю, как они должны анализировать данные.

Вы также хотите включить соответствующий код статуса в свой ответ. Для любого успешного GET запроса вы должны вернуться 200 OK. Это говорит пользователю о том, что его запрос был обработан должным образом.

Взгляните на другой GET запрос, на этот раз для одного автомобиля:

GET /cars/1 HTTP/1.1
Host: api.example.com

Этот HTTP-запрос запрашивает API для car 1. Вот ответ:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": 1,
    "make": "GMC",
    "model": "1500 Club Coupe",
    "year": 1998,
    "vin": "1D7RV1GTXAS806941",
    "color": "Red"
},

Этот ответ содержит один объект JSON с данными автомобиля. Поскольку это один объект, его не нужно упаковывать в список. Как и в последнем ответе, здесь также есть 200 OK код состояния.

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

Далее, ознакомьтесь с POST запросом на добавление нового автомобиля:

POST /cars HTTP/1.1
Host: api.example.com
Content-Type: application/json

{
    "make": "Nissan",
    "model": "240SX",
    "year": 1994,
    "vin": "1N6AD0CU5AC961553",
    "color": "Violet"
}

Этот POST запрос включает в себя JSON для нового автомобиля в запросе. Он устанавливает Content-Type заголовок application/json таким образом, чтобы API знал тип содержимого запроса. API создаст новый автомобиль из JSON.

Вот ответ:

HTTP/1.1 201 Created
Content-Type: application/json

{
    "id": 4,
    "make": "Nissan",
    "model": "240SX",
    "year": 1994,
    "vin": "1N6AD0CU5AC961553",
    "color": "Violet"
}

Этот ответ содержит 201 Created код состояния, сообщающий пользователю о создании нового ресурса. Обязательно используйте 201 Created вместо 200 OK для всех успешных POST запросов.

Этот ответ также включает копию нового автомобиля с id сгенерированным API. Важно отправить ответ id в ответе, чтобы пользователь мог снова изменить ресурс.

Примечание .Важно всегда отправлять копию ресурса обратно, когда пользователь создает его с POST помощью или изменяет его с PUT помощью или PATCH. Таким образом, пользователь может видеть внесенные им изменения.

Теперь взгляните на PUT запрос:

PUT /cars/4 HTTP/1.1
Host: api.example.com
Content-Type: application/json

{
    "make": "Buick",
    "model": "Lucerne",
    "year": 2006,
    "vin": "4T1BF3EK8AU335094",
    "color":"Maroon"
}

Этот запрос использует id данные предыдущего запроса для обновления автомобиля всеми новыми данными. Напомним, PUT что все поля ресурса обновляются новыми данными. Вот ответ:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": 4,
    "make": "Buick",
    "model": "Lucerne",
    "year": 2006,
    "vin": "4T1BF3EK8AU335094",
    "color":"Maroon"
}

Ответ включает копию car с новыми данными. Опять же, вы всегда хотите отправить обратно полный ресурс для PUT запроса. То же самое относится и к PATCH запросу:

PATCH /cars/4 HTTP/1.1
Host: api.example.com
Content-Type: application/json

{
    "vin": "VNKKTUD32FA050307",
    "color": "Green"
}

PATCH запросы обновляют только часть ресурса. В приведенном выше запросе поля vin и color будут обновлены новыми значениями. Вот ответ:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": 4,
    "make": "Buick",
    "model": "Lucerne",
    "year": 2006,
    "vin": "VNKKTUD32FA050307",
    "color": "Green"
}

Ответ содержит полную копию car. Как вы можете видеть, vincolor были обновлены только поля и.

Наконец, взгляните на то, как ваш REST API должен реагировать при получении DELETE запроса. Вот DELETE запрос на удаление car:

DELETE /cars/4 HTTP/1.1

Этот DELETE запрос сообщает API об удалении car с идентификатором 4. Вот ответ:

HTTP/1.1 204 No Content

Этот ответ включает только код состояния 204 No Content. Этот код состояния сообщает пользователю, что операция прошла успешно, но в ответе не было возвращено никакого содержимого. Это имеет смысл, так car как файл был удален. Нет причин отправлять его копию обратно в ответе.

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

Ответы На Ошибки Проектирования

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

Для начала взгляните на запрос ресурса, которого нет в API:

GET /motorcycles HTTP/1.1
Host: api.example.com

Здесь пользователь отправляет GET запрос /motorcycles, которого не существует. API отправляет обратно следующий ответ:

HTTP/1.1 404 Not Found
Content-Type: application/json
...

{
    "error": "The requested resource was not found."
}

Этот ответ включает 404 Not Found код состояния. Наряду с этим, ответ содержит объект JSON с описательным сообщением об ошибке. Предоставление описательного сообщения об ошибке предоставляет пользователю больше контекста для ошибки.

Теперь взгляните на ответ на ошибку, когда пользователь отправляет неверный запрос:

POST /cars HTTP/1.1
Host: api.example.com
Content-Type: application/json

{
    "make": "Nissan",
    "year": 1994,
    "color": "Violet"

Этот POST запрос содержит JSON, но он неправильно отформатирован. В конце не хватает закрывающей фигурной скобки (}). API не сможет обработать эти данные. Ответ на ошибку сообщает пользователю о проблеме:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
    "error": "This request was not properly formatted. Please send again."
}

Этот ответ включает в себя описательное сообщение об ошибке вместе с кодом 400 Bad Request состояния, сообщающим пользователю, что ему необходимо исправить запрос.

Есть несколько других способов, которыми запрос может быть неправильным, даже если он правильно отформатирован. В следующем примере пользователь отправляет POST запрос, но включает неподдерживаемый тип носителя:

POST /cars HTTP/1.1
Host: api.example.com
Content-Type: application/xml

<?xml version="1.0" encoding="UTF-8" ?>
<car>
    <make>Nissan</make>
    <model>240SX</model>
    <year>1994</year>
    <vin>1N6AD0CU5AC961553</vin>
    <color>Violet</color>
</car>

В этом запросе пользователь отправляет XML, но API поддерживает только JSON. API отвечает следующим образом:

HTTP/1.1 415 Unsupported Media Type
Content-Type: application/json

{
    "error": "The application/xml mediatype is not supported."
}

Этот ответ включает код 415 Unsupported Media Type состояния, указывающий, что POST запрос включал формат данных, который не поддерживается API. Этот код ошибки имеет смысл для данных, которые находятся в неправильном формате, но как насчет данных, которые недействительны даже при правильном формате?

В следующем примере пользователь отправляет POST запрос, но включает car данные, которые не соответствуют полям других данных:

POST /cars HTTP/1.1
Host: api.example.com
Content-Type: application/json

{
    "make": "Nissan",
    "model": "240SX",
    "topSpeed": 120
    "warrantyLength": 10
}

В этом запросе пользователь добавляет topSpeedwarrantyLength поля и в JSON. Эти поля не поддерживаются API, поэтому он выдает сообщение об ошибке:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json

{
    "error": "Request had invalid or missing data."
}

Этот ответ включает код 422 Unprocessable Entity состояния. Этот код состояния указывает на то, что с запросом не было никаких проблем, но данные были неверными. API REST должен проверять входящие данные. Если пользователь отправляет данные с запросом, то API должен проверить данные и сообщить пользователю о любых ошибках.

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

REST и Python: Инструменты торговли

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

Каждая страна будет иметь следующие поля:

  • name это название страны.
  • capital является столицей страны.
  • area это площадь страны в квадратных километрах.

Пол яnamecapital, и area хранят данные о конкретной стране где-то в мире.

В большинстве случаев данные, отправляемые из REST API, поступают из базы данных. Подключение к базе данных выходит за рамки данного руководства. В приведенных ниже примерах вы будете хранить свои данные в списке Python. Исключением из этого является пример платформы Django REST, которая запускается из базы данных SQLite, созданной Django.

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

Чтобы все было согласовано, вы будете использовать countries в качестве основной конечной точки все три платформы. Вы также будете использовать JSON в качестве формата данных для всех трех фреймворков.

Теперь, когда у вас есть предпосылки для API, вы можете перейти к следующему разделу, где вы рассмотрите API REST в Flask.

Колба

Flask-это микроструктура Python, используемая для создания веб-приложений и API-интерфейсов REST. Колба обеспечивает прочную основу для ваших приложений, оставляя за вами множество вариантов дизайна. Основная задача Flask-обрабатывать HTTP-запросы и направлять их в соответствующую функцию приложения.

Примечание: Код в этом разделе использует новый синтаксис Flask 2. Если вы используете более старую версию Flask, используйте @app.route("/countries")вместо @app.get("/countries")и @app.post("/countries").

Чтобы обрабатывать POST запросы в более старых версиях Flask, вам также необходимо добавить methods параметр в @app.route():

@app.route("/countries", methods=["POST"])

Этот маршрут обрабатывает POST запросы /countries в колбу 1.

Ниже приведен пример приложения Flask для REST API:

# app.py
from flask import Flask, request, jsonify

app = Flask(__name__)

countries = [
    {"id": 1, "name": "Thailand", "capital": "Bangkok", "area": 513120},
    {"id": 2, "name": "Australia", "capital": "Canberra", "area": 7617930},
    {"id": 3, "name": "Egypt", "capital": "Cairo", "area": 1010408},
]

def _find_next_id():
    return max(country["id"] for country in countries) + 1

@app.get("/countries")
def get_countries():
    return jsonify(countries)

@app.post("/countries")
def add_country():
    if request.is_json:
        country = request.get_json()
        country["id"] = _find_next_id()
        countries.append(country)
        return country, 201
    return {"error": "Request must be JSON"}, 415

Это приложение определяет конечную точку API /countries для управления списком стран. Он обрабатывает два разных вида запросов:

  1. GET /countries возвращает список countries.
  2. POST /countries добавляет новое country в список.

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

Вы можете попробовать это приложение, установив flask с pip:

$ python -m pip install flask

После flask установки сохраните код в файле под названием app.py. Чтобы запустить это приложение Flask, вам сначала нужно установить переменную среды, вызываемую FLASK_APP на app.py. Это сообщает Flask, какой файл содержит ваше приложение.

$ export FLASK_APP=app.py

Это значение устанавливается FLASK_APPapp.py в текущей оболочке. При желании вы можете установить FLASK_ENV значение development, которое переводит колбу в режим отладки:

$ export FLASK_ENV=development

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

Примечание: Вышеуказанные команды работают на macOS или Linux. Если вы используете это в Windows, то вам нужно установить FLASK_APP и FLASK_ENV, как это, в командной строке:

C:\> set FLASK_APP=app.py
C:\> set FLASK_ENV=development

Теперь FLASK_APP и FLASK_ENV устанавливаются внутри оболочки Windows.

Теперь, когда все переменные среды готовы, вы можете запустить сервер разработки Flask, позвонив flask run:

$ flask run
* Serving Flask app "app.py" (lazy loading)
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

При этом запускается сервер, на котором запущено приложение. Откройте свой браузер и перейдите в http://127.0.0.1:5000/countries раздел , и вы увидите следующий ответ:

[
    {
        "area": 513120,
        "capital": "Bangkok",
        "id": 1,
        "name": "Thailand"
    },
    {
        "area": 7617930,
        "capital": "Canberra",
        "id": 2,
        "name": "Australia"
    },
    {
        "area": 1010408,
        "capital": "Cairo",
        "id": 3,
        "name": "Egypt"
    }
]

Этот ответ JSON содержит три countries, определенные в начале app.py. Взгляните на следующий код, чтобы понять, как это работает:

@app.get("/countries")
def get_countries():
    return jsonify(countries)

Этот код использует @app.get() декоратор маршрута колбы для подключения GET запросов к функции в приложении. При доступе /countries Flask вызывает функцию оформления для обработки HTTP-запроса и возврата ответа.

В приведенном выше коде get_countries() берется countries список Python и преобразует его в JSON с jsonify() помощью . Этот JSON возвращается в ответе.

Примечание: В большинстве случаев вы можете просто вернуть словарь Python из функции Flask. Flask автоматически преобразует любой словарь Python в JSON. Вы можете увидеть это в действии с помощью функции ниже:

@app.get("/country")
def get_country():
    return countries[1]

В этом коде вы возвращаете второй словарь из countries. Flask преобразует этот словарь в JSON. Вот что вы увидите, когда запросите /country:

{
    "area": 7617930,
    "capital": "Canberra",
    "id": 2,
    "name": "Australia"
}

Это JSON — версия словаря, из которого вы вернулись get_country().

В get_countries(), вам нужно использовать jsonify(), потому что вы возвращаете список словарей, а не только один словарь. Flask не преобразует списки автоматически в JSON.

А теперь взгляните на add_country(). Эта функция обрабатывает POST запросы в /countries новую страну и позволяет добавлять ее в список. Он использует объект Flask request для получения информации о текущем HTTP-запросе:

@app.post("/countries")
def add_country():
    if request.is_json:
        country = request.get_json()
        country["id"] = _find_next_id()
        countries.append(country)
        return country, 201
    return {"error": "Request must be JSON"}, 415

Эта функция выполняет следующие операции:

  1. Используется request.is_json для проверки того, что запрос является JSON
  2. Создание нового country экземпляра с request.get_json()
  3. Нахождение следующего id и установка его на country
  4. Добавление нового country в countries
  5. Возвращаем country в ответе вместе с 201 Created кодом состояния
  6. Возврат сообщения об ошибке и 415 Unsupported Media Type кода состояния, если запрос не был JSON

add_country() также призывает _find_next_id() определить id для нового country:

def _find_next_id():
    return max(country["id"] for country in countries) + 1

Эта вспомогательная функция использует выражение генератора для выбора всех идентификаторов стран, а затем вызывает max() их, чтобы получить наибольшее значение. Он увеличивает это значение на 1, чтобы получить следующий идентификатор для использования.

Вы можете опробовать эту конечную точку в командной оболочке с помощью инструмента командной строки curl, который позволяет отправлять HTTP-запросы из командной строки. Здесь вы добавите новое country в список countries:

$ curl -i http://127.0.0.1:5000/countries \
-X POST \
-H 'Content-Type: application/json' \
-d '{"name":"Germany", "capital": "Berlin", "area": 357022}'

HTTP/1.0 201 CREATED
Content-Type: application/json
...

{
    "area": 357022,
    "capital": "Berlin",
    "id": 4,
    "name": "Germany"
}

Эта команда curl содержит некоторые параметры, которые полезно знать:

  • -X задает метод HTTP для запроса.
  • -H добавляет заголовок HTTP к запросу.
  • -d определяет данные запроса.

Если эти параметры установлены, curl отправляет данные JSON в POST запросе с Content-Type установленным заголовком application/json. API REST возвращает 201 CREATED вместе с JSON для country добавленного вами нового.

Примечание: В этом примере add_country() не содержится никакой проверки, подтверждающей, что JSON в запросе соответствует формату countries. Проверьте flask-ожидает-json, если вы хотите проверить формат JSON в Flask.

Вы можете использовать curl для отправки GET запроса /countries, чтобы подтвердить, что новое country было добавлено. Если вы не используете -X в своей команде curl, то GET по умолчанию она отправляет запрос:

$ curl -i http://127.0.0.1:5000/countries

HTTP/1.0 200 OK
Content-Type: application/json
...

[
    {
        "area": 513120,
        "capital": "Bangkok",
        "id": 1,
        "name": "Thailand"
    },
    {
        "area": 7617930,
        "capital": "Canberra",
        "id": 2,
        "name": "Australia"
    },
    {
        "area": 1010408,
        "capital": "Cairo",
        "id": 3,
        "name": "Egypt"
    },
    {
        "area": 357022,
        "capital": "Berlin",
        "id": 4,
        "name": "Germany"
    }
]

Это возвращает полный список стран в системе, с самой новой страной внизу.

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

Каркас отдыха Django

Еще одним популярным вариантом создания API REST является платформа Django REST framework. Django REST framework-это плагин Django, который добавляет функциональность REST API поверх существующего проекта Django.

Чтобы использовать платформу Django REST, вам нужен проект Django для работы. Если он у вас уже есть, вы можете применить шаблоны в этом разделе к своему проекту. В противном случае следуйте инструкциям, и вы создадите проект Django и добавите в него платформу Django REST.

Во-первых, установите Django и djangorestframework с pip:

$ python -m pip install Django djangorestframework

Это устанавливает Django и djangorestframework. Теперь вы можете использовать этот django-admin инструмент для создания нового проекта Django. Выполните следующую команду, чтобы начать свой проект:

$ django-admin startproject countryapi

Эта команда создает новую папку в вашем текущем каталоге под названием countryapi. В этой папке находятся все файлы, необходимые для запуска вашего проекта Django. Затем вы создадите новое приложение Django внутри своего проекта. Django разбивает функциональность проекта на приложения. Каждое приложение управляет отдельной частью проекта.

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

Чтобы создать приложение, измените каталоги на countryapi и выполните следующую команду:

$ python manage.py startapp countries

Это создаст новую countries папку внутри вашего проекта. Внутри этой папки находятся базовые файлы для этого приложения.

Теперь, когда вы создали приложение для работы, вам нужно рассказать об этом Django. Рядом countries с только что созданной папкой находится еще одна папка под названием countryapi. Эта папка содержит конфигурации и настройки для вашего проекта.

Примечание. Эта папка имеет то же имя, что и корневая папка, созданная Django при запуске django-admin startproject countryapi.

Откройте settings.py файл, который находится внутри countryapi папки. Добавьте следующие строки INSTALLED_APPS, чтобы рассказать Django о countries приложении и платформе Django REST:

# countryapi/settings.py
INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "rest_framework",
    "countries",
]

Вы добавили строку для countries приложения и rest_framework.

Возможно, вам интересно, зачем вам нужно добавлять rest_framework в список приложений. Вам нужно добавить его, потому что Django REST framework-это просто еще одно приложение Django. Плагины Django-это приложения Django, которые упаковываются и распространяются и которые может использовать любой желающий.

Следующим шагом является создание модели Django для определения полей ваших данных. Внутри countries приложения обновите models.py его следующим кодом:

# countries/models.py
from django.db import models

class Country(models.Model):
    name = models.CharField(max_length=100)
    capital = models.CharField(max_length=100)
    area = models.IntegerField(help_text="(in square kilometers)")

Этот код определяет Country модель. Django будет использовать эту модель для создания таблицы базы данных и столбцов для данных по странам.

Выполните следующие команды, чтобы Django обновил базу данных на основе этой модели:

$ python manage.py makemigrations
Migrations for 'countries':
  countries/migrations/0001_initial.py
    - Create model Country

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, countries, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  ...

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

Эта таблица начинается пустой, но было бы неплохо иметь некоторые исходные данные, чтобы вы могли протестировать фреймворк Django REST. Для этого вы собираетесь использовать приспособление Django для загрузки некоторых данных в базу данных.

Скопируйте и сохраните следующие данные JSON в файл с именем countries.json и сохраните его в countries каталоге:

[
    {
        "model": "countries.country",
        "pk": 1,
        "fields": {
            "name": "Thailand",
            "capital": "Bangkok",
            "area": 513120
        }
    },
    {
        "model": "countries.country",
        "pk": 2,
        "fields": {
            "name": "Australia",
            "capital": "Canberra",
            "area": 7617930
        }
    },
    {
        "model": "countries.country",
        "pk": 3,
        "fields": {
            "name": "Egypt",
            "capital": "Cairo",
            "area": 1010408
        }
    }
]

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

$ python manage.py loaddata countries.json
Installed 3 object(s) from 1 fixture(s)

Это добавляет три строки в базу данных.

Таким образом, ваше приложение Django полностью настроено и заполнено некоторыми данными. Теперь вы можете начать добавлять фреймворк Django REST в проект.

Платформа Django REST использует существующую модель Django и преобразует ее в JSON для API REST. Это делается с помощью стерилизаторов моделей. Стерилизатор моделей сообщает платформе Django REST, как преобразовать экземпляр модели в JSON и какие данные включить.

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

# countries/serializers.py
from rest_framework import serializers
from .models import Country

class CountrySerializer(serializers.ModelSerializer):
    class Meta:
        model = Country
        fields = ["id", "name", "capital", "area"]

Этот стерилизатор CountrySerializer, подклассы serializers.ModelSerializer для автоматической генерации содержимого JSON на основе полей модели Country. Если не указано иное, ModelSerializer подкласс будет включать все поля из модели Django в JSON. Вы можете изменить это поведение, установив fields список данных, которые вы хотите включить.

Как и Django, платформа Django REST использует представления для запроса данных из базы данных для отображения пользователю. Вместо того, чтобы писать представления REST API с нуля, вы можете подкласс класса Django REST framework ModelViewSet, который имеет представления по умолчанию для обычных операций REST API.

Примечание: Документация Django REST framework ссылается на эти представления как на действия.

Вот список действий, которые ModelViewSet предоставляет и их эквивалентные методы HTTP:

Метод HTTPЭкшенОписание
GET.list()Получите список стран.
GET.retrieve()Получите единую страну.
POST.create()Создайте новую страну.
PUT.update()Обновите страну.
PATCH.partial_update()Частично обновите страну.
DELETE.destroy()Удалите страну.

Как вы можете видеть, эти действия соответствуют стандартным методам HTTP, которые вы ожидаете в REST API. Вы можете переопределить эти действия в своем подклассе или добавить дополнительные действия в соответствии с требованиями вашего API.

Ниже приведен код для ModelViewSet называемого подкласса CountryViewSet. Этот класс создаст представления, необходимые для управления Country данными. Добавьте следующий код views.py в countries приложение:

# countries/views.py
from rest_framework import viewsets

from .models import Country
from .serializers import CountrySerializer

class CountryViewSet(viewsets.ModelViewSet):
    serializer_class = CountrySerializer
    queryset = Country.objects.all()

В этом классе serializer_class установлено значение CountrySerializer и querysetустановлено значение Country.objects.all(). Это указывает платформе Django REST, какой стерилизатор использовать и как запрашивать базу данных для этого конкретного набора представлений.

После создания представлений их необходимо сопоставить с соответствующими URL-адресами или конечными точками. Для этого платформа Django REST framework предоставляет a DefaultRouter, которая автоматически генерирует URL-адреса для a ModelViewSet.

Создайте urls.py файл в countries приложении и добавьте в него следующий код:

# countries/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter

from .views import CountryViewSet

router = DefaultRouter()
router.register(r"countries", CountryViewSet)

urlpatterns = [
    path("", include(router.urls))
]

Этот код создает DefaultRouter и регистрируется CountryViewSet под countries URL-адресом. Это приведет к размещению всех URL-адресов для CountryViewSet под /countries/.

Примечание: Платформа Django REST автоматически добавляет косую черту (/) в конец любых конечных точек, созданных DefaultRouter. Вы можете отключить это поведение следующим образом:

router = DefaultRouter(trailing_slash=False)

Это отключит прямую косую черту в конце конечных точек.

Наконец, вам необходимо обновить базовый urls.py файл проекта, чтобы включить все countries URL-адреса в проект. Обновите urls.py файл внутри countryapi папки следующим кодом:

# countryapi/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include("countries.urls")),
]

Это помещает все URL-адреса под /countries/. Теперь вы готовы опробовать свой REST API, поддерживаемый Django. Выполните следующую команду в корневом country api каталоге, чтобы запустить сервер разработки Django:

$ python manage.py runserver

Сервер разработки теперь запущен. Продолжайте и отправьте GET запрос /countries/, чтобы получить список всех стран в вашем проекте Django:

$ curl -i http://127.0.0.1:8000/countries/ -w '\n'

HTTP/1.1 200 OK
...

[
    {
        "id": 1,
        "name":"Thailand",
        "capital":"Bangkok",
        "area":513120
    },
    {
        "id": 2,
        "name":"Australia",
        "capital":"Canberra",
        "area":7617930
    },
    {
        "id": 3,
        "name":"Egypt",
        "capital":"Cairo",
        "area":1010408
    }
]

Платформа Django REST отправляет ответ JSON с тремя странами, которые вы добавили ранее. Приведенный выше ответ отформатирован для удобства чтения, поэтому ваш ответ будет выглядеть по-другому.

Созданный DefaultRouter вами в countries/urls.py предоставляет URL-адреса для запросов ко всем стандартным конечным точкам API:

  • GET /countries/
  • GET /countries/<country_id>/
  • POST /countries/
  • PUT /countries/<country_id>/
  • PATCH /countries/<country_id>/
  • DELETE /countries/<country_id>/

Вы можете опробовать еще несколько конечных точек ниже. Отправьте POST запрос на /countries/ создание нового Country в вашем проекте Django:

$ curl -i http://127.0.0.1:8000/countries/ \
-X POST \
-H 'Content-Type: application/json' \
-d '{"name":"Germany", "capital": "Berlin", "area": 357022}' \
-w '\n'

HTTP/1.1 201 Created
...

{
    "id":4,
    "name":"Germany",
    "capital":"Berlin",
    "area":357022
}

Это создает новый Country файл с JSON, который вы отправили в запросе. Платформа Django REST возвращает 201 Created код состояния и новый Country.

Примечание. По умолчанию ответ не содержит новой строки в конце. Это означает, что JSON может попасть в вашу командную строку. Приведенная выше команда curl включает -w '\n' в себя добавление символа новой строки после JSON, чтобы устранить эту проблему.

Вы можете просмотреть существующий Country, отправив запрос на GET /countries/<country_id>/с существующим id. Выполните следующую команду, чтобы получить первую Country:

$ curl -i http://127.0.0.1:8000/countries/1/ -w '\n'

HTTP/1.1 200 OK
...

{
    "id":1,
    "name":"Thailand",
    "capital":"Bangkok",
    "area":513120
}

Ответ содержит информацию для первого Country. Эти примеры касались только GET запросов и POST запросов. Не стесняйтесь опробовать PUTPATCH, и DELETE запросы самостоятельно, чтобы увидеть, как вы можете полностью управлять своей моделью с помощью REST API.

Как вы уже видели, платформа Django REST framework-отличный вариант для создания API REST, особенно если у вас есть существующий проект Django и вы хотите добавить API.

FastAPI

FastAPI — это веб-фреймворк Python, оптимизированный для создания API. Он использует подсказки типа Python и имеет встроенную поддержку асинхронных операций. FastAPI построен поверх Starlette и Pydantic и очень эффективен.

Ниже приведен пример API REST, построенного с помощью FastAPI:

# app.py
from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()

def _find_next_id():
    return max(country.country_id for country in countries) + 1

class Country(BaseModel):
    country_id: int = Field(default_factory=_find_next_id, alias="id")
    name: str
    capital: str
    area: int

countries = [
    Country(id=1, name="Thailand", capital="Bangkok", area=513120),
    Country(id=2, name="Australia", capital="Canberra", area=7617930),
    Country(id=3, name="Egypt", capital="Cairo", area=1010408),
]

@app.get("/countries")
async def get_countries():
    return countries

@app.post("/countries", status_code=201)
async def add_country(country: Country):
    countries.append(country)
    return country

Это приложение использует функции FastAPI для создания REST API для тех же country данных, которые вы видели в других примерах.

Вы можете попробовать это приложение, установив fastapi с pip:

$ python -m pip install fastapi

Вам также потребуется установить uvicorn[standard] сервер , который может запускать приложения FastAPI:

$ python -m pip install uvicorn[standard]

Если вы установили оба fastapi и uvicorn, затем сохраните приведенный выше код в файле под названием app.py. Выполните следующую команду для запуска сервера разработки:

$ uvicorn app:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

Сервер теперь запущен. Откройте браузер и перейдите в http://127.0.0.1:8000/countries раздел . Вы увидите, как FastAPI отреагирует на это:

[
    {
        "id": 1,
        "name":"Thailand",
        "capital":"Bangkok",
        "area":513120
    },
    {
        "id": 2,
        "name":"Australia",
        "capital":"Canberra",
        "area":7617930
    },
    {
        "id": 3,
        "name":"Egypt",
        "capital":"Cairo",
        "area":1010408
    }
]

FastAPI отвечает массивом JSON, содержащим список countries. Вы также можете добавить новую страну, отправив POST запрос по адресу /countries:

$ curl -i http://127.0.0.1:8000/countries \
-X POST \
-H 'Content-Type: application/json' \
-d '{"name":"Germany", "capital": "Berlin", "area": 357022}' \
-w '\n'

HTTP/1.1 201 Created
content-type: application/json
...

{"id":4,"name":"Germany","capital":"Berlin","area": 357022}

Вы добавили новую страну. Вы можете подтвердить это с помощью GET /countries:

$ curl -i http://127.0.0.1:8000/countries -w '\n'

HTTP/1.1 200 OK
content-type: application/json
...

[
    {
        "id":1,
        "name":"Thailand",
        "capital":"Bangkok",
        "area":513120,
    },
    {
        "id":2,
        "name":"Australia",
        "capital":"Canberra",
        "area":7617930
    },
    {
        "id":3,
        "name":"Egypt",
        "capital":"Cairo",
        "area":1010408
    },
    {
        "id":4,
        "name": "Germany",
        "capital": "Berlin",
        "area": 357022
    }
]

FastAPI возвращает список JSON, включающий новую страну, которую вы только что добавили.

Вы заметите, что приложение FastAPI похоже на приложение Flask. Как и Flask, FastAPI имеет специализированный набор функций. Он не пытается обрабатывать все аспекты разработки веб-приложений. Он предназначен для создания API с современными функциями Python.

Если вы посмотрите в верхней части app.py, то увидите класс Country, который называется «расширяется BaseModel«. Country Класс описывает структуру данных в REST API:

class Country(BaseModel):
    country_id: int = Field(default_factory=_find_next_id, alias="id")
    name: str
    capital: str
    area: int

Это пример модели Pydantic. Модели Pydantic предоставляют некоторые полезные функции в FastAPI. Они используют аннотации типа Python для применения типа данных для каждого поля в классе. Это позволяет FastAPI автоматически генерировать JSON с правильными типами данных для конечных точек API. Это также позволяет FastAPI проверять входящие JSON.

Полезно выделить первую строку, так как там многое происходит:

country_id: int = Field(default_factory=_find_next_id, alias="id")

В этой строке, как вы видите country_id, хранится целое число для идентификатора Country. Он использует Field функцию из Pydantic для изменения поведения country_id. В этом примере вы передаете Field аргументы ключевого default_factory слова и alias.

Первый аргумент, default_factory, имеет значение _find_next_id(). Этот аргумент указывает функцию, которая будет выполняться при каждом создании новой Country. Возвращаемое значение будет присвоено country_id.

Второй аргумент, alias, имеет значение id. Это говорит FastAPI выводить ключ "id"вместо "country_id"в JSON:

{
    "id":1,
    "name":"Thailand",
    "capital":"Bangkok",
    "area":513120,
},

Это alias также означает, что вы можете использовать id при создании нового Country. Вы можете увидеть это в countries списке:

countries = [
    Country(id=1, name="Thailand", capital="Bangkok", area=513120),
    Country(id=2, name="Australia", capital="Canberra", area=7617930),
    Country(id=3, name="Egypt", capital="Cairo", area=1010408),
]

Этот список содержит три экземпляра Country для начальных стран в API. Модели Pydantic предоставляют некоторые замечательные функции и позволяют FastAPI легко обрабатывать данные JSON.

Теперь взгляните на две функции API в этом приложении. Первый, get_countries(), возвращает список countries GET запросов на /countries:

@app.get("/countries")
async def get_countries():
    return countries

FastAPI автоматически создаст JSON на основе полей в модели Pydantic и установит правильный тип данных JSON из подсказок типа Python.

Модель Pydantic также предоставляет преимущества, когда вы делаете POST запрос на /countries. Вы можете видеть во второй функции API ниже, что параметр country имеет Country аннотацию:

@app.post("/countries", status_code=201)
async def add_country(country: Country):
    countries.append(country)
    return country

Эта аннотация типа указывает FastAPI на проверку входящего JSON Country. Если он не совпадает, то FastAPI вернет ошибку. Вы можете попробовать это, отправив запрос с помощью JSON, который не соответствует модели Pydantic:

$ curl -i http://127.0.0.1:8000/countries \
-X POST \
-H 'Content-Type: application/json' \
-d '{"name":"Germany", "capital": "Berlin"}' \
-w '\n'

HTTP/1.1 422 Unprocessable Entity
content-type: application/json
...

{
    "detail": [
        {
            "loc":["body","area"],
            "msg":"field required",
            "type":"value_error.missing"
        }
    ]
}

В JSON в этом запросе отсутствовало значение для area, поэтому FastAPI вернул ответ с кодом 422 Unprocessable Entity состояния, а также подробную информацию об ошибке. Эта проверка становится возможной благодаря модели Pydantic.

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

Вывод

API-интерфейсы REST есть везде. Знание того, как использовать Python для использования и создания API, позволяет вам работать с огромным объемом данных, предоставляемых веб-службами.

В этом уроке вы узнали, как:

  • Определите стиль архитектуры REST
  • Работа с методами HTTP и кодами состояния
  • Используется requests для получения и использования данных из внешнего API
  • Определите конечные точки, данные и ответы для API REST
  • Начните работу с инструментами Python для создания API REST

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