Как использовать веб-API в Python 3
В этой статье мы рассмотрим общий принцип взаимодействия с веб-API, используя Python, на примере Timeweb Cloud. Научимся получать информацию об аккаунте и добавлять SSH-ключи.
API — сокращение от Application Programming Interface (программный интерфейс приложения). Благодаря ему можно получить информацию от других программ / сервисов или автоматизировать рутинные действия, выполняемые в браузере.
Python — отличный выбор для работы с API по нескольким причинам:
- Во-первых, Python имеет большое количество библиотек и модулей, которые упрощают взаимодействие с API. Это позволяет легко выполнять HTTP-запросы, обрабатывать JSON и другие форматы данных.
- Во-вторых, Python известен своей простотой и читаемостью кода.
- В-третьих, Python популярен среди разработчиков, что означает наличие обширного сообщества и множества ресурсов для обучения и поддержки.
- И наконец, Python мультиплатформен, что означает, что вы можете разрабатывать и запускать приложения, использующие API, на разных операционных системах без больших изменений в коде.
Знакомство с веб-API Timeweb Cloud
Перед началом работы с любым API необходимо в первую очередь ознакомиться с его документацией. Это позволит узнать, какие функции и методы доступны, каким образом можно отправлять запросы (описание конечных точек), и какие коды ответов могут быть получены от API.
Обратившись к документации веб-API Timeweb Cloud, мы увидим, что все запросы выполняются с использованием HTTP-протокола и все ответы возвращаются в виде JSON, поддерживаются методы GET, POST, PUT, DELETE и PATCH.
Также в документации описаны возможные коды ответов. Коды ответов можно разделить на 3 группы:
- 2** — означает «успех». Запрос был выполнен корректно, в теле ответа содержится информация, если это было предусмотрено.
- 4** - означает, что в запросе допущена ошибка. Ошибка не связана с работой сервера, а возникает именно из-за некорректно выполненного запроса.
- 5** — ошибка сервера. Ошибка может возникнуть, если на сервере возникли какие-то проблемы. При возникновении ошибки стоит подождать некоторое время. Если ошибка не пропадает, стоит обратиться в поддержку с подробным описанием того, как воспроизвести проблему.
Отдельно стоит отметить 429 код ответа — он может возникнуть, если было выполнено более 20 запросов в секунду.
Стоит упомянуть, что как и у многих других сервисов, у Timeweb Cloud есть «оболочка» над веб-API — Timeweb Cloud CLI. Этот инструмент позволяет создавать и настраивать облачные серверы, хранилища данных и прочие облачных ресурсы средствами командной строки.
Подготовка к работе
Приступим к созданию проекта. Создайте директорию TWAPI
:
mkdir TWAPI
Перейдите в новый каталог:
cd ./TWAPI
Создайте виртуальное окружение Python:
python3 -m venv venv
Виртуальное окружение в Python используется для изоляции проектов и их зависимостей, обеспечивая чистоту кода и избегая конфликтов между библиотеками разных версий.
Активируйте виртуальное окружение:
source ./venv/bin/activate
Установим библиотеку requests
:
pip install requests
Перед началом работы с веб-API, нам необходимо получить токен. Токен — это специальный ключ, который используется для аутентификации и авторизации пользователя при доступе к ресурсам. Он обеспечивает безопасность, контроль доступа и идентификацию запросов, позволяя серверу определить, какие действия и данные может выполнять или получать конкретный пользователь или приложение.
Для создания токена переходим во вкладку «API и Terrafrom» в панели управления аккаунтом.
Нажимаем «Создать». Вводим имя токена, при необходимости меняем срок действия токена. Галочку с «Удалять сервисы по API без кода в Телеграме» можно не снимать.
После нажатия на кнопку «Выпустить» появится возможность скопировать токен. На данном этапе его стоит сохранить в каком-либо файле, так как после закрытия окна увидеть токен вновь не удастся. Временно сохранить токен можно в файл token.txt
, выполнив команду в директории проекта:
echo 'скопированный_токен' > token.txt
ВАЖНО: Если стороннее лицо завладеет вашим токеном, ему будут доступны любые операции с вашим аккаунтом. Поэтому, если вы собираетесь загружать проект, например, в публичный репозиторий github, файл
token.txt
необходимо добавить в.gitignore
.
Выполнив настройку среды и получив токен для работы с веб-API, создадим файл main.py
в директории проекта. В файле выполним подключение библиотек requests
и json
:
import requests
import json
Эти инструкции подключают библиотеки, облегчающие выполнение HTTP-запросов к серверу и работу с форматом JSON.
Следующим шагом объявим необходимые переменные:
token = 'токен_полученный_ранее'
api_url_base = 'https://api.timeweb.cloud/api/v1/'
ВАЖНО: В «боевых» проектах не стоит указывать токен в коде скрипта. Чувствительные данные не должны храниться в коде скрипта, так как это создает риск утечки данных в случае доступа к исходному коду или его случайной публикации. Для подключения токена лучше использовать переменные окружения. В рамках этой статьи токен будет указан в коде скрипта для упрощения демонстрации.
Переменная api_url_base
хранит в себе URl, одинаковый для всех конечных точек API.
Далее настроим HTTP-заголовки, следуя документации:
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {token}'
}
Заголовок Content-Type
указывает серверу на то, что в теле запроса передаются данные в формате JSON. Заголовок Authorization
должен содержать в себе токен. Его можно было бы указать строкой в заголовке, но тогда код становится нечитаемым и неподдерживаемым.
Полный листинг main.py
:
import requests
import json
token = 'токен_полученный_ранее'
api_url_base = 'https://api.timeweb.cloud/api/v1/'
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {token}'
}
На этом подготовительный этап завершен, и мы можем приступить к выполнению запросов.
Получение информации о балансе аккаунта
Обратимся к документации и увидим, что для получения платежной информации необходимо отправить GET-запрос к https://api.timeweb.cloud/api/v1/account/finances
. Из документации также узнаем, что при корректном запросе код ответа будет 200.
Реализуем функцию для получения платежной информации аккаунта:
def get_finances_info():
api_url = f'{api_url_base}account/finances'
response = requests.get(api_url, headers=headers)
if response.status_code == 200:
print('Платежная информация:')
for key, value in json.loads(response.content.decode('utf-8'))['finances'].items():
print(key, value)
else:
print (f'Ошибка {response.status_code}')
Распишем подробнее:
- В
api_url
при помощи f-строк мы объединилиapi_url_base
, объявленную ранее, сaccount/finances
. В результате мы получили путь к конечной точке API. - Далее, в переменную
response
мы сохраняем результат выполнения GET-запроса. При выполнении запроса также были переданы заголовки, сохраненные в переменнойheaders
. - При помощи конструкции
if response.status_code == 200:
проверяем код ответа, и если он равен 200 (код состояния, который мы должны получить при успешном обращении), выводим строку«Платежная информация»:
. - Строка
json.loads(response.content.decode('utf-8'))['finances']
декодирует JSON-ответ от сервера (response.content
) из байтового формата в текстовый формат с кодировкой UTF-8, а затем извлекает словарь с ключом'finances'
из этого JSON-ответа. - Далее, с помощью цикла
for key, value in ...
перебираются элементы этого словаря и выводятся на экран ключи и соответствующие им значения. - В случае, если код состояния ответа не равен 200, выполняется блок
else
, и на экран выводится сообщение об ошибке, содержащее код состояния ответа.
Вызовем нашу функцию, добавив в конце main.py
get_finances_info()
Итоговый листинг main.py
:
import requests
import json
token = 'токен_полученный_ранее'
api_url_base = 'https://api.timeweb.cloud/api/v1/'
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {token}'
}
def get_finances_info():
api_url = f'{api_url_base}account/finances'
response = requests.get(api_url, headers=headers)
if response.status_code == 200:
print('Платежная информация:')
for key, value in json.loads(response.content.decode('utf-8'))['finances'].items():
print(key, value)
else:
print (f'Ошибка {response.status_code}')
get_finances_info()
Запустим наш код:
python3 main.py
В результате выполнения скрипта в терминале получим вывод:
Платежная информация:
balance 149.49
currency RUB
discount_end_date_at None
discount_percent 0
hourly_cost 0
hourly_fee 0
monthly_cost 0
monthly_fee 0
total_paid 767
hours_left None
autopay_card_info None
Добавление SSH-ключа в панель управления аккаунтом
В следующем примере опишем добавление SSH-ключа в панель управления при помощи веб-API. Вновь обращаемся к документации.
Видим, что добавление выполняется при помощи POST-запроса к конечной точке https://api.timeweb.cloud/api/v1/ssh-keys
. В теле запроса необходимо передать сам ключ, имя и параметр is_default
. При успешном добавлении возвращается код состояния 201.
Приступим к написанию функции:
def add_ssh_key():
api_url = f'{api_url_base}ssh-keys'
ssh_key_path = '/home/user/.ssh/id_rsa.pub'
try:
with open(ssh_key_path, 'r') as file:
ssh_key = file.read()
data = {
'body': ssh_key,
'is_default': False,
'name': 'My SSH key'
}
json_data = json.dumps(data)
response = requests.post(api_url, headers=headers, data=json_data)
if response.status_code == 201:
print('Ключ успешно добавлен! \nДанные ключа:')
for key, value in json.loads(response.content.decode('utf-8'))['ssh_key'].items():
print(key, value)
else:
print(f'Возникла ошибка {response.status_code}')
except FileNotFoundError:
print(f'Файл {ssh_key_path} не найден.')
except Exception as e:
print(f'Произошла ошибка: {str(e)}')
add_ssh_key()
Здесь:
- В переменной
ssh_key_path
указываем путь к SSH-ключу (если у вас нет ключа, сгенерировать его можно командойssh-keygen -t rsa
). - В блоке
try
выполняются следующие действия:- Открывается файл SSH-ключа в режиме чтения;
- Считывается содержимое файла в переменную
ssh_key
; - Создается словарь data, который содержит сам ключ, флаг
is_default
и имя ключа; - Данные преобразуются в JSON-формат с помощью
json.dumps()
; - Выполняется HTTP POST-запрос к API с указанием заголовков и JSON-данных;
- Если ответ имеет статус код 201 (Created), то выводится сообщение об успешном добавлении и данные о ключе;
- В противном случае выводится сообщение об ошибке с указанием статус кода;
- В блоке
except
обрабатываются исключения, такие какFileNotFoundError
(если файл с ключом не найден) и общие исключенияException
, выводя соответствующие сообщения об ошибках. - Вызываем функцию при помощи
add_ssh_key()
.
Полный листинг main.py
(код из этого раздела не связан с функцией, созданной в предыщем разделе, поэтому в листинге не указан. Вызов get_finances_info()
из прошлой главы можно закомментировать, добавив #
перед вызовом):
import requests
import json
token = 'токен_полученный_ранее'
api_url_base = 'https://api.timeweb.cloud/api/v1/'
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {token}'
}
def add_ssh_key():
api_url = f'{api_url_base}ssh-keys'
ssh_key_path = '/home/user/.ssh/id_rsa.pub'
try:
with open(ssh_key_path, 'r') as file:
ssh_key = file.read()
data = {
'body': ssh_key,
'is_default': False,
'name': 'My SSH key'
}
json_data = json.dumps(data)
response = requests.post(api_url, headers=headers, data=json_data)
if response.status_code == 201:
print('Ключ успешно добавлен! \nДанные ключа:')
for key, value in json.loads(response.content.decode('utf-8'))['ssh_key'].items():
print(key, value)
else:
print(f'Возникла ошибка {response.status_code}')
except FileNotFoundError:
print(f'Файл {ssh_key_path} не найден.')
except Exception as e:
print(f'Произошла ошибка: {str(e)}')
add_ssh_key()
Запускаем скрипт командой python3 main.py
. В терминале видим, что ключ успешно добавлен, также получаем информацию о добавленном ключе:
Ключ успешно добавлен!
Данные ключа:
id 111235
body ssh-rsa "тут указан ключ"
created_at 2023-09-21T00:45:00.000Z
expired_at None
is_default False
name My SSH key
used_by []
В панели управления переходим в раздел «SSH-ключи» и видим, что ключ действительно добавлен:
Изменение имени SSH-ключа
Рассмотрим еще один метод API, который использует PATCH для изменения имени SSH-ключа. В этом примере нам понадобится id
добавленного ранее ключа, который мы получили в результате выполнения прошлой функции.
def change_ssh_key_name(key_id):
api_url = f'{api_url_base}ssh-keys/{key_id}'
data = {
'name': 'Changed Name'
}
json_data = json.dumps(data)
response = requests.patch(api_url, headers=headers, data=json_data)
if response.status_code == 200:
print('Имя успешно изменено! \nДанные ключа:')
for key, value in json.loads(response.content.decode('utf-8'))['ssh_key'].items():
print(key, value)
else:
print(f'Возникла ошибка {response.status_code}')
change_ssh_key_name(111235)
В этом примере мы создаем функцию change_ssh_key_name
, принимающую параметр key_id
, значение которого используется при формировании api_url
. Метод PATCH подразумевает частичное обновление информации, поэтому в словаре data
мы не указываем все параметры, что использовались при добавлении ключа, а только те, что хотим изменить.
При запуске скрипта мы получим подобный вывод:
Имя успешно изменено!
Данные ключа:
id 111235
body ssh-rsa "тут указан ключ"
created_at 2023-09-21T02:08:39.000Z
expired_at None
is_default False
name Changed Name
used_by []
Откроем раздел «SSH-ключи» и убедимся, что имя действительно изменено:
Заключение
В этом руководстве на примере взаимодействия с веб-API Timeweb Cloud мы рассмотрели, как при помощи Python можно работать с API. Используя примеры из статьи, вам не составит труда переписать функции для выполнения запросов к другим конечным точкам, описанных в документации. Также мы описали общий алгоритм, благодаря которому работа с API Timeweb Cloud или других сервисов не вызовет у вас проблем.
- Исследование документации:
- Первым шагом является поиск документации по API нужного сервиса. Это может быть официальная документация на веб-сайте провайдера или другие ресурсы, предоставляющие информацию о взаимодействии с API.
- Ознакомьтесь с основами взаимодействия, включая формат запросов и ответов, доступные методы и ожидаемые данные.
- Аутентификация:
- Если для работы с API требуется аутентификация, получите необходимые учетные данные или токен.
- Создание запросов:
- Используя данные из документации, создайте HTTP-запросы.
- Укажите необходимые параметры запроса: метод (GET, POST, PUT, DELETE, PATCH), заголовки, тело запроса (если необходимо)
- Обработка ошибок:
- Предусмотрите обработку ошибок. Это может включать в себя проверку статус-кодов ответов (например, 200 - успешно, 4xx - клиентская ошибка, 5xx - серверная ошибка) и обработку исключений.