Руководство по созданию API-запросов в Python

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

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

Подходит ли Python для API?

Это может показаться странным вопросом, но, учитывая засилье в вебе Node.js и Ruby, вы можете подумать, что Python не так хорош для создания API-запросов. Но это не так. На самом деле Python тоже давно присутствует в вебе, особенно если принять во внимание его библиотеки Flask и Django.

Поскольку Python предоставляет мощные и доступные инструменты для работы с данными, имеет смысл также использовать его и для получения самих источников данных. Для этого и служат запросы к API. Давайте начнем с самой популярной библиотеки Python под названием Requests.

Библиотека Requests

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

pip install requests

Библиотеку также нужно импортировать:

import requests

Распространенные типы API-запросов в библиотеке Requests

Наиболее простой GET-запрос интуитивно понятен:

response = requests.get('https://example.com')

По аналогии с приведенным выше примером метода get, библиотека Requests предлагает методы для всех HTTP-действий, а именно: POST, PUT, DELETE, HEAD и OPTIONS.

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

response = requests.get('https://example.com', params={'name': 'Bearer'})

Переменная response содержит данные, возвращаемые API в качестве ответа на наш запрос. Есть три основных способа доступа к этим данным:

  • в виде текста, при помощи response.text,
  • в виде байт-кода, при помощи response.content,
  • в формате JSON, при помощи response.json().

Также можно получить сырые данные при помощи response.raw.

Помимо тела самого ответа, мы также можем получить доступ к коду состояния — при помощи response.status_code, к заголовкам — при помощи response.headers, и так далее. Полный список атрибутов и методов, доступных для Response, вы можете найти в документации requests.Response.

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

response = requests.get('https://example.com, headers={'example-header': 'Bearer'})

Здесь мы передаем в качестве аргумента заголовок в виде словаря Python.

Последний тип API-запроса, который мы сейчас рассмотрим — это полнофункциональный POST-запрос с аутентификацией. Этот пример объединит два предыдущих, здесь мы передадим в качестве аргументов и заголовок, и данные.

url = 'https://example.com'
headers = {'Authorization': 'Bearer example-auth-code'}
payload = {'name':'Mark', email: 'mark@bearer.sh'}

response = requests.post(url, headers=headers, data=payload)

Здесь мы отправляем данные из переменной payload в формате словаря Python. Для большинства современных API нам часто требуется отправлять данные в формате JSON. В следующем примере мы используем встроенный json-конвертер из библиотеки Requests.

url = 'https://example.com'
headers = {'Authorization': 'Bearer example-auth-code'}
payload = {'name':'Mark', email: 'mark@bearer.sh'}

response = requests.post(url, headers=headers, json=payload)

Это преобразует содержимое переменной payload в формат JSON, а также автоматически переведет в этот тип данных заголовки из переменной headers.

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

Библиотека aiohttp

Для выполнения асинхронных HTTP-запросов вам необходимо воспользоваться некоторыми новыми функциями Python 3. Хотя у библиотеки Requests есть различные дополнения и плагины для асинхронного программирования, одной из наиболее популярных библиотек для этого является библиотека aiohttp. Используя ее вместе с библиотекой acincio, мы можем эффективно исполнять асинхронные запросы. Код будет немного сложнее, но асинхронные запросы сами по себе предоставляют большую свободу действий.

Для начала установим библиотеку aiohttp:

pip install aiohttp

Распространенные типы API-запросов в библиотеке aiohttp

Как и раньше, начнем с GET-запроса. Для начала импортируем обе библиотеки и определим функцию main() как асинхронную.

import asyncio #  [1]
import aiohttp

async def main(): # [2]
    async with aiohttp.ClientSession() as session: # [3]
    async with session.get('http://example.com') as resp: # [4]
        response = await resp.read() # [5]
        print(response)

asyncio.run(main()) # [6]

В этом коде мы выполняем следующие шаги:

  1. Импортируем необходимые библиотеки.
  2. Определяем функцию main как асинхронную.
  3. Устанавливаем сессию ClientSession из aiohttp.
  4. Используем данную сессию для выполнения HTTP GET-запроса.
  5. Далее дожидаемся ответа и выводим его на экран.
  6. Наконец, используем метод run из библиотеки asyncio для запуска асинхронной функции main().

Если вы никогда раньше не работали с асинхронными методами в Python, это может показаться странным и сложным по сравнению с предыдущими примерами. Создатели библиотеки aiohttp рекомендуют устанавливать один сеанс для каждого приложения и открывать / закрывать соединения в этом сеансе. Чтобы сделать наши примеры самодостаточными, мы составили примеры в менее эффективном формате.

Далее давайте рассмотрим полнофункциональный POST-запрос с заголовками аутентификации, как мы сделали в примере для библиотеки Requests.

# ...

async def main():
    async with aiohttp.ClientSession() as session:
        async with session.post('http://example.com',
            headers={'Authorization':'Bearer 123456', 'Content-Type':'application/json'},
            json={'title':'Try Bearer'}) as resp: # [1]

            response = await resp.json() # [2]
            print(response)

asyncio.run(main())

Между этим примером и предыдущим есть несколько различий:

  1. В нашей сессии используется метод post, который передает заголовки и словари json вместе с URL-адресом.
  2. Мы используем встроенный в библиотеку метод json из класса resp для анализа возвращенных данных в формате json.

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

Некоторые дополнительные библиотеки

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

  • httpx: данная библиотека поддерживает как синхронные, так и асинхронные запросы. Она также использует API-интерфейс, совместимый с библиотекой Requests, что значительно упрощает переход между ними. В настоящее время библиотека находится в стадии бета-тестирования, но за ее развитием стоит последить.
  • httpcore: интересный вариант, если вы сами создаете библиотеку. Эта библиотека низкоуровневая, поэтому вы можете создавать на нем свои собственные абстракции. Но если вам не нужна именно низкоуровневая библиотека, то сами создатели не рекомендуют ее использовать.
  • urllib3: мы должны упомянуть urllib3 хотя бы потому, что это базовая библиотека, на которой построена библиотека Requests и многие другие очень известные библиотеки (например pip). Хотя urllib3 и менее удобна для пользователя, чем некоторые высокоуровневые библиотеки, она мощна и проверена на практике. Если по какой-то причине вам нужно что-то с меньшим количеством абстракций, чем в библиотеке Requests, urllib3 будет хорошим вариантом.

Прокрутить вверх