以前弊社のエンジニア小林がRESTful Web Services と REST UIで始めるDrupal8 REST API入門ということで、REST APIについてブログをあげてくださっていました。

今回はそれを利用し、httpClientクラスを用いて既存のWeb APIへリクエストする方法についてご紹介したいと思います。

題材としてPHPでQiita api v2を触ってみるという記事を参考にさせていただきました。

PHPにはcurlという関数があり、このcurl関数を使用してWeb APIを実行していると思います。この題材もそのように行っております。

Drupalでもcurl関数を使用することは出来ますが、標準でhttpClientクラスが使用できます。ですので、こちらを利用して今回はQiitaに投稿した記事の情報を取得をhttpClientクラス用いて実施したいと思います。


httpClientクラス

まずhttpClientクラスについて説明いたします。

httpClientはDrupal 8から使用可能になったクラスで、Drupal 7ではdrupal_http_request()が用いられていたかと思います。

Drupal 8からはGuzzle HTTP Clientライブラリが変わって追加されました。

GuzzleとはPHPのHTTPクライアントで、HTTPリクエストを簡単に実現することができるライブラリのことです。

ですので、httpClientはこのGuzzleのラッパーとしての役割を担っているクラスになります。

簡単ではありますが、これがhttpClientクラスの概要となっております。


では早速ですが、題材を例にhttpClientクラスを用いてQiitaに記事の投稿と記事の内容を取得するラッパーAPIの実装を行っていきます。

下準備といたしまして、

などの記事をご参照ください。

まずは最初に全てのコードを記載しておきます。

今回は趣旨にあったところをだけを順番に説明していきます。

<?php

namespace Drupal\get_qiita_article_info_api\Plugin\rest\resource;

use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use GuzzleHttp\Exception\GuzzleException;

/**
 * Qiita APIを使って投稿情報を取得するAPI.
 *
 * @RestResource(
 *   id = "get_qiita_article_info",
 *   label = "Qiita APIを使って投稿情報を取得するAPI",
 *   uri_paths = {
 *     "canonical" = "/api/get-qiita-article-info"
 *   }
 * )
 */
class Example extends ResourceBase {

 /**
  * QiitaのベースURL.
  */
  const QIITA_API_BASE_URL = "https://qiita.com/api/v2";

 /**
  * アクセストークン
  */
  const ACCESS_TOKEN = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

  /**
   * Qiita APIを使って自分の投稿情報を取得するAPI.
   *
   * @return \Drupal\rest\ResourceResponse
   *   リソースレスポンス.
   */
  public function get() {

    try {
      // 記事の情報を取得するAPIのURL
      $url = self::QIITA_API_BASE_URL . '/authenticated_user/items';

      // Qiita APIを使って自分の投稿情報を取得.
      $client = \Drupal::httpClient();
      try {
        $response = $client->request('GET', $url, [
          'headers' => [
            'Content-Type' => 'application/json',
            'Authorization' => 'Bearer ' . self::ACCESS_TOKEN,
          ],
        ]);
      }
      catch (GuzzleException $e) {
        throw new \Exception($e->getMessage());
      }

      $result = json_decode($response->getBody(), TRUE);
      $data = [
        'status' => 'success',
        'title' => $result[0]['title'],
        // 改行コードが入るため取り除く.
        'body' => trim($result[0]['body']),
      ];

      $status = 200;
    }
    catch (\Exception $e) {
      $status = 500;
      $data = [
        'status' => 'error',
        'message' => $e->getMessage(),
      ];
    }

    $resource_response = new ResourceResponse($data, $status);
    $resource_response->addCacheableDependency(['#cache' => ['max-age' => 0]]);
    return $resource_response;
  }

}


httpClientクラスの利用方法

DrupalからリクエストするにはまずhttpClientクラスをインスタンス化します。

$client = \Drupal::httpClient();

次に

  $response = $client->request('GET', $url, [
    'headers' => [
      'Content-Type' => 'application/json',
      'Authorization' => 'Bearer ' . self::ACCESS_TOKEN,
    ],
  ]);

httpClientクラスをインスタンス化したことで、request()が使用可能となり、こちらにリクエストする情報を記載していきます。

目的に応じて、request('GET')request('POST')というように記載しますが、request()を使用しなくても、

// GETの場合
$response = $client->get()

// POSTの場合
$response = $client->post()

としてもリクエストできます。ただし、上記のように記載した場合、次に説明する例外処理で使用できるものが変わってきます。これは後ほど記載させていただきます。

リクエストする内容にはまずheader情報を記載します。Qiita APIの仕様上、アクセストークンを含めなければならないのでこちらも記載します。

どのようなものを記載しなければ行けないのかなどについては、Qiita APIをご参照ください。


例外処理

httpClientクラスを使用する場合は、try / catchで例外を処理する必要があります。

request()を使用した場合GuzzleExceptionが使用できるので、以下のように記載します。

      catch (GuzzleException $e) {
        throw new \Exception($e->getMessage());
      }

get()やpost()を使用した場合はGuzzleExceptionが使用できないため、下記のように記載します。

      catch (RequestException $e) {
        throw new \Exception($e->getMessage());
      }

RequestException以外にも、下記のものが使用できますが、基本的にはエラーを単純に処理して記録するしてくれるRequestExceptionとするので十分かと思います。

BadResponseException.php
ClientException.php
ConnectException.php
RequestException.php
SeekException.php
ServerException.php
TooManyRedirectsException.php
TransferException.php

例外処理まで記載できたら、jsonで取得したデータをデコードさせて、投稿した記事のタイトルと本文の内容を取得します。

取得できているか確認するために、Googleの拡張機能であるRestlet Client - REST API Testingを用いてテストするか、直接Web上で実行してください。

実行が出来れば以下のようにレスポンスがあるかと思います。

拡張機能


終わりに

いかがでしたでしょうか。今回Drupal側から外部APIよりデータを取得してその内容を返却するというラッパーAPIの実装を初めて行い、それを通してここに記載したことを学びました。

APIとは何かなど、文章として読んでいてもイメージしづらかった部分が今回を通して明確になり、少しだけ成長できたのではないかと実感することができました。

インプットするだけでなく、アウトプットも積極的に行って新しく学んだこと自分の中に定着させて行こうと思います。