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 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.

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.

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));


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'
curl -i -H 'Accept-Language: en' -H 'Accept: application/hal+json'
HTTP/1.1 200 OK
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"