Как составить json запрос

Время на прочтение
8 мин

Количество просмотров 301K

Эта памятка писалась для внутренних нужд (открыть глаза менее опытным в вебе коллегам). Но, т.к. я насмотрелся велосипедов от довольно уважаемых, казалось бы, контор, — выкладываю на хабр. Мне кажется, многим будет полезно.

Зачем

Надеюсь, читающий уже понимает, зачем ему вообще нужен именно REST api, а не какой-нибудь монстр типа SOAP. Вопрос в том, зачем соблюдать какие-то стандарты и практики, если браузеры вроде бы позволяют делать что хочешь.

  • Стандарт HTTP это стандарт. Его несоблюдение вредно для кармы и ведёт к постоянным проблемам с безопасностью, кэшированием и прочими “закидонами” браузеров, которые совсем не закидоны, а просто следование стандарту.
  • Велосипеды со всякими {error: "message","result":...} невозможно нормально тестировать и отлаживать
  • Поддержка большим количеством готовых клиентских библиотек на все случаи жизни. Те, кто будет вашим api пользоваться, скажут большое человеческое спасибо.
  • Поддержка автоматизированного интеграционного тестирования. Когда сервер на любые запросы отдаёт 200 ОК — ну, это такое себе развлечение.

Структура запросов и ответов

Любой http-запрос начинается со строки

METHOD URI

где METHOD — это метод доступа (GET, PUT и т.д.), а URI — адрес запрашиваемого ресурса.

В начале запроса идут заголовки — просто текстовые строки вида key: value
Затем передаётся пустая строка, означающая конец секции заголовков, и затем — тело запроса, если оно есть.

В ответе сначала передаётся строка с версией http, кодом и строковым статусом ответа (например HTTP/1.1 200 OK), далее текстовые заголовки ответа, потом пустая строка, потом тело ответа.

Тут вроде всё просто.

Кодирование запросов и ответов

Кодировка для всех и запросов, и ответов — UTF-8 и только UTF-8, т.к. некоторые, кхм, “браузеры” имеют привычку игнорировать содержимое заголовка charset.

Использование кодов символов и html-сущностей не допускается, т.е. режим JSON_UNESCAPED_UNICODE обязателен. Не все клиенты знают всю таблицу html сущностей (типа каких-нибудь ù ), да и при чём тут html. Не все клиенты готовы/хотят заниматься перекодированием uXXXX; и &#XX;. Плюс возможны “весёлые” ситуации с избыточным экранированием или пропаданием слэшей и амперсандов.

Все данные, кроме URI и двоичных файлов, передаются в формате JSON. Обратите внимание, что далеко не всякий валидный javascript код является валидным JSON.
В частности, для строк используются только двойные кавычки. Одинарные кавычки в json-данных, хотя и допустимы в “обычном” javascript, могут вызвать непредсказуемые плохо отлавливаемые баги.

В запросах обязательно указывается заголовок

Accept: application/json, */*; q=0.01

Вызовы к API отличаются от прочих вызовов (например, обычной загрузки html страницы по данному URI) именно по наличию application/json в Accept.

Сама строка Accept формируется браузером/клиентом и может немного отличаться от браузера к браузеру, например, наличием и других форматов типа text/javascript, поэтому нужно проверять не равенство, а именно вхождение “application/json”.

В ответах 2хх с непустым телом обязательно наличие заголовка ответа

Content-Type: application/json; charset=UTF-8

При наличии тела запроса также обязателен заголовок запроса

Content-Type: application/json; charset=UTF-8

либо, при загрузке файлов,

Content-Type: multipart/form-data

и далее, в первой части

-----------------
Content-Type: application/json; charset=UTF-8
Content-Disposition: form-data; name="data"

после чего для каждого файла

-----------------
Content-Type: image/jpeg
Content-Disposition: form-data; name="avatar"; filename="user.jpg"

Если вы используете защиту от CSRF (а лучше бы вам её использовать), то удобнее передавать CSRF-токен в отдельном заголовке (типа X-CSRF-Token) для всех запросов, а не внедрять вручную в каждый запрос. Хранить CSRF токен в куках плохо по той причине, что куки можно украсть, в чём собственно и состоит суть CSRF атаки.

Структура URI

Нагородить можно всякое, но лучшая практика — чтобы все URI имели вид

/:entity[/:id][/?:params]

ну, или если у вас api лежит в какой-то папке,

/api/:entity[/:id][/?:params]

Здесь:

  • entity — название сущности, например, класса или таблицы/представления в БД. Примеры: users, dictionary
  • id opt. — первичный ключ объекта. Если первичный ключ составной, то части указываются через слэш. Примеры: /users/10, /dictionary/ru/apptitle
  • params opt. — дополнительные параметры выборки для списочных запросов (фильтрация, сортировка, паджинация и пр.). Форматируются по правилам HTTP GET параметров (функции encodeURIComponent и пр.)

Для разбора части URI до знака вопроса можно использовать регулярку

#^/(<entity>([a-z]-_)+)/?(<id>([a-z][A-Z][0-9]-_/)*)?$#

Ведущий слэш обязателен, т.к. неизвестно, с какого URL будет осуществлён запрос.

Методы HTTP

GET /:entity/:idgetById

В случае успеха сервер возвращает 200 OK с полями объекта в формате JSON в теле ответа (без дополнительного оборачивания в какой-либо объект)

В случае, если объект с такими id не существует, сервер возвращает 404 Not Found

В ответе обязательно должны быть заголовки, касающиеся политики кэширования, т.к. браузеры активно кешируют GET и HEAD запросы. При остутствии какой-либо политики управления кэшем должно быть:

Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache

GET /:entity[?param1=...&param2=...] — списочный get

Простой случай: в случае успеха сервер возвращает 200 OK с массивом объектов в формате JSON в теле ответа (т.е. ответ начинается с [ и заканчивается ]).

Если массив получился пустой, всё равно вовзращается 200 OK с пустым масивом [] в теле ответа.

Более сложный вариант: возвращается объект, в одном из полей которого — искомый массив. В остальных полях — данные о пагинации, фильтры, счётчики и пр. Только держите это консистентным по всем api.

HEAD /:entity[/:id] — запрос заголовков

Полный аналог GET с таким же URI, но не возвращает тело ответа, а только HTTP-заголовки.

Реализация поддержки HEAD запросов веб-сервером обязательна.

Активно используется браузерами в качестве автоматических pre-flight запросов перед выполнением потенциально опасных, по их мнению, операций. Например, браузер Chrome активно кидается head-запросами для получения политик CORS при кросс-доменных операциях (виджеты и пр). При этом ошибка обработки такого head-запроса приведёт к тому, что основной запрос вообще не будет выполнен браузером.

Может использоваться для проверки существования объекта без его передачи (например, для больших объектов типа мультимедиа-файлов).

POST /:entity — создаёт новый объект типа :entity

В теле запроса должны быть перечислены поля объекта в формате JSON без дополнительного заворачивания, т.е. {"field1":"value","field2":10}

В случае успеха сервер должен возвращать 201 Created с пустым телом, но с дополнительным заголовком

Location: /:entity/:new_id

указывающим на месторасположение созданного объекта.

Возвращать тело ответа чаще всего не требуется, так как у клиента есть все необходимые данные, а id созданного объекта он может получить из Location.

Также метод POST используется для удалённого вызова процедур (RPC), в этом случае ответ будет иметь статус 200 OK и результаты в теле. Вообще смешивать REST и RPC в одном api — идея сомнительная, но всякое бывает.

Единственный неидемпотентный некешируемый метод, т.е. повтор двух одинаковых POST запросов создаст два одинаковых объекта.

PUT /:entity/:id — изменяет объект целиком

В запросе должны содержаться все поля изменяемого объекта в формате JSON.

В случае успеха должен возвращать 204 No Data с пустым телом, т.к. у клиента есть все необходимые данные.

Идемпотентный запрос, т.е. повторный PUT с таким же телом не приводит к каким-либо изменениям в БД.

PATCH /:entity/:id — изменяет отдельные поля объекта

В запросе должны быть перечислены только поля, подлежащие изменению.

В случае успеха возвращает 200 OK с телом, аналогичным запросу getById, со всеми полями изменённого объекта.

Используется с осторожностью, т.к. два параллельных PATCH от двух разных клиентов могут привести объект в невалидное состояние.

Идемпотентный запрос.

DELETE /:entity/:id — удаляет объект, если он существует.

В случае успеха возвращает 204 No Data с пустым телом, т.к. возвращать уже нечего.

Идемпотентный запрос, т.е. повторный DELETE с таким же адресом не приводит к ошибке 404.

OPTIONS /:entity[/:id]

Получает список методов, доступных по данному URI.

Сервер должен ответить 200 OK с дополнительным заголовком

Allow: GET, POST, ...

Некешиуремый необязательный метод.

Обработка ошибок

Возвращаемые ошибки передаются с сервера на клиент как ответы со статусами 4хх (ошибка клиента) или 5хх (ошибка сервера). При этом описание ошибки, если оно есть, приводится в теле ответа в формате text/plain (без всякого JSON). Соответственно, передаётся заголовок ответа

Content-Type: text/plain; charset=UTF-8

Использовать html для оформления сообщений об ошибках в api — так себе идея, будут проблемы журналированием и т.д. Предполагается, что клиент способен сам красиво оформить сообщение об ошибке для пользователя.

При выборе конкретных кодов ошибок не следует слишком увлекаться и пытаться применить существующие коды только потому, что название кажется подходящим. У многих кодов есть дополнительные требования к наличию определённых заголовков и специальная обработка браузерами. Например, код 401 запускает HTTP-аутентификацию, которая будет странно смотреться в каком-нибудь приложении на react или electron.

UPD по мотивам комментариев. Клиенты у вас будут разные: не только веб и мобильные приложения, но и такие штуки, как запускалка интеграционных тестов (CI), балансировщик нагрузки или система мониторинга у админов. Использование или неиспользование того или иного статуса ошибки определяется тем, будет ли он полезен хоть какому-то клиенту (т.е. этот клиент сможет предпринять какие-то действия конкретно по этому коду) и, наоборот, не будет ли проблем у какого-то из клиентов из-за неиспользования вами этого кода. Придумать реальный use-case, когда реакция клиента будет различаться в зависимости от 404 или 410, довольно сложно. При этом отличий 404 от 200 или 500 — вагон и телега.

400 Bad Request

Универсальный код ошибки, если серверу непонятен запрос от клиента.

403 Forbidden

Возвращается, если операция запрещена для текущего пользователя. Если у оператора есть учётка с более высокими правами, он должен перелогиниться самостоятельно. См. также 419

404 Not Found

Возвращается, если в запросе был указан неизвестный entity или id несуществующего объекта.

Списочные методы get не должны возвращать этот код при верном entity (см. выше).

Если запрос вообще не удалось разобрать, следует возвращать 418.

415 Unsupported Media Type

Возвращается при загрузке файлов на сервер, если фактический формат переданного файла не поддерживается. Также может возвращаться, если не удалось распарсить JSON запроса, или сам запрос пришёл не в формате JSON.

418 I'm a Teapot

Возвращается для неизвестных серверу запросов, которые не удалось даже разобрать. Обычно это указывает на ошибку в клиенте, типа ошибки при формировании URI, либо что версии протокола клиента и сервера не совпадают.

Этот ответ удобно использовать, чтобы отличать запросы на неизвестные URI (т.е. явные баги клиента) от ответов 404, у которых просто нет данных (элемент не найден). В отличие от 404, код 418 не бросается никаким промежуточным софтом. Альтернатива — использовать для обозначения ситуаций “элемент не найден” 410 Gone, но это не совсем корректно, т.к. предполагает, что ресурс когда-то существовал. Да и выделить баги клиента из потока 404 будет сложнее.

419 Authentication Timeout

Отправляется, если клиенту нужно пройти повторную авторизацию (например, протухли куки или CSRF токены). При этом на клиенте могут быть несохранённые данные, которые будут потеряны, если просто выкинуть клиента на страницу авторизации.

422 Unprocessable Entity

Запрос корректно разобран, но содержание запроса не прошло серверную валидацию.

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

Обычно это означает ошибку в введённых пользователем данных, но может также быть вызвано ошибкой на клиенте или несовпадением версий.

500 Internal Server Error

Возвращается, если на сервере вылетело необработанное исключение или произошла другая необработанная ошибка времени исполнения.

Всё, что может сделать клиент в этом случае — это уведомить пользователя и сделать console.error(err) для более продвинутых товарищей (админов, разработчиков и тестировщиков).

501 Not Implemented

Возвращается, если текущий метод неприменим (не реализован) к объекту запроса.


Ну вот, в общем-то, и всё. Спасибо за внимание!

Огромный проект у нас впереди. Скоро мы будем делать менеджер шаблонов текста, который сможет хранить наши бесценные данные не локально на компьютере, а на сервере.

Для этого мы уже сделали рабочий прототип приложения, а потом разобрались с понятием JSON. Теперь попробуем отправить данные на сервер.

Как это устроено

Если мы хотим хранить данные на сервере и отправлять их туда в любой момент, нам нужно действовать так:

  1. Собрать данные в JSON-формат.
  2. Упаковать их в специальный запрос.
  3. Встроенными средствами JavaScript отправить этот запрос на сервер по нужному адресу.
  4. Чтобы наш запрос был принят, по этому адресу на сервере должен находиться скрипт, который умеет работать с такими запросами.
  5. А чтобы сервер в принципе отвечал на какие-то запросы, нам нужно его этому обучить.

Первые три пункта сделаем на клиенте — нашей HTML-странице, а скрипт и настройки — на сервере. Скрипт будем писать на PHP, поэтому, если не знаете, что это и как с этим работать, — почитайте.

Чтобы было проще, мы отправим и обработаем на сервере совсем маленький JSON — в нём всего две пары «имя: значение», но даже со сложным запросом всё будет работать так же.

Готовим HTML-страницу

У нас будет очень простая страница, потому что самое важное сейчас — научиться работать с JSON-форматом, а красоту наведём позже.

На странице нам понадобятся:

  • заголовок;
  • два поля ввода, чтобы вы могли ввести туда любые данные и убедиться, что отправка работает;
  • кнопка, которая отправляет JSON на сервер;
  • место для вывода результата — там мы выведем то, что пришлёт нам сервер в ответ.

Мы сразу подключим jQuery, чтобы в скрипте напрямую обращаться к полям ввода и месту для вывода результата. А ещё заранее зададим синий цвет для вывода ответа от сервера — так мы сразу отличим данные на странице от того, что нам ответил сервер.

На языке HTML это будет так:

<!DOCTYPE html>
<html>
<head>
  <title>
    Отправляем JSON-данные на сервер
  </title>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body style="text-align:center;" id="body">
  <!-- заголовок -->
  <h1> Простая форма для проверки работы JSON </h1>
  <!-- делаем форму с полями ввода -->
  <p>
    <input type="text" id="name" placeholder="Ваше имя">
    <input type="text" id="lastname" placeholder="и фамилия">
    <!-- по нажатию на эту кнопку данные уйдут на сервер -->
    <button onclick="sendJSON()">Проверить JSON</button>
    <!-- а вот тут они появятся снова, но уже после обработки сервером -->
  <p class="result" style="color:blue"></p>
  </p>
</body>
</html>

Внешний вид очень простой, чтобы проверить работоспособность всей системы

Отправляем данные на сервер

Обычно, чтобы отправить данные на сервер, нужно делать запрос. Вы нажимаете кнопку на странице, браузер уходит думать, ждёт ответа сервера и рисует вам новую страницу в соответствии с этим ответом. Грубо говоря, запрос на сервер заставляет вашу страницу перезагружаться.

К счастью, инженеры давно придумали, как отправлять данные на сервер, не перезагружая страницу. Для этого используют JavaScript.

Чтобы отправить запрос, нам понадобится встроенный объект XMLHttpRequest(). Вот как мы вводим его в повествование:

// создаём новый экземпляр запроса XHR

let xhr = new XMLHttpRequest();

Для запроса нам нужно знать адрес, куда будем отправлять наш JSON — это и есть адрес нашего скрипта, который мы напишем позже. Мы будем писать его на PHP, поэтому заранее можем придумать ему имя и адрес, где он будет лежать: http://mihailmaximov.ru/projects/json/json.php.

// адрес, куда мы отправим нашу JSON-строку

url = "http://mihailmaximov.ru/projects/json/json.php";

Когда мы знаем адрес, мы можем открыть соединение, чтобы сервер был готов принять наши данные. Это значит, что мы пока ничего ценного туда не посылаем, а просто предупреждаем сервер, что скоро что-то прилетит:

// открываем соединение. url — это переменная с нашим адресом

xhr.open("POST", url, true);

Теперь напишем заголовок запроса, чтобы сервер понимал, какие данные мы ему пришлём и как ему их обрабатывать. Так как у нас JSON, то это и пропишем в заголовке:

 // устанавливаем заголовок —
выбираем тип контента, который отправится на сервер,
в нашем случае мы явно пишем, что это JSON

setRequestHeader("Content-Type", "application/json");

Чуть ниже сразу пропишем поведение скрипта на случай ответа сервера. Сервер должен обработать наши данные, вернуть ответ, а мы должны этот ответ поймать и вывести на страницу:

// когда придёт ответ на наше обращение к серверу, мы его обработаем здесь
xhr.onreadystatechange = function () {
  // если запрос принят и сервер ответил, что всё в порядке
  if (xhr.readyState === 4 && xhr.status === 200) {
    // выводим то, что ответил нам сервер — так мы убедимся, что данные он получил правильно
    result.innerHTML = this.responseText;
  }
};

Последнее, что нам осталось сделать, — вытащить наши введённые данные из полей, собрать из них JSON и отправить на сервер:

 // преобразуем наши данные JSON в строку

      var data = JSON.stringify({ "name":
name.value, "lastname": lastname.value });

      // когда всё готово, отправляем JSON на сервер

<!-- скрипт, который обработает нажатие на кнопку и отправит данные на сервер -->
<script>
  // эта функция сработает при нажатии на кнопку
  function sendJSON() {
    // с помощью jQuery обращаемся к элементам на странице по их именам
    let name = document.querySelector('#name');
    let lastname = document.querySelector('#lastname');
    // а вот сюда мы поместим ответ от сервера
    let result = document.querySelector('.result');
    // создаём новый экземпляр запроса XHR
    let xhr = new XMLHttpRequest();
    // адрес, куда мы отправим нашу JSON-строку
    let url = "http://mihailmaximov.ru/projects/json/json.php";
    // открываем соединение
    xhr.open("POST", url, true);
    // устанавливаем заголовок — выбираем тип контента, который отправится на сервер, в нашем случае мы явно пишем, что это JSON
    xhr.setRequestHeader("Content-Type", "application/json");
    // когда придёт ответ на наше обращение к серверу, мы его обработаем здесь
    xhr.onreadystatechange = function () {
      // если запрос принят и сервер ответил, что всё в порядке
      if (xhr.readyState === 4 && xhr.status === 200) {
        // выводим то, что ответил нам сервер — так мы убедимся, что данные он получил правильно
        result.innerHTML = this.responseText;
      }
    };
    // преобразуем наши данные JSON в строку
    var data = JSON.stringify({ "name": name.value, "lastname": lastname.value });
    // когда всё готово, отправляем JSON на сервер
    xhr.send(data);
  }
</script>

Пишем PHP-скрипт для сервера

Задача скрипта пока будет очень простой — ему нужно будет получить наши данные и показать, что всё пришло как нужно. В PHP уже встроена команда, которая разбирает JSON-строку на составляющие, поэтому весь скрипт будет занимать три строчки:

<?php
// на какие данные рассчитан этот скрипт
header("Content-Type: application/json");
// разбираем JSON-строку на составляющие встроенной командой
$data = json_decode(file_get_contents("php://input"));
// отправляем в ответ строку с подтверждением
echo "Сервер получил следующие данные: имя — $data->name, фамилия — $data->lastname";

Для получения данных наш PHP-скрипт использует стандартную команду file_get_contents("php://input"). Она просто ждёт, когда что-то прилетит, и отправляет результат в выбранную переменную. Дальше её можно разобрать как JSON-объект командой json_decode() и работать с данными напрямую.

Последняя команда echo отправляет в ответ то, что написано в двойных кавычках. Там мы обращаемся к переменной $data, где хранятся присланные данные. Именно этот ответ будет обрабатывать скрипт на JavaScript, в функции xhr.onreadystatechange, которую мы прописали раньше.

Сам код нам нужно сохранить как json.php и положить в папку /projects/json/ на нашем сайте — так мы прописали в скрипте на JavaScript.

Настраиваем сервер

Если мы сейчас попробуем нажать на кнопку, браузер нам выдаст ошибку:

Как отправить JSON-данные на сервер

Штука в том, что если сервер заранее всем не сообщит, что он готов работать с запросами, то браузер не даст нашей локальной странице на компьютере получить данные с другого сервера в интернете. Это сделано в целях безопасности, например, чтобы при оплате картой данные не ушли на другой сервер кроме нужного.

Чтобы браузер разрешил нам получать и отправлять данные с сервера, нам нужно настроить сервер. Настройка происходит в файле .htaccess: это такой системный файл, который лежит на вашем сервере и подсказывает серверу, как себя вести в разных ситуациях, что-то вроде инструкции. Название .htaccess неслучайно: у файла как бы нет имени, но есть расширение .htaccess, и в обычных папках этот файл не будет виден.

Создаём пустой файл, пишем в него вот такое колдовство и сохраняем как .htaccess

Header set Access-Control-Allow-Origin "*"

Header set Access-Control-Allow-Methods: "GET,POST,OPTIONS,DELETE,PUT"

Header add Access-Control-Allow-Headers
"origin, x-requested-with, content-type"

Первая строка разрешает серверу работать с запросами от любых страниц (хоть это и небезопасно, но пока мы учимся — так можно). Вторая строка содержит список разрешённых запросов. Третья разрешает нужные нам заголовки в запросе.

Фактически этот файл сейчас означает: «разрешаю тебе принимать запросы со всех сайтов, вот такого типа запросы можно принимать, вот такие у них могут быть заголовки». В буквальном смысле методичка.

Откуда вы знаете, что нужны именно эти команды?

Когда мы писали эту статью, нам потребовалось почитать справочники и форумы, протестировать несколько вариантов команд и в итоге найти именно эту — ту, что работает.

Вся информация по командам и настройке в интернете уже есть. Нужно просто ее искать, анализировать и тестировать.

Теперь в интернете есть ещё и эта статья, которая поможет вам меньше искать 🙂

Файл .htaccess нужно не потерять (на некоторых операционках он станет невидимым, как только вы его сохраните как .htaccess — придётся покопаться в настройках, чтобы его раскрыть). Загружаем его на сервер.

Перезапускаем нашу локальную страничку и пробуем её в действии.

Всё работает. Синий текст мы получили от PHP-скрипта на сервере. Связь налажена!

Что дальше

Мы научились отправлять данные на сервер и немного работать там с ними. Дальше попробуем заменить в наших проектах локальное хранение данных на хранение на сервере, чтобы проекты работали с любого браузера.

Взаимодействие с API Яндекс Директа в формате JSON.

Преимущество JSON в большей компактности по сравнению с SOAP/XML, а также в скорости анализа запросов на стороне Яндекс Директа.

Во многих языках программирования существуют модули и библиотеки для работы с JSON. Ниже перечислены рекомендуемые модули и библиотеки для популярных языков.

  • Perl: модуль JSON.

  • PHP: встроенная поддержка JSON началась в версии 5.2.0. В предыдущих версиях можно использовать библиотеку Services_JSON.

  • Python: модуль json.

В документе содержатся примеры работы с JSON: Perl, PHP, Python.

Запросы в формате JSON передаются методом HTTP POST на следующий адрес:

Версия 4
https://api.direct.yandex.ru/v4/json/ 
Версия Live 4
https://api.direct.yandex.ru/live/v4/json/

Запрос всегда содержит ключ method с именем вызываемого метода и в большинстве случаев ключ param (см. пример ниже). Некоторые методы не имеют входных параметров, и для них ключ param не требуется.

Пример демонстрирует вызов метода GetClientInfo. В ключе param передается массив из одной строки, которая является логином пользователя. Ключ locale устанавливает русский язык для ответных сообщений. Ключ token — авторизационный токен, выданный OAuth-сервером Яндекса с согласия пользователя (подробнее см. Авторизационные токены).

POST /v/json/ HTTP/1.1
Host: api.direct.yandex.ru
Content-Length: 204
Content-Type: application/json; charset=utf-8

{
    "method": "GetClientInfo",
    "param": ["agrom"],
    "locale": "ru",
    "token": "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"
}

Запрос может содержать ключ locale, указывающий язык ответных сообщений. На выбранном языке возвращаются статусы кампаний, статусы баннеров и сообщения об ошибках. Возможны следующие значения locale:

  • ru — русский;

  • ua — украинский;

  • en — английский.

Если ключ locale отсутствует, подразумевается английский язык.

Для вызова финансовых методов CreateInvoice, TransferMoney, GetCreditLimits, PayCampaigns необходимо дополнительно указывать номер операции и финансовый токен в ключах operation_num и finance_token. Об их формировании рассказывается в разделе Доступ к финансовым методам.

Вызов финансового метода GetCreditLimits.

{
    "method": "GetCreditLimits",
    "finance_token": "07c2fbae9722634918bb00a70d2c467cf1bd07255012008ff249ba41b7a5cd6c",
    "operation_num": 123,
    "token": "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"
}

При возникновении ошибок обработка запроса прекращается и возвращается сообщение об ошибке в формате JSON. Пример сообщения показан ниже.

{
    "error_detail":"Метод HTTP запроса должен быть POST",
    "error_str":"Неверный метод запроса",
    "error_code":512
}

Параметр error_code содержит код ошибки, error_str — краткое описание ошибки, error_detail — дополнительные пояснения, если имеются. Краткое описание и дополнительное пояснение могут выводиться на разных языках, что определяется параметром locale, указанным при вызове метода.

1. Overview

In this tutorial, we’ll demonstrate how to make a JSON POST request using HttpURLConnection.

2.1. Create a URL Object

Let’s create a URL object with a target URI string that accepts the JSON data via HTTP POST method:

URL url = new URL ("https://reqres.in/api/users");

2.2. Open a Connection

From the above URL object, we can invoke the openConnection method to get the HttpURLConnection object.

We can’t instantiate HttpURLConnection directly, as it’s an abstract class:

HttpURLConnection con = (HttpURLConnection)url.openConnection();

2.3. Set the Request Method

To send a POST request, we’ll have to set the request method property to POST:

con.setRequestMethod("POST");

2.4. Set the Request Content-Type Header Parameter

Set the “content-type” request header to “application/json” to send the request content in JSON form. This parameter has to be set to send the request body in JSON format.

Failing to do so, the server returns HTTP status code “400-bad request”:

con.setRequestProperty("Content-Type", "application/json");

2.5. Set Response Format Type

Set the “Accept” request header to “application/json” to read the response in the desired format:

con.setRequestProperty("Accept", "application/json");

2.6. Ensure the Connection Will Be Used to Send Content

To send request content, let’s enable the URLConnection object’s doOutput property to true.

Otherwise, we won’t be able to write content to the connection output stream:

con.setDoOutput(true);

2.7. Create the Request Body

After creating a custom JSON String:

String jsonInputString = "{"name": "Upendra", "job": "Programmer"}";

We would need to write it:

try(OutputStream os = con.getOutputStream()) {
    byte[] input = jsonInputString.getBytes("utf-8");
    os.write(input, 0, input.length);			
}

2.8. Read the Response From Input Stream

Get the input stream to read the response content. Remember to use try-with-resources to close the response stream automatically.

Read through the whole response content, and print the final response string:

try(BufferedReader br = new BufferedReader(
  new InputStreamReader(con.getInputStream(), "utf-8"))) {
    StringBuilder response = new StringBuilder();
    String responseLine = null;
    while ((responseLine = br.readLine()) != null) {
        response.append(responseLine.trim());
    }
    System.out.println(response.toString());
}

If the response is in JSON format, use any third-party JSON parsers such as Jackson library, Gson, or org.json to parse the response.

3. Conclusion

In this article, we learned how to make a POST request with JSON content body using HttpURLConnection.

As always, the relevant code snippets can be found over on GitHub

Время чтение: 7 минут
2018-11-22

Подумала я подумала и решила, поговорим о JSON! Но не на языки великой и всемогущей «Википедии» где статьи пишутся по моему в большинстве своём для сверх разума, а не для людей. Так же не буду парить тебе мозг, на кучу абзацев тем, что JSON  это текстовый формат данных, который явился из JavaScript и прочею скучную хернь. Ну, все это нахер…

Мы пойдём другим путём более интересным и информативным, что бы было ясно, зачем и для чего может пригодится JSON и как с ним работать. Сначала не много болтовни, а после пару практических примеров. Поработаем с какой-нибудь API системой и на практике убедится, что JSON  это очень круто, просто и удобно!

Где и для чего используется JSON

Вы можете использовать JSON везде, где есть необходимость для передачи или получения какой либо информации, между приложениями. Или использовать JSON как бы локально, просто хранить там какие-то настройки своего приложения. Как я это уже делала в соседней статье.

Например: Сервер — Клиент.
Имеем сервер, на сервере стоит база данных которая таит в себе некую информацию. Эту информацию нам нужно получить, например из python приложения, которое вы кодите на своём ПК. Возникает вопрос, как? Вот тут-то JSON  себя и проявляет во всей красе.

Ложем на сервер, скажем PHP скрипт, который мониторит  входящие GET запросы. Из приложухи python  отправляем запрос на сервер, PHP ловит запрос… ломится в базу данных и вытаскивает от туда информацию в виде массива. Далее полученный массив преобразуется в JSON и как обычный текст отправляется в приложения python. А там уже можно декодировать  JSON и продолжить работу с инфой полученной из Базы Данных! Удобно? Круто? Да это б*ять п*здец как ахуе*но!

Например: В пределах одного приложения.
Кодите вы что-то там, такое не большое и простое. Есть необходимость где-то, что-то хранить, некую статистическую информацию, которая никогда не меняется и при этом часто используется в приложении. Использовать БД не вариант, зато  JSON  подойдёт в самый раз. Как такой пример работает в действии, читайте в соседней статье, ссылку кинул выше…

Синтаксис и структура JSON

Прежде чем приступить к разбору JSON надо понять и разобраться в том, как собственно все это дело создаётся и записывается в файл. Синтаксис достаточно простой и не должен вызвать каких-то сложностей. Достаточно запомнить следующие моменты и посмотреть на примеры.

Общие принципы:

  1. Массив всегда заключается в  квадратные скобки [ … ]
  2. Объект нужно заключать в фигурные скобки { … }
  3. Свойства и значения в двойных кавычках разделённые ( : ) «Значение» : «Свойства»

Свойства может быть:

  1. Логическим (true или false).
  2. Числом, записывается без двойных кавычек.
  3. Строкой, записывается в двойные кавычки.
  4. Массивом или объектом.

Когда основные моменты структуры JSON известны, рассмотрим примеры JSON файлов и начнём с самого примитивного и простого примера.

[cc lang=»php»]
{
«Машка» : «28 год»,
«Дашка» : «35 лет»,
«Анжелка» : «30 лет»
}
[/cc]

Если декодировать этот пример из приложения, например из PHP используя функцию json_decode() то вывод будет следующим.

[cc lang=»php»]
stdClass Object
(
[Машка] => 28 год
[Дашка] => 35 лет
[Анжелка] => 30 лет
)
[/cc]

Поскольку JSON пофиг на табуляцию и пробелы, вы можете делать записи как Вам больше нравится, например в одну строку.

[cc lang=»php»]{ «Машка» : «28 год», «Дашка» : «35 лет», «Анжелка» : «30 лет» }[/cc]

Или использовать табуляцию, для полной красоты записи.

[cc lang=»php»]
{
«Машка» : «28 год»,
«Дашка» : «35 лет»,
«Анжелка» : «30 лет»
}
[/cc]

Давай сделаем все не много интереснее и усложним пример. Разделим логически записи для каждой особы, что бы добавить для каждой девушки информацию о ней.

[cc lang=»php»]
{
«Машка» : {
«Возрост» : «33»,
«1 час» : «150$»
},
«Дашка» : {
«Возрост» : «28»,
«1 час» : «200$»
},
«Анжелка» : {
«Возрост» : «28»,
«1 час» : «100$»
}
}
[/cc]

Обратите внимание, что за последним элементом не ставится запитая, как после свойства так и объекта. Посмотрим, какой теперь будет ответ.

[cc lang=»php»]
stdClass Object
(
[Машка] => stdClass Object
(
[Возрост] => 33
[1 час] => 150$
)

[Дашка] => stdClass Object
(
[Возрост] => 28
[1 час] => 200$
)

[Анжелка] => stdClass Object
(
[Возрост] => 28
[1 час] => 100$
)

)
[/cc]

Теперь все куда интереснее. Можно из программы получить нужный объект, например «[Дашка]» и посмотреть что там за час))) Но что если и этого мало. Нужно больше информации и по каждому объекту. Можно присобачить массив. Далее буду использовать примеры JSON в более коротком варианте, либо листинги длинные…

[cc lang=»php»]
{
«Машка» : {
«Возрост» : «33»,
«1 час» : «150$»,

«Доп инфа» : [{
«Рост» : 169,
«Статус» : true
}]

}
}

[/cc]

Ну и стразу можно посмотреть в каком виде прилетит ответ. Кстати, в этом примере [] можно убрать, они тут в принципе и нахер не нужны, но для примера сойдёт.

[cc lang=»php»]
stdClass Object
(
[Машка] => stdClass Object
(
[Возрост] => 33
[1 час] => 150$
[Доп инфа] => Array
(
[0] => stdClass Object
(
[Рост] => 169
[Статус] => 1
)

)

)

)
[/cc]

Думаю понятно, что к чему, и как создаются JSON файлы. Вы сами можете продумывать структуру файлов под свои задачи, главное не нарушать синтаксис, и все будет хорошо.

Теперь предлагаю перейти к практики, и написать приложуху, которая будет отправлять на API запросы и получать ответы, конечно же в JSON формате.

JSON в практических примерах

Первое что в голову приходит, это взять соц.сеть, например API VK и поработать с ним, но нет. Не охота тратить время на создание приложения, подтверждать все по СМС и прочие, и вообще ВК дно…

Не много подумал, если же coinmarketcap.com/api/ с публичным API без всяких ключей и секретов. Круто, будем писать крипто приложение, можно какойнить виджет на сайт замутить))) Напишем прогу которая будет сообщать, какие монеты находятся в ТОП 3, какие цены, и всю херню…

Отправляем запрос на сервер 

Ломимся на coinmarketcap.com и смотрим что там есть. Что бы получить ТОП 3 манеты можно отправить GET запрос по адресу http://api.coinmarketcap.com/v2/ticker/?limit=10 где параметру limit передать нужно количество монет «Значение», нас интересует 3. Пишем код.

[cc lang=»php»]
$ticker = file_get_contents(‘http://api.coinmarketcap.com/v2/ticker/?limit=3’);
$ticker = json_decode($ticker);

echo «n»;
print_r($ticker);
echo «n»;
[/cc]

И сразу смотрим ответ, что там пришло.

Видим уже нечто знакомое, это сервер вернул ответ в JSON формате, в котором содержится целая куча всякой разной информации по каждой монете. Теперь осталось разобрать все это дело и забрать только то, что нам нужно. Пишем код дальше.

[cc lang=»php»]
$ticker = file_get_contents(‘http://api.coinmarketcap.com/v2/ticker/?limit=3’);
$ticker = json_decode($ticker);

echo «n»;

foreach ($ticker->data as $key => $value) {
echo ‘ ============= TOP ‘. $value->rank .’ ==============’ . «rn»;
echo ‘ Монета :’ . $value->name . «rn»;
echo ‘ Цена :’ . $value->quotes->USD->price . «rn»;
echo ‘ Объём :’ . $value->quotes->USD->volume_24h . «rn»;
echo ‘ ==================================’ . «rnrn»;
}
[/cc]

Для примера я взяла только некоторую часть информации, а остальное брать не буду, сами разбирайтесь))) Результат работы этой крутой и полезной программы представлен на этом скнине.

Как вы понимаете я использую консоль, по скольку все это дело на PHP думаю понятно, как просто вывести все это дело на сайте.

На этом работа с JSON на сегодня окончена, мы посмотрели пару примеров, и написали программу, которая прекрасно демонстрирует всю прелесть и удобство JSON.

Добавить комментарий