コンテントネゴシエーション
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"
}
}
}