PHPackages                             gaiatools/content-accord - 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. gaiatools/content-accord

ActiveLibrary[API Development](/categories/api)

gaiatools/content-accord
========================

Laravel package for API versioning with composable strategies and generic negotiation dimensions

v0.2.0(3mo ago)01[4 PRs](https://github.com/GaiaTools/content-accord/pulls)MITPHPPHP ^8.3|^8.4|^8.5CI passing

Since Feb 22Pushed 5d agoCompare

[ Source](https://github.com/GaiaTools/content-accord)[ Packagist](https://packagist.org/packages/gaiatools/content-accord)[ Docs](https://github.com/GaiaTools/content-accord)[ RSS](/packages/gaiatools-content-accord/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (26)Versions (20)Used By (0)

Content Accord
==============

[](#content-accord)

Content Accord is a Laravel package for API versioning with composable strategies and a generic negotiation layer. It supports URI, header, and Accept header versioning behind a single fluent API and prepares your application for future negotiation dimensions (locale, format, tenant).

Features
--------

[](#features)

- URI, custom header, or Accept header versioning
- Optional resolver chaining (try multiple strategies in order)
- Configurable missing-version behavior
- Per-route-group fallback when the requested version is missing
- Deprecation headers with sunset and documentation links
- Attribute-driven version metadata on controllers and methods
- Generic negotiation foundation for future dimensions

Requirements
------------

[](#requirements)

- PHP 8.3+
- Laravel 12+ (Laravel 11 and 13 are supported via constraints)

Installation
------------

[](#installation)

```
composer require gaiatools/content-accord
```

Publish the configuration file:

```
php artisan vendor:publish --tag=content-accord-config
```

Configuration
-------------

[](#configuration)

The main configuration lives in `config/content-accord.php` under the `versioning` key.

Key settings:

- `dimensions`: array of dimension services to negotiate
- `strategy`: `uri`, `header`, or `accept`
- `resolver`: custom resolver class/binding for versioning
- `chain`: array of strategies to try in order
- `missing_strategy`: `reject`, `default`, `latest`, or `require`
- `default_version`: used when missing strategy is `default`
- `fallback`: global default for version fallback
- `versions`: registered versions and deprecation metadata

Usage
-----

[](#usage)

### Fluent Route Groups (Recommended)

[](#fluent-route-groups-recommended)

Use `Route::apiVersion()` to declare versioned route groups. The URI prefix is managed automatically based on your configured resolver strategy.

```
use Illuminate\Support\Facades\Route;

Route::apiVersion('1')
    ->prefix('api')
    ->middleware(['content-accord.negotiate'])
    ->group(function () {
        Route::get('/users', [V1\UserController::class, 'index']);
    });

Route::apiVersion('2')
    ->prefix('api')
    ->middleware(['content-accord.negotiate'])
    ->group(function () {
        Route::get('/users', [V2\UserController::class, 'index']);
    });
```

With the URI strategy (default), the above registers at `/api/v1/users` and `/api/v2/users`. With header or Accept strategies, both register at `/api/users`and Content Accord selects the right route at dispatch time.

Deprecation metadata is a fluent chain:

```
Route::apiVersion('1')
    ->prefix('api')
    ->deprecated()
    ->sunsetDate('2026-03-01')
    ->deprecationLink('https://docs.example.com/v1-migration')
    ->middleware(['content-accord.negotiate'])
    ->group(function () {
        Route::get('/users', [V1\UserController::class, 'index']);
    });
```

### Header Strategy

[](#header-strategy)

```
// config/content-accord.php
'versioning' => ['strategy' => 'header'],
```

```
Route::apiVersion('1')
    ->prefix('api')
    ->middleware(['content-accord.negotiate'])
    ->group(function () {
        Route::get('/users', [V1\UserController::class, 'index']);
    });
```

Requests:

```
GET /api/users
Api-Version: 1
```

### Accept Header Strategy

[](#accept-header-strategy)

```
GET /api/users
Accept: application/vnd.myapp.v1+json
```

### Custom Dimensions and Resolvers

[](#custom-dimensions-and-resolvers)

Override the negotiated dimensions or the resolver implementation:

```
use GaiaTools\ContentAccord\Dimensions\VersioningDimension;
use App\Http\Negotiation\LocaleDimension;

'dimensions' => [
    VersioningDimension::class,
    LocaleDimension::class,
],

'versioning' => [
    'resolver' => [
        App\Http\Negotiation\CustomVersionResolver::class,
        GaiaTools\ContentAccord\Resolvers\Version\HeaderVersionResolver::class,
    ],
],
```

Register any custom dimensions/resolvers in the container so they can be resolved.

### Missing Version Behavior

[](#missing-version-behavior)

Configure what happens when a request has no version:

```
'missing_strategy' => 'default',
'default_version' => '1',
```

### Fallback Behavior

[](#fallback-behavior)

Enable fallback globally or per group:

```
// config
'fallback' => false,

// route group override
Route::apiVersion('2')
    ->prefix('api')
    ->fallback()
    ->middleware(['content-accord.negotiate'])
    ->group(function () {
        Route::get('/users', [V2\UserController::class, 'index']);
    });
```

If a request targets v3 but only v2 exists for that endpoint, the v2 route will be selected when fallback is enabled.

Attributes
----------

[](#attributes)

Add version metadata on controllers or methods:

```
use GaiaTools\ContentAccord\Attributes\ApiVersion;
use GaiaTools\ContentAccord\Attributes\MapToVersion;

#[ApiVersion('2')]
class UserController
{
    public function index() {}

    #[MapToVersion('2.1')]
    public function show() {}
}
```

Method-level attributes take precedence over class-level attributes. Attribute versions override the group version in route metadata. Mismatches are logged in local/testing environments.

Deprecation Headers
-------------------

[](#deprecation-headers)

Mark version groups as deprecated and optionally add sunset dates and docs links:

```
Route::apiVersion('1')
    ->prefix('api')
    ->deprecated()
    ->sunsetDate('2026-03-01')
    ->deprecationLink('https://docs.example.com/v1-migration')
    ->middleware(['content-accord.deprecate', 'content-accord.negotiate'])
    ->group(function () {
        Route::get('/users', [V1\UserController::class, 'index']);
    });
```

The `Deprecation`, `Sunset`, and `Link` headers are added automatically when deprecation metadata is present.

Accessing the Negotiated Version
--------------------------------

[](#accessing-the-negotiated-version)

Use the `apiVersion()` helper in controllers or anywhere after the negotiate middleware has run:

```
use GaiaTools\ContentAccord\ValueObjects\ApiVersion;

public function index(): JsonResponse
{
    $version = apiVersion(); // ?ApiVersion
}
```

Or inject `NegotiatedContext` directly:

```
use GaiaTools\ContentAccord\Http\NegotiatedContext;

$version = app(NegotiatedContext::class)->get('version');
```

Testing Utilities
-----------------

[](#testing-utilities)

Use the testing helper to attach API versions to test requests:

```
use GaiaTools\ContentAccord\Testing\Concerns\InteractsWithApiVersion;

class ExampleTest extends TestCase
{
    use InteractsWithApiVersion;

    public function test_example()
    {
        $this->withApiVersion('2')->get('/api/users');
    }
}
```

The helper respects the configured strategy (URI, header, or Accept).

Artisan Command
---------------

[](#artisan-command)

List configured versions and route counts:

```
php artisan api:versions
```

License
-------

[](#license)

MIT

###  Health Score

39

—

LowBetter than 85% of packages

Maintenance91

Actively maintained with recent releases

Popularity1

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 86.4% 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 ~30 days

Total

2

Last Release

100d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/322753aaef9bf95a5274bc8c84210cdd9286e1b0cc359acdd33b91892e7f08db?d=identicon)[GaiaTools](/maintainers/GaiaTools)

---

Top Contributors

[![KnightYoshi](https://avatars.githubusercontent.com/u/6134576?v=4)](https://github.com/KnightYoshi "KnightYoshi (19 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (3 commits)")

---

Tags

apilaravelcontent negotiationapi versioningcontent-accord

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/gaiatools-content-accord/health.svg)

```
[![Health](https://phpackages.com/badges/gaiatools-content-accord/health.svg)](https://phpackages.com/packages/gaiatools-content-accord)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

77022.3M145](/packages/laravel-mcp)[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.6k29.8M142](/packages/laravel-cashier)[api-platform/laravel

API Platform support for Laravel

58170.4k13](/packages/api-platform-laravel)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k15.1M129](/packages/laravel-pulse)[nuwave/lighthouse

A framework for serving GraphQL from Laravel

3.5k11.8M116](/packages/nuwave-lighthouse)

PHPackages © 2026

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