Как правильно прочитать большой ответ JSON API в Guzzle 6?

В настоящее время у меня есть следующая реализация Guzzle 6, возвращающая поток данных JSON, содержащий пользовательские данные:

$client = new GuzzleHttp\Client([
        'base_uri' => 'https://www.apiexample.com',
        'handler' => $oauthHandler,
        'auth'    => 'oauth',
        'headers' => [
            'Authorization' => 'Bearer xxxxxxxxxxxxxx',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
]);

$res = $client->post('example');
$stream = GuzzleHttp\Psr7\stream_for($res->getBody());

Ответы JSON выглядят так:

{
    "name": "Users",
    "record": [
        {
            "title": "Consulting",
            "_name": "Users",
            "end date": "07/03/2020",
            "session number": "1",
            "start date": "09/02/2019",
            "course id": "2900",
            "first name": "John",
            "unique user number": "123456",
            "time": "08 AM",
            "last name": "Doe",
            "year": "19-20",
            "location name": "SD"
        },
        .........
     ],
     "@extensions": "activities,corefields,u_extension,u_stu_x,s_ncea_x,s_stu_crdc_x,c_locator,u_userfields,s_edfi_x"
 }

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

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

Я новичок в том, что мне нужно передавать такой ответ API, и мне интересно, каким будет правильный подход к повторению записей? Глядя на документы Guzzle 6, кажется, что итерация происходит путем выбора символа числа x в строке и захвата этого подраздела:

http://docs.guzzlephp.org/en/stable/psr7.html#streams

use GuzzleHttp\Psr7;

$stream = Psr7\stream_for('string data');
echo $stream;
// string data
echo $stream->read(3);
// str
echo $stream->getContents();
// ing data
var_export($stream->eof());
// true
var_export($stream->tell());
// 11

Я потенциально мог бы написать что-то, что анализирует строки в подразделах посредством сопоставления с образцом и постепенно записывает данные на диск по мере прохождения ответа. Но похоже, что это будет подвержено ошибкам и станет частью Guzzle 6.

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

Я ценю это, спасибо!


person space97    schedule 19.03.2020    source источник


Ответы (1)


Но похоже, что это будет подвержено ошибкам и станет частью Guzzle 6.

Нет, Guzzle — это HTTP-клиент, он не имеет ничего общего с анализом разных форматов ответов.

Вам нужен потоковый анализатор JSON. Пожалуйста, взгляните на этот вопрос SO и также в библиотеках: https://github.com/salsify/jsonstreamingparser, https://github.com/clue/php-json-stream, https://github.com/halaxa/json-machine.

В Guzzle у вас будет 2 возможности:

  • читать поток ответов вручную (как вы это делаете сейчас), но для этого, вероятно, требуется ручная интеграция с потоковым парсером JSON.
  • для передачи всего ответа во временный файл (см. параметр запроса "sink") и прочитать этот файл позже с помощью анализатора потоковой передачи JSON, это должно поддерживаться всеми библиотеками.
person Alexey Shokov    schedule 20.03.2020