3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

DrupalAdvent Calendar 2016

Day 20

Drupal8.2でREST APIを使ってみる(Guzzle6編)

Last updated at Posted at 2016-12-20

#はじめに
前回の投稿からはや丸一年。そして遅刻。
時の流れとは恐ろしいものです。

さて、今回は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にします。

rest_client.php
<?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形式で送信します。

ログイン認証/CSRFトークン取得
//ログイン情報を送信( 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 で登録するコンテンツの種類を指定します。
※配列の階層には要注意

記事登録(JSON)
$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」を指定します。

記事登録(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でも様々な機能拡張や改善が期待できますね!
(そもそも現行機能もごく一部しか使えていませんが・・・^^;)

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?