В Интернете доступно огромное количество данных. Многие веб-сервисы, такие как 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
и POST
, requests
обеспечивает поддержку всех других методов 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()
для изменения значения определенного поля в существующем todo
. PATCH
отличается от 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:
- Управление версиями URI
- Управление версиями HTTP-заголовка
- Управление версиями строк запроса
- Управление версиями типов носителей
Независимо от того, какую стратегию вы выберете, управление версиями вашего 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-запрос состоит из четырех частей:
GET
является типом метода HTTP./cars
является конечной точкой API.HTTP/1.1
является версией HTTP.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
для управления списком стран. Он обрабатывает два разных вида запросов:
GET /countries
возвращает списокcountries
.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
Эта функция выполняет следующие операции:
- Используется
request.is_json
для проверки того, что запрос является JSON - Создание нового
country
экземпляра сrequest.get_json()
- Нахождение следующего
id
и установка его наcountry
- Добавление нового
country
вcountries
- Возвращаем
country
в ответе вместе с201 Created
кодом состояния - Возврат сообщения об ошибке и
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
запросов. Не стесняйтесь опробовать PUT
, PATCH
, и 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 для своих приложений. Эти инструменты открывают двери для широкого спектра интересных приложений и сервисов, основанных на данных.