Drupal8でREST APIを使ってみる

  • 23
    Like
  • 0
    Comment
More than 1 year has passed since last update.

(※2016/7/14 追記)
こちらでご紹介しているRESTful web servicesモジュールのDrupal7バージョンは、極めて危険な脆弱性が報告されています。
まだセキュリティアップデートが行われていない場合は直ちにアップデートを行ってください。
■RESTWS - Highly critical - Remote code execution - SA-CONTRIB-2016-040
https://www.drupal.org/node/2765567

はじめに

こちらは、Drupal Advent Calendar 2015の19日目の投稿です。

Drupal8の特長の一つとして、標準でRestfulなWEBサービスを構築できるというものがありますが、日本語でまとまった情報がなかなか見つからないので自分で調べながら使ってみました。
試行錯誤しながら書いていますので、間違いやより良い方法などがありましたら、コメントででもご指摘いただければ感謝です。

Drupal8におけるREST APIの構成

REST(RESTful)の詳細についてはここでは割愛させて頂き、URLをリソースに見立てて、HTTPメソッドとパラメータでデータを操作するWebサービスの提供形態の一つ位の漠然とした定義としておきます。
以下、REST APIを使ったリソースへのアクセス、認証、フォーマットの仕様についてまとめました。

HTTPメソッド/CRUDの対応表

よくあるHTTPメソッドとCRUD処理の対応表をDrupal8のREST API用にまとめてみました。

留意点としては以下の2点。
1.リソース一覧の取得はViewsのREST export displayで構築します。
 強力なViewsの出力機能をそのまま使うことができるのは非常に魅力的です。
 (もちろん個別のリソースの取得にも使用できます)
2.リソースの更新はPUTではなくPATCHで行います。
 必要なところだけを更新してあとはDrupalに任せるということでしょうが、PaaSやレンタルサーバによっては、PATCHメソッドが使用できるか注意が必要でしょう。

HTTPメソッド 概要 CRUD パス HTTPステータスコード(成功時)
GET リソース一覧の取得(ViewsのREST export) READ (任意のパス) 200 OK
GET リソースの取得 READ /node/{nid} または URLエイリアス 200 OK
POST リソースの新規登録 CREATE /entity/node 201 Created
(PUT) リソースの更新(使用不可?) UPDATE - -
PATCH リソースの一部更新 UPDATE /node/{nid} または URLエイリアス 204 No Content
DELETE リソースの削除 DELETE /node/{nid} または URLエイリアス 204 No Content

認証プロバイダーとCSRFトークン

認証プロバイダー

標準でCookieとベーシック認証、モジュールの追加でOAuthを利用できます。
■Cookieを使う
従来のセッションを使った認証を利用します。
/user/login にPOSTリクエストを投げることでログイン状態にします。
リクエストのたびに認証を行った(セッションIDが登録されている)クッキーを送信する必要があります。

■ベーシック認証を使う
DrupalのユーザID/パスワードでベーシック認証を行うことが出来ます。
リクエストにAuthorizationヘッダーを付加して送信します。

■OAuthを使う
この記事では取扱いませんが、Simple OAuthモジュール(OAuth 2.0)OAuthモジュール(OAuth 1.0)を導入すると利用できるようです。
この辺りもご参照ください。

CSRFトークン

リソースの登録・更新・削除を行う際にリクエストにX-CSRF-TokenヘッダーにCSRFトークンを付与する必要があります。
(ベーシック認証を使用する場合は不要)
/rest/session/token にリクエストを送信することで取得できます。

対応フォーマット形式

HTTPメソッドごとに以下の種類のフォーマットを利用できます。

  • json ( Content-Type: application/json )
  • hal_json ( Content-Type: application/hal+json )
  • xml ( Content-Type: text/xml )

出入力フォーマットは、GETでは _format パラメータ、POST/PATCHではHTTPヘッダーのContent-Typeで指定します。
(ex. /node/1?_format=json )

GETでは、もともとAcceptヘッダーでフォーマットを指定する仕様から、途中で変更されたようです。
(参照) Accept header based routing got replaced by a query parameter

準備

ここからはDrupal8インストールが完了してからの具体的な手順を追っていきます。

1.モジュールのインストール

GUIでリソースの各種設定ができる、REST UIモジュールをインストールし、ウェブサービスの各モジュールを有効化します。

ホーム > 管理 > 拡張
WS000000.JPG

(HALとベーシック認証は使わない場合は無効で問題ないと思います)

2.REST UIモジュールのREST resourcesを設定

この記事では最初から有効になっているコンテンツのみを使用します。

ホーム > 管理 > 環境設定 > ウェブサービス > REST
WS000010.JPG

  • 入出力フォーマットはjson, hal+jsonを使用
  • 認証プロバイダーはCookie,ベーシック認証を使用

コンテンツのほかにも、ユーザー、ファイル、タクソノミータームなど様々なリソースが用意されていますので、有効化するだけでいろいろ使えそうです。

3.役割(Role)とユーザの作成

編集者(editor)ロールを追加し、そのロールを付与したユーザを作成します。

ホーム > 管理 > ユーザー > 役割 > 役割の追加
ホーム > 管理 > ユーザー > ユーザーの追加
WS000004.jpg

4.権限の設定

この記事では、コンテンツタイプは記事(Article)のみを使用します。

ホーム > 管理 > ユーザー > 権限
■Nodeの権限設定
WS000005.JPG

  • 編集者は記事の投稿と自分の記事を編集・削除ができる

■RESTful Web Serviceの権限設定
WS000004.JPG

  • GETは誰でも可、POST,PATCH,DELETEは編集者、管理者のみ

実際にAPIを叩いてみる

ここではHTTPクライアントとして、Chrome拡張の DHC - REST/HTTP API Client を使って検証していきます。

まずは最初の記事(article)をDrupalから普通に登録します。
URLエイリアスを「 /my-1st-article 」としておきます。

ホーム > コンテンツの追加 > 記事の作成
article1.png

記事の取得(GET)

先ほど登録した記事はノードIDが1なので、パスは「/node/1」となり、出力するフォーマットをHALにする場合は「_format=hal_json」のパラメータを追加します。(jsonなら_format=jsonです)

/node/1?_format=hal_json
WS000011.JPG

また、URLエイリアスを使用することもできます。

/my-1st-article?_format=json
WS000013.JPG

認証(cookie)およびCSRFトークンの取得

次に、記事の登録・更新・削除を行っていきますが、ここではCookieを使った場合の手順で進めます。
(HTTPクライアントがCookieを管理してくれるので、スクリーンショットでは省略)

  1. ログイン認証(POST送信)
  2. CookieでCSRFトークンの取得(GET送信)
  3. Cookie+CSRFトークンで POST,PATCH,DELETE送信

■LOGIN認証
「/user/login」にPOSTリクエストを送信します。
送信内容は通常のログインフォームから入力したものと大体同じです。
送信時のHTTPステータスコードに少し注意が必要です。

/user/login
WS000015_2.jpg

  • Content-Type: application/x-www-form-urlencoded
  • BODY: name={user id}&pass={password)&form_id=user_login_form

(HTTPステータスコード)

  • 認証成功: 303 See Other
  • ログイン済み: 302 Found
  • 認証失敗: 200 OK

■CSRFトークン
「/rest/session/token」にGETリクエストを送信すると、text/plainな文字列を取得できます。(JSONではありません)

/rest/session/token
WS000025.jpg

記事の登録(POST)

それでは、ログイン後に取得したCSRFトークンを使って記事を登録します。
今回はタイトルと内容をhal+json形式で登録します。

/entity/node
WS000020.JPG

  • Content-Type: application/application/hal+json
  • X-CSRF-Token: 取得したCSRFトークン文字列
  • BODY: {"title":[{"value":"My 2nd article"}],"body":[{"value":"Hello REST API!"}],"type":[{"target_id":"article"}],"_links":{"type":{"href":"http:\/\/d8dev.local\/rest\/type\/node\/article"}}}

記事が登録されているかサイトを確認します。
WS000021.JPG

記事の更新(PATCH)

次に、先ほど登録した記事のタイトルのみを更新しましょう。
先ほど登録した記事のノードIDは2ですので、「/node/2」にPATCHでリクエストを送信します。

/node/2
WS000022.JPG

  • Content-Type: application/application/hal+json
  • X-CSRF-Token: 取得したCSRFトークン文字列
  • BODY: {"title":[{"value":"REST APIで更新!"}],"type":[{"target_id":"article"}],"_links":{"type":{"href":"http:\/\/d8dev.local\/rest\/type\/node\/article"}}}

記事が更新されたことを確認します。
WS000023.JPG

記事の削除(DELETE)

つぎに登録した記事を削除します。

/node/2
WS000026.JPG

  • X-CSRF-Token: 取得したCSRFトークン文字列

記事が削除されたことを確認します。
WS000024.JPG

ベーシック認証を使った記事の登録

ベーシック認証でも記事が登録できるかも試してみましょう。
Authorizationヘッダーに認証情報を付与しますが、使用する開発言語やライブラリなどには大抵便利な仕組みがありますので、そちらを利用してください。

/entity/node
WS000029.JPG

  • Content-Type: application/application/hal+json
  • Authorization: Basic ~
  • BODY: {"title":[{"value":"My 3rd article"}],"body":[{"value":"ベーシック認証で登録!"}],"type":[{"target_id":"article"}],"_links":{"type":{"href":"http:\/\/d8dev.local\/rest\/type\/node\/article"}}}

無事登録できました。
WS000028.JPG

記事一覧の取得(Views REST export)

リソースの一覧を提供する機能として、ViewsのREST出力機能を使います。
(RESTful Web Services/Serializationモジュールが有効であることが前提です)
使い方はすごく簡単で、ビューの基本設定をしたあとに、REST出力を提供するにチェック、RESTのパス(エンドポイント)を設定するだけです。

ホーム > 管理 > サイト構築 > ビュー > ビューを追加
WS000032.JPG

各種出力フォーマットの指定や必要なフィールドのみ出力することもできます。
そのほかにも強力なViewsの各種機能が使えるので、アイデア次第で何でもできそうですね!
WS000033.JPG

最後に、HTTPクライアントでアクセスできるか確認します。
WS000034.JPG

(時間切れ^^;)郵便番号検索APIを作ってみる

REST exportを使って、WEBサービスでは定番の郵便番号検索APIを作るまでの過程をまとめようとしましたが、あえなく時間切れ(^^;
たいしたことはしてませんが、ニーズがありそうなら別の機会に。
(完成形はこんな感じです)
WS000009.JPG

おわりに

いかがだったでしょうか。
実際使ってみると、REST APIが単なるオプション機能としてではなく、設計思想の段階からDrupalコアに組み込まれているんだなぁということが実感できました。
今後、主要なモジュールがDrupal8に対応されてくると、さらに選択肢の幅が広がってきそうなので楽しみですね!
皆さんもぜひ試してみてください。

参考リンク