コンテントネゴシエーション

HTTPにおいてコンテントネゴシエーション (content negotiation) は、同じ URL に対してさまざまなバージョンのリソースを提供するために使用する仕組みです。BEAR.Sundayではその内のメディアタイプのAcceptと言語のAccept-Languageのサーバーサイドのコンテントネゴシエーションをサポートします。アプリケーション単位またはリソース単位で指定することができます。

インストール

composerでBEAR.Acceptをインストールします。

composer require bear/accept ^0.1

次にAccept*リクエストヘッダーに応じたコンテキストを/var/locale/available.phpに保存します。

<?php
return [
    'Accept' => [
        'text/hal+json' => 'hal-app',
        'application/json' => 'app',
        'cli' => 'cli-hal-app'
    ],
    'Accept-Language' => [ // キーを小文字で
        'ja-jp' => 'ja',
        'ja' => 'ja',
        'en-us' => 'en',
        'en' => 'en'
    ]
];

Acceptキー配列はメディアタイプをキーにしてコンテキストが値にした配列を指定します。cliはコンソールアクセスでのコンテキストでwebアクセスで使われることはありません。

Accept-Languageキー配列は言語をキーにしてコンテキストキーを値した配列を指定します。

アプリケーション

アプリケーション全体でコンテントネゴシエーションを有効にするためにpublic/index.phpを変更します。

<?php
use BEAR\Accept\Accept;

require dirname(__DIR__) . '/vendor/autoload.php';

$accept = new Accept(require dirname(__DIR__) . '/var/locale/available.php');
list($context, $vary) = $accept($_SERVER);

require dirname(__DIR__) . '/bootstrap/bootstrap.php';

上記の設定で例えば以下のAccept*ヘッダーのアクセスのコンテキストはprod-hal-ja-appになります。

Accept: application/hal+json
Accept-Language: ja-JP

この時JaModuleで日本語テキストのための束縛が必要です。詳しくはデモアプリケーションMyVendor.Localeをごらんください。

リソース

リソース単位でコンテントネゴシエーションを行う場合はAcceptModuleモジュールをインストールして@Producesアノテーションを使います。

モジュール

protected function configure()
{
    // ...
    $available = $appDir . '/var/locale/available.php';
    $this->install(new AcceptModule(available));
}

@Producesアノテーション

use BEAR\Accept\Annotation\Produces;

/**
 * @Produces({"application/hal+json", "text/csv"})
 */
public function onGet()

利用可能なメディアタイプを左から優先順位でアノテートします。対応したコンテキストのレンダラーがAOPでセットされ表現が変わります。アプリケーション単位でのネゴシエーションの時と違って、Varyヘッダーを手動で付加する必要はありません。

curlを使ったアクセス

-HオプションでAccept*ヘッダーを指定します。

curl -H 'Accept-Language: en' http://127.0.0.1:8080/
curl -i -H 'Accept-Language: en' -H 'Accept: application/hal+json' http://127.0.0.1:8080/
HTTP/1.1 200 OK
Host: 127.0.0.1:8080
Date: Fri, 11 Aug 2017 08:32:33 +0200
Connection: close
X-Powered-By: PHP/7.1.4
Vary: Accept, Accept-Language
content-type: application/hal+json

{
    "greeting": "Hello BEAR.Sunday",
    "_links": {
        "self": {
            "href": "/index"
        }
    }
}