Guzzle のレスポンスが空配列に見える件の検証のため、 Chrome拡張機能 (Talend API Tester) から POST を投げてみる

経緯

Guzzle で API を叩いていたのですが、レスポンスのステータスコードが 200 なのにボディ部が [] (空配列) だったので嵌まってしまいました。そこで検証のため、ブラウザから POST しようとした、というお話です。

検証

検証のため、以下のようなリクエストヘッダとレスポンスヘッダを出力するだけの PHP を用意します。

<?php

date_default_timezone_set('Asia/Tokyo');
mb_language('ja');
mb_internal_encoding('UTF-8');

$status = [
    'code'    => 200,
    'message' => 'OK.',
];

// request
$requestHeaders = apache_request_headers();
unset($requestHeaders['Cookie']);
$requestHeaders['Method'] = $_SERVER['REQUEST_METHOD'];

$requestBodies = file_get_contents('php://input');

$request = [
    'headers' => $requestHeaders,
    'bodies'  => $requestBodies,
];

switch ($_SERVER['REQUEST_METHOD']) {
    case 'GET':
        $status['code'] = 200;
        $status['message'] = 'OK.';
        break;
    case 'POST':
        $status['code'] = 200;
        $status['message'] = 'OK.';
        break;
    case 'PUT':
        $status['code'] = 201;
        $status['message'] = 'Created.';
        break;
    case 'DELETE':
        $status['code'] = 205;
        $status['message'] = 'Reset Content.';
        break;
    case 'HEAD':
        $status['code'] = 400;
        $status['message'] = 'Bad Request.';
        break;
    case 'OPTIONS':
        $status['code'] = 405;
        $status['message'] = 'Method Not Allowed.';
        break;
    case 'PATCH':
        $status['code'] = 409;
        $status['message'] = 'Conflict.';
        break;
    default:
        $status['code'] = 405;
        $status['message'] = 'Method Not Allowed.';
        break;
}

// response
$responseHeaders = [
    'Code'           => $status['code'],
    'Status-Message' => $status['message'],
    'Protocol'       => $_SERVER['SERVER_PROTOCOL'],
    'Host'           => $_SERVER['HTTP_HOST'],
    'Date'           => date('D, d M Y H:i:s T'),
    'Connection'     => isset($_SERVER['HTTP_CONNECTION']) && !empty($_SERVER['HTTP_CONNECTION']) ? $_SERVER['HTTP_CONNECTION'] : 'Close',
    'X-Powered-By'   => explode(' ', $_SERVER['SERVER_SOFTWARE'])[0] . '/' . explode(' ', $_SERVER['SERVER_SOFTWARE'])[1],
    'Content-Type'   => isset($_SERVER['CONTENT_TYPE']) && !empty($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : '',
];

$responseBodies = file_get_contents('php://input');

$response = [
    'headers' => $responseHeaders,
    'bodies'  => $responseBodies,
];

// concat
$output = json_encode(
    [
        'request'  => $request,
        'response' => $response
    ],
    JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE
);

// output

header('Content-Type: application/json; charset=UTF-8');
header($_SERVER['SERVER_PROTOCOL'] . ' ' . (string)$status['code'] . ' ' . $status['message']);
echo $output;

次に、 Chrome拡張機能 の Talend API Tester をインストールします。

ブラウザでアクセスしてGETしたリクエストとレスポンスの例
ブラウザでアクセスしてGETしたリクエストとレスポンスの例

そして、先程の PHP が置いてある Webサーバ に向けて各メソッドとデータの投げ込みを試します。

Talend API Tester で GET リクエストを投げた図
Talend API Tester で GET リクエストを投げた図
Talend API Tester で POST リクエストを投げた図
Talend API Tester で POST リクエストを投げた図
Talend API Tester で HEAD リクエストを投げた図
Talend API Tester で HEAD リクエストを投げた図

確かに POST や他のメソッドがリクエストできていることが確認できました。

ここで、 Guzzle で上手く行っていない API に向けて POST したところ、正常なレスポンス、ボディ部もきちんと JSON が返却されていることが確認できました。

この Chrome拡張機能、自作の API の動作確認するとき等で役に立ちそうですね。

原因

さて、本題の Guzzle がコケていた原因ですが……結局はレスポンスのデータを格納している Guzzle のオブジェクトから取り出す方法を間違えていただけでした (処理自体は正しく完了していた)。

具体的には、 Guzzle のレスポンス $rensponse に対し、 $response->getBody()ではダメで、 $response->getBody()->getContents() までしないとレスポンスボディ部の JSONデータ が拾えなかった、というオチ。

なお、今回のケースでは $response->getBody()->getContents() の出力が文字列なのでそのまま echo しても良い状態でした。

あるいは、冗長ですが json_encode(json_decode($response->getBody(), true), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE) と一度 JSON をデコードしてオブジェクトの形で取り出してから、再度 JSON エンコードで JSON文字列 にすれば上述と同様の結果が出力されました。

参考

Chrome拡張機能 (Talend API Tester)

Guzzle

PHP標準出力

この記事を書いた人

アルム=バンド

フロントエンド・バックエンド・サーバエンジニア。LAMPやNodeからWP、Gulpを使ってejs,Scss,JSのコーディングまで一通り。たまにRasPiで遊んだり、趣味で開発したり。