Аннотация. В статье описываются общие принципы взаимодействия при работе с API, а также пошаговая реализация создания класса отправки, приёма и обработки запросов на языке C++ с использованием библиотек Qt. Предложенное решение позволяет с минимальными временными затратами создать кроссплатформенный универсальный метод взаимодействия с серверов API системы «Яндекс.Директ», для получения данных для модуля прогнозирования результата и помощи принятия решения на основе статистики.
Ключевые слова. Программирование HTTP запросов, Qt Creator; работа с API, прогнозирование результата.
Введение.
В современном мире практически все вычисления переносятся в облачные сервисы, а за персональными компьютерами остаются функции обработки запросов и взаимодействие с пользователями. Для того, чтобы передавать данные для вычисления и получать результат, был разработан стандарт взаимодействия API, который позволяет удалено работать с удаленным сервером или облачным сервисом по принципу отправки, получения и обработки API запросов. Одной из распространённых проблем в данной системе является реализация клиент-сервер взаимодействия на языке C++. Ниже представлена готовый модуль реализации отправки и приёма данных по API на примере работы с API системы контекстной рекламы «Яндекс.Директ».
Описание работы с API
При работе с API взаимодействие делиться на работу двух участников: сервера и клиента. Сервер предоставляет доступ к методам API, обрабатывает методы и возвращает ответ. Клиент формирует запрос на сервер, отправляет запрос, получает ответ и обрабатывает ответ для дальнейшей работы над полученной информацией.
Сервер API системы «Яндекс.Директ» работает по средствам POST запросов. Запрос отправляется на сервер, где поэтапно происходит его обработка: определение типа запроса, проверка доступа и последующая авторизация в системе, обработка запроса, проверка запроса на достоверность данных, формирование ответа или ошибки, отправка ответа клиенту.
Для отправки запроса на сервер клиенту необходимо иметь токен доступа, который будет однозначно определять программу с которой взаимодействует система и логин клиента отправителя. Подобный токен при работе с «Яндекс.Директ» можно получить вручную или по средствам OAuth.
После получение токена необходимо сформировать запрос, который состоит из названия метода и его параметров. Метод может не содержать параметров. Все методы документированы на страницы технической документации API системы «Яндекс.Директ».
Помимо токена и метода, запрос должен содержать заголовок, который является постоянным для всех запросов к системе, а так же язык взаимодействия, на котором будут выданы результирующие данные.
Все данные упаковываются в универсальный контейнер JSON документа и вместе с параметрами запроса отправляются на сервер API. Каждый из этих процессов необходимо рассмотреть отдельно.
Формирование данных для отправки
Для формирования данных необходимо создать JSON документ. JSON — это универсальный язык описания данных, который имеет структуру схожую с JavaScript. Для работы с данными в формате JSON удобнее всего использовать библиотеки, которые входят в состав используемой среды разработки Qt Creator, а именно QJsonDocument, QJsonArray, QJsonObject, QJsonValue. Каждая из библиотек позволяет создать экземпляр и одного объекта из 4 основных типов JSON, а так же предоставляет удобный интерфейс для работы с данными внутри каждого из них.
Основным элементом, который будет в последующем отправлен на сервер является JSON Document. Он формируется из набора JSON Object. Каждый JSON Object это пара «ключ» — «значение». При этом значение может быть как ещё одним объектом, так и массивом объектов. Для работы с массивами используются JSON Array.
Для подготовки запроса создается метод, внутри которого поэтапно формируется JSON документ. Т.к. документ является готовой к отправке формой, все данные создаются в JSON объекте.
QJsonDocument jResultDocument;
QJsonObject jRequest;
jRequest.insert("locale", yaApiLocale);
jRequest.insert("token", token);
jRequest.insert("method", method);
Таким образом указывается метод работы, язык и токен доступа. Следующим шагом будет формирование параметра запроса. Для этого используется ключ param. Данный ключ является обязательным независимо от налаичия иили отсуствия параметров у выбранного метода работы. Такой подход сохраняет обратную совместимость при работе с запросами, а также позволяет добавить универсальную строчку:
jRequest.insert("param«, params);
Таким образом весь запрос был собран в один объект класса QJsonObject. Для того, чтобы данный запрос можно было отправить его необходимо преобразовать в доекмент. Это реализуется с помощью готового метода путём добавления объекта к пустому документу:
jResultDocument.setObject(jRequest);
Подготовка запроса для отправки
После подготовки данных необходимо сформировать запрос. Запрос должен иметь заранее определённый тип, заголовок и содержание. Содержание уже сформировано и упаковано в JSON документ. Тип запросов, с которыми работает сервер API «Яндекс.Директ» — POST запросы отправленные по протоколу HTTPS. Заголовок запроса является постоянным и должен соответствовать:
POST /json-api/v4 HTTP/1.1
Host: api-sandbox.direct.yandex.ru/v4/json/
Content-Type: text/plain; charset=UTF-8
Первые две строки будут сформированы автоматически: они отвечают за адрес сервера API. Третья строка определяет тип содержимого запроса. Для того, чтобы его определить, необходимо создать объект запроса. Это реализуется с помощью готового класса QNetworkRequest. Таким образом создаётся объект, добавляется заголовок и указывается адрес отправки запроса:
QNetworkRequest request;
request.setRawHeader(QByteArray("Content-Type"),QByteArray("text/plain; charset=UTF-8″));
request.setUrl(QUrl("https://api.direct.yandex.ru/live/v4/json/«));
Обработка отправки запроса и приёма ответа
Чтобы отправить запрос, дождаться ответа и его обработать необходим модуль QNetworkAccessManager. Класс автоматически следит за состоянием отправленого запроса и позволит определить, если соединение с сервером было потеряно. Для того, чтобы дождаться ответ объект менеджера должен находится в не метода отправки запроса. При поступлении ответа будет создан сигнал и вызван соответствующий метод обработки ответа. Поэтому правильной реализацией было бы передача указателя на внешний объект менеджера в метод отправки ответа, а в самом методе реализована только отправка запроса:
manager->post(request, QString(jResultDocument.toJson()).toUtf8());
Обработка ответа
Метод обработки ответа на входе должен получить объект класса QNetworkReply.
Для того, чтобы считать полученный ответ необходимо создать объект строкго типа QString и передать в него данные потока «ответ»:
QString replyText = reply->readAll();
Если строка окажется пустой, то ответ от сервера не получен, из чего следует отсутствие связи с сервером.
Объявление методов и создание сигнал-слот связи
Последним шагом необходимо объявить методы, создать метод обработки запроса и создать сигнал-слот связь для обработки ответа. Для этого необходимо в файле заголовков добавить следующие объявления:
public:
void postYaDirectAPI(QNetworkAccessManager *manager, const QString method, const QStringList params);
public slots:
void yaDirectApiReply(QNetworkReply *reply);
Также в конструктор класса добавить метод сопоставления ответа от сервера со слотом обработки ответа:
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager,SIGNAL(finished(QNetworkReply*)),
this,SLOT(yaDirectApiReply(QNetworkReply*)));
Выводы
Таким образом будет реализован класс отправки, приёма и обработки ответа от сервера API «Яндекс.Директ». При этом при реализации не потребуется низко-уровнего программирования взаимодействий с сервером, а реализованное решение поставленной задачи будет работать вне зависимости от платформы, на которой запускается: OS Windows, OS X, *nix.
Литература
- Qt 5.3. Профессиональное программирование на C++, Макс Шлее, 2015, 928 с.