Content Negotiation

In HTTP,(content negotiation) is a mechanism used to provide various versions of resources for the same URL. BEAR.Sunday supports server-side content negotiation of media type ‘Accept’ and ‘Accept-Language’ of language. It can be specified on an application basis or resource basis.

Install

Install BEAR.Accept with composer.

composer require bear/accept ^0.1

Next, save the context corresponding to the Accept * request header in /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'
    ]
];

The Accept key array specifies an array whose context is a value with the media type as a key. cli is not used in web access in the context of console access.

The Accept-Language key array specifies an array with the context key as key for the language.

By Application

Change public/index.php to enable content negotiation throughout the application.

<?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';

For example, in the above setting, the access context of the following Accept* header will be prod-hal-ja-app.

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

At this time JaModule requires binding for Japanese text. For details, refer to the demo application MyVendor.Locale.

By Resource

To do content negotiation on a resource basis, install the AcceptModule module and use the @Produces annotation.

Module Install

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

@Produces

use use BEAR\Accept\Annotation\Produces;

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

Annotate the available media types from left to right. The renderer of the corresponding context is set in AOP and the expression changes. Unlike negotiation on a per-application basis, you do not need to manually add the Vary header.

Access using curl

Specify the Accept* header with the -H option.

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"
        }
    }
}