#はじめに
前回の投稿からはや丸一年。そして遅刻。
時の流れとは恐ろしいものです。
さて、今回はDrupal8でも採用されているPHPのHTTPクライアント Guzzle を使って、REST APIを叩きます。
(モジュール設定等は前回の記事を参照してください)
また、本家のドキュメントでもGuzzleを使ったコードが紹介されていますが、jsonとhal+json、basic authとcookieがごちゃまぜになっている気がするので、今回は最小構成で利用できるように心がけます。
#Drupal8.2以降のREST APIの変更点
Drupal8.2では、1年前と比べるとたくさんの変更点がありますが、個人的に使い勝手が大きく向上したと思う2点をご紹介します。
1.気持ち悪かったログイン/CSRFトークンの取得まわりが改善された
ログイン成功時のレスポンスでCSRFトークンやuidなどがJSON形式で取得できます。
(ログインエラーなのにステータスコードが「200 OK」な現象がなくなりました)
2.登録・編集したコンテンツのエンティティデータがレスポンス(JSON文字列)として返ってくる
コンテンツを登録したものの、登録したコンテンツのノードIDがわからないとか、更新した後に再度読み込む2度手間などがなくなりました。
(以前はレスポンスがNo Contentでした)
#準備
任意のディレクトリでcomposerを使ってguzzleをインストールします。
composer init
~
composer require guzzlehttp/guzzle:~6.0
空のphpファイル(rest_client.php)を作成し、次のコードを追記していきます。
#GuzzleでREST APIを叩いてみる
##初期化
GuzzleのHTTPクライアントのオブジェクトを生成します。
今回はCookieを使うので、 cookiesはtrueにします。
<?php
require 'vendor/autoload.php';
$base_uri = "https://drupal82.local";
$client = new \GuzzleHttp\Client([
'base_uri' => $base_uri,
'cookies' => true, //必須
]);
##記事の取得(GET)
ノードID:1 の記事データを取得してタイトルと本文を変数に格納します。
レスポンスはJSONの文字列として返ってくるので、デコードしたうえで使用します。
$response = $client->request("GET", "node/1", [
"query" => ["_format" => "json"],
]);
$article_entity = json_decode($response->getBody());
//タイトル: My 1st article
$title = $article_entity->title[0]->value;
//本文: Hello Drupal8!
$body = $article_entity->body[0]->value;
下記のようにパスにパラメータを含める、エイリアス名を使うといったことも可能です
//hal+json
$response = $client->request("GET", "node/1?_format=hal_json");
//エイリアス名
$response = $client->request("GET", "my_1st_article?_format=hal_json");
##ログイン認証(cookie)およびCSRFトークンの取得
Drupal8.2で改善されたログイン機能を使ってCSRFトークンを取得します。
ログインURLに_formatパラメータを付与したうえで、ユーザ名とパスワードをJSON形式で送信します。
//ログイン情報を送信( application/json )
$response = $client->request('POST', 'user/login', [
"query" => ["_format" => "json"],
"json" => [
"name" => "rest_user",
"pass" => "rest_pass",
]
]);
//JSON文字列をデコード(配列にする場合は第2引数をtrue)
$login_info = json_decode($response->getBody());
$uid = $login_info->current_user->uid;
$name = $login_info->current_user->name;
$csrf_token = $login_info->csrf_token;
$logout_token = $login_info->logout_token;
##記事の登録(POST)
コンテンツの登録・更新・削除は取得したCSRFトークンを「X-CSRF-Token」ヘッダーに付与して行います。
JSON形式で登録する場合は、type で登録するコンテンツの種類を指定します。
※配列の階層には要注意
$article_data = [
'title' => [['value' => 'REST APIで登録(JSON)']],
'body' => [['value' => '本文']],
'type' => [['target_id' => 'article']],
];
$response = $client->post('/entity/node', [
'headers' => [
'Content-Type' => 'application/json',
'X-CSRF-Token' => $csrf_token
],
"query" => ["_format" => "json"],
'json' => $article_data,
]);
//更新結果がレスポンスに入る
$article_entity = json_decode($response->getBody());
//登録したノードID
$nid = $article_entity->nid[0]->value;
//タイトル: REST APIで登録(JSON)
$title = $article_entity->title[0]->value;
HAL+JSON形式で登録する場合は、_links で登録するコンテンツの種類を指定します。
また、Content-Typeは「application/hal+json」を指定します。
$article_data = [
'title' => [['value' => 'REST APIで登録(HAL+JSON)']],
'body' => [['value' => '本文']],
'_links' => ['type' => [
'href' => $base_uri . '/rest/type/node/article'
]],
];
$response = $client->post('/entity/node', [
'headers' => [
'Content-Type' => 'application/hal+json',
'X-CSRF-Token' => $csrf_token
],
"query" => ["_format" => "hal_json"],
'json' => $article_data,
]);
//更新結果がレスポンスに入る
$article_entity = json_decode($response->getBody());
//登録したノードID
$nid = $article_entity->nid[0]->value;
//タイトル: REST APIで登録(HAL+JSON)
$title = $article_entity->title[0]->value;
##記事の更新(PATCH)
先ほど登録した記事を更新します。
レスポンスで取得したノードIDを使い、本文を更新します。
HAL+JSON形式の場合は次のようになります。
$article_data = [
'body' => [['value' => 'REST APIで本文更新']],
'_links' => ['type' => [
'href' => $base_uri . '/rest/type/node/article'
]],
];
$response = $client->patch('node/' . $nid, [
'headers' => [
'Content-Type' => 'application/hal+json',
'X-CSRF-Token' => $csrf_token
],
"query" => ["_format" => "hal_json"],
'json' => $article_data,
]);
//更新結果がレスポンスに入る
$article_entity = json_decode($response->getBody());
//本文: REST APIで本文更新
$body = $article_entity->body[0]->value;
##記事の削除(DELETE)
最後に更新した記事を削除します。
$response = $client->delete('node/' . $nid, [
'headers' => [
'X-CSRF-Token' => $csrf_token
]
]);
#さいごに
今回は駆け足で、Guzzleを使った実装についてご紹介しました。
Drupal8.2で痒い所に手が届くようになり、より使いやすくなったREST APIをぜひ使ってみてください。
また、RESTモジュールは現在でも活発に開発が進められているようですので、Drupal8.3でも様々な機能拡張や改善が期待できますね!
(そもそも現行機能もごく一部しか使えていませんが・・・^^;)