Аннотация. В статье описываются общие принципы взаимодействия при работе с 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.

Литература

  1. Qt 5.3. Профессиональное программирование на C++, Макс Шлее, 2015, 928 с.