PHPackages                             apitte/negotiation - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. apitte/negotiation

Abandoned → [contributte/apitte](/?search=contributte%2Fapitte)ArchivedLibrary[API Development](/categories/api)

apitte/negotiation
==================

Content-Negotiation support for Apitte stack

v0.8.0(4y ago)5257.3k↓42.3%23MITPHPPHP &gt;=7.3

Since Nov 23Pushed 5mo ago3 watchersCompare

[ Source](https://github.com/contributte/apitte-negotiation)[ Packagist](https://packagist.org/packages/apitte/negotiation)[ Docs](https://github.com/apitte/negotiation)[ Fund](https://contributte.org/partners.html)[ GitHub Sponsors](https://github.com/f3l1x)[ RSS](/packages/apitte-negotiation/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (8)Versions (12)Used By (3)

[![](https://camo.githubusercontent.com/816bbe8f085637ed0d0f4a4267b5ede82653c0685edff5636fb5f7766dc93a6e/68747470733a2f2f686561746261646765722e76657263656c2e6170702f6769746875622f726561646d652f636f6e74726962757474652f6170697474652d6e65676f74696174696f6e2f3f646570726563617465643d31)](https://camo.githubusercontent.com/816bbe8f085637ed0d0f4a4267b5ede82653c0685edff5636fb5f7766dc93a6e/68747470733a2f2f686561746261646765722e76657263656c2e6170702f6769746875622f726561646d652f636f6e74726962757474652f6170697474652d6e65676f74696174696f6e2f3f646570726563617465643d31)

 [![](https://camo.githubusercontent.com/a8b1cd856d7d396fdebbe46947cc3507490acc267a02361e5e53bb7b820c95c3/68747470733a2f2f62616467656e2e6e65742f62616467652f737570706f72742f6769747465722f6379616e)](https://bit.ly/ctteg) [![](https://camo.githubusercontent.com/86d6416fc04f8bcc3daa7bf881526b9953b9726b1164d05c157c8713e3a73418/68747470733a2f2f62616467656e2e6e65742f62616467652f737570706f72742f666f72756d2f79656c6c6f77)](https://bit.ly/cttfo) [![](https://camo.githubusercontent.com/5d170ab94e6d594609561e16fe0f9e4293968fbd4dfcfafc5e11efc1415ef09c/68747470733a2f2f62616467656e2e6e65742f62616467652f73706f6e736f722f646f6e6174696f6e732f463936383534)](https://contributte.org/partners.html)

 Website 🚀 [contributte.org](https://contributte.org) | Contact 👨🏻‍💻 [f3l1x.io](https://f3l1x.io) | Twitter 🐦 [@contributte](https://twitter.com/contributte)

Disclaimer
----------

[](#disclaimer)

⚠️This project is no longer being maintained. Please use [contributte/apitte](https://github.com/contributte/apitte).Composer[`apitte/negotiation`](https://packagist.org/packages/apitte/negotiation)Version[![](https://camo.githubusercontent.com/76c6babd7811948c8b1a2feaddd3a64e367b37d6ca7f4e9dc43fa68ad9770de8/68747470733a2f2f62616467656e2e6e65742f7061636b61676973742f762f6170697474652f6e65676f74696174696f6e)](https://camo.githubusercontent.com/76c6babd7811948c8b1a2feaddd3a64e367b37d6ca7f4e9dc43fa68ad9770de8/68747470733a2f2f62616467656e2e6e65742f7061636b61676973742f762f6170697474652f6e65676f74696174696f6e)PHP[![](https://camo.githubusercontent.com/1dbe9bd3337776a50ecb201d18332a6263c9a1f12ed26e358e527b62b843245a/68747470733a2f2f62616467656e2e6e65742f7061636b61676973742f7068702f6170697474652f6e65676f74696174696f6e)](https://camo.githubusercontent.com/1dbe9bd3337776a50ecb201d18332a6263c9a1f12ed26e358e527b62b843245a/68747470733a2f2f62616467656e2e6e65742f7061636b61676973742f7068702f6170697474652f6e65676f74696174696f6e)License[![](https://camo.githubusercontent.com/f528a96bf4e0d2ce22cd9158bd77e50b156e9680d459c61ce86b1840a037074c/68747470733a2f2f62616467656e2e6e65742f6769746875622f6c6963656e73652f636f6e74726962757474652f6170697474652d6e65676f74696174696f6e)](https://camo.githubusercontent.com/f528a96bf4e0d2ce22cd9158bd77e50b156e9680d459c61ce86b1840a037074c/68747470733a2f2f62616467656e2e6e65742f6769746875622f6c6963656e73652f636f6e74726962757474652f6170697474652d6e65676f74696174696f6e)Usage
-----

[](#usage)

To install the latest version of `apitte/negotiation` use [Composer](https://getcomposer.org).

```
composer require apitte/negotiation
```

Documentation
-------------

[](#documentation)

Content negotiation for [Apitte](https://github.com/apitte/negotiation).

Transform response entity into response with unified format in dependence on `Accept` header and uri path suffix `/api/v1/users(.json|.xml)`

### Setup

[](#setup)

First of all, setup [core](https://github.com/apitte/core) package and enable `CoreDecoratorPlugin`.

Install and register negotiation plugin

```
composer require apitte/negotiation
```

```
api:
    plugins:
        Apitte\Negotiation\DI\NegotiationPlugin:
```

### Response

[](#response)

Instead of writing data into response body use `$response->withEntity($entity)` so transformers could handle transformation for you.

```
namespace App\Api\V1\Controllers;

use Apitte\Core\Annotation\Controller\ControllerPath;
use Apitte\Core\Annotation\Controller\Method;
use Apitte\Core\Annotation\Controller\Path;
use Apitte\Core\Http\ApiRequest;
use Apitte\Core\Http\ApiResponse;
use Apitte\Negotiation\Http\ArrayEntity;

/**
 * @ControllerPath("/users")
 */
class UsersController extends BaseV1Controller
{

    /**
     * @Path("/")
     * @Method("GET")
     */
    public function index(ApiRequest $request, ApiResponse $response): ApiResponse
    {
        $entity = ArrayEntity::from([
            [
                'id' => 1,
                'firstName' => 'John',
                'lastName' => 'Doe',
                'emailAddress' => 'john@doe.com',
            ],
            [
                'id' => 2,
                'firstName' => 'Elon',
                'lastName' => 'Musk',
                'emailAddress' => 'elon.musk@spacex.com',
            ],
        ]);

        return $response
            ->withStatus(ApiResponse::S200_OK)
            ->withEntity($entity);
    }

}
```

### Entities

[](#entities)

Value objects which are used to create response

- `ArrayEntity` - create from array
- `ObjectEntity` - create from stdClass
- `ScalarEntity` - create from raw data

### Error handling

[](#error-handling)

Negotiations are implemented through an `IErrorDecorator`, which have higher priority than internal `ErrorHandler`so response is created from exception in an `ITransformer` and `ErrorHandler` only log that exception (if you use `PsrLogErrorHandler`)

### Negotiators

[](#negotiators)

Handle request and based on path suffix or request headers call appropriate transformer.

`SuffixNegotiator`

- used for request with path suffix like `/api/v1/users.json` -&gt; transformer for `json` suffix is used

`DefaultNegotiator`

- called when none other transform
- require annotation `@Negotiation(default = true, suffix = "json")` defined on endpoint - transformer for given suffix is looked for

`FallbackNegotiator`

- used last if no other negotiator transformed response
- uses json transformer by default

### Transformers

[](#transformers)

Transformers convert entities and exceptions into response.

`JsonTransformer`

- transform into json

`JsonUnifyTransformer`

- transform into json with unified format

```
api:
    plugins:
        Apitte\Negotiation\DI\NegotiationPlugin:
            unification: true
```

`CsvTransformer`

- transform into csv
- known limitation: data need to be a flat structure

#### Implementing transformer

[](#implementing-transformer)

```
services:
    - factory: App\Api\Transformer\XmlTransformer
      tags: [apitte.negotiator.transformer: [suffix: xml, fallback: true]]
```

- register transformer for suffix `xml`, used for uris like `/api/v1/users.xml`
- if `fallback: true` is defined and none of transformers matched then use that transformer

```
namespace App\Api\Transformer;

use Apitte\Core\Exception\ApiException;
use Apitte\Core\Http\ApiRequest;
use Apitte\Core\Http\ApiResponse;
use Apitte\Core\Http\ResponseAttributes;
use Apitte\Negotiation\Http\ArrayEntity;
use Apitte\Negotiation\Transformer\AbstractTransformer;
use Throwable;

class XmlTransformer extends AbstractTransformer
{

    /**
     * Encode given data for response
     *
     * @param mixed[] $context
     */
    public function transform(ApiRequest $request, ApiResponse $response, array $context = []) : ApiResponse
    {
        if (isset($context['exception'])) {
            return $this->transformError($context['exception'], $request, $response);
        }

        return $this->transformResponse($request, $response);
    }

    protected function transformResponse(ApiRequest $request, ApiResponse $response): ApiResponse
    {
        $data = $this->getEntity($response)->getData();
        $content = $this->dataToXmlString($data);
        $response->getBody()->write($content);

        return $response
            ->withHeader('Content-Type', 'application/xml');
    }

    protected function transformError(Throwable $error, ApiRequest $request, ApiResponse $response): ApiResponse
    {
    	if ($error instanceof ApiException) {
    		$code = $error->getCode();
    		$message = $error->getMessage();
    	} else {
    		$code = 500;
    		$message = 'Application encountered an internal error. Please try again later.';
    	}

        return $response
            ->withStatus($code)
            ->withAttribute(ResponseAttributes::ATTR_ENTITY, ArrayEntity::from([
                'status' => 'error',
                'message' => $message,
            ]));
    }

}
```

Version
-------

[](#version)

StateVersionBranchNettePHPstable`^0.8``master`3.0+`>=7.3`stable`^0.5``master`2.4`>=7.1`Development
-----------

[](#development)

This package was maintained by these authors.

[ ![](https://avatars2.githubusercontent.com/u/538058?v=3&s=80)](https://github.com/f3l1x)---

Consider to [support](https://contributte.org/partners.html) **contributte** development team. Also thank you for being used this package.

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance49

Moderate activity, may be stable

Popularity37

Limited adoption so far

Community21

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 64.2% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~153 days

Recently: every ~267 days

Total

10

Last Release

1714d ago

PHP version history (5 changes)v0.1PHP &gt;= 5.6

v0.4PHP &gt;= 7.1

v0.6.0PHP ^7.2

v0.7.0PHP &gt;=7.2

v0.8.0PHP &gt;=7.3

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/538058?v=4)[Milan Šulc](/maintainers/f3l1x)[@f3l1x](https://github.com/f3l1x)

---

Top Contributors

[![f3l1x](https://avatars.githubusercontent.com/u/538058?v=4)](https://github.com/f3l1x "f3l1x (68 commits)")[![mabar](https://avatars.githubusercontent.com/u/20974277?v=4)](https://github.com/mabar "mabar (28 commits)")[![petrparolek](https://avatars.githubusercontent.com/u/6066243?v=4)](https://github.com/petrparolek "petrparolek (4 commits)")[![vody105](https://avatars.githubusercontent.com/u/22433893?v=4)](https://github.com/vody105 "vody105 (4 commits)")[![josefbenjac](https://avatars.githubusercontent.com/u/6731626?v=4)](https://github.com/josefbenjac "josefbenjac (1 commits)")[![woytam](https://avatars.githubusercontent.com/u/12713483?v=4)](https://github.com/woytam "woytam (1 commits)")

---

Tags

apiapittecontent-negotiationcontributtenegotiationnegotiatonnettenegotiationcontent negotiationapitteview-resolver

###  Code Quality

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/apitte-negotiation/health.svg)

```
[![Health](https://phpackages.com/badges/apitte-negotiation/health.svg)](https://phpackages.com/packages/apitte-negotiation)
```

###  Alternatives

[twilio/sdk

A PHP wrapper for Twilio's API

1.6k92.9M272](/packages/twilio-sdk)[facebook/php-business-sdk

PHP SDK for Facebook Business

90821.9M34](/packages/facebook-php-business-sdk)[meilisearch/meilisearch-php

PHP wrapper for the Meilisearch API

74513.7M114](/packages/meilisearch-meilisearch-php)[google/common-protos

Google API Common Protos for PHP

173103.7M50](/packages/google-common-protos)[hubspot/api-client

Hubspot API client

23914.2M16](/packages/hubspot-api-client)[botman/driver-telegram

Telegram driver for BotMan

92437.3k6](/packages/botman-driver-telegram)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
