PHPackages                             tiime/api-deprecation-bundle - 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. tiime/api-deprecation-bundle

ActiveSymfony-bundle[API Development](/categories/api)

tiime/api-deprecation-bundle
============================

Symfony bundle for managing API endpoint deprecation with Deprecation, Sunset and Link HTTP headers, including brownout support

11[3 PRs](https://github.com/Tiime-Software/ApiDeprecationBundle/pulls)PHPCI passing

Since Mar 13Pushed 2mo agoCompare

[ Source](https://github.com/Tiime-Software/ApiDeprecationBundle)[ Packagist](https://packagist.org/packages/tiime/api-deprecation-bundle)[ RSS](/packages/tiime-api-deprecation-bundle/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependenciesVersions (16)Used By (0)

 [![logo Tiime](https://camo.githubusercontent.com/5b9879db054f83565b9024fb3f692ffa3c9c0e4ad0756aa1806637fb6f6d5f6f/68747470733a2f2f6173736574732e7469696d652e66722f61757468302d756e6976657273616c2d6c6f67696e2f617070732f6c6f676f5f7469696d652e737667)](https://camo.githubusercontent.com/5b9879db054f83565b9024fb3f692ffa3c9c0e4ad0756aa1806637fb6f6d5f6f/68747470733a2f2f6173736574732e7469696d652e66722f61757468302d756e6976657273616c2d6c6f67696e2f617070732f6c6f676f5f7469696d652e737667)
API Deprecation Bundle

Symfony bundle for managing API endpoint deprecation via standard HTTP headers, with brownout support (planned interruptions). HTTP Headers
------------

[](#http-headers)

HeaderRFCDescription`Deprecation`[RFC 9745](https://www.rfc-editor.org/rfc/rfc9745.html)Indicates when the endpoint was deprecated`Sunset`[RFC 8594](https://www.rfc-editor.org/rfc/rfc8594.html)Indicates when the endpoint will be removed`Link`[RFC 9745 §3](https://www.rfc-editor.org/rfc/rfc9745.html#section-3)Points to deprecation documentation (`rel="deprecation"`)`Retry-After`[RFC 7231 §7.1.3](https://www.rfc-editor.org/rfc/rfc7231#section-7.1.3)Seconds until brownout window ends (brownout 410 responses only)Installation
------------

[](#installation)

```
composer require tiime/api-deprecation-bundle
```

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

[](#configuration)

```
# config/packages/api_deprecation.yaml
api_deprecation:
    enabled: true
    gone_after_sunset: true          # return 410 Gone after the sunset date
    brownout_strategies:
        progressive:
            phases:
                - starts_before: '30 days'   # activates 30 days before sunset
                  cron: '0 10 * * 1'         # every Monday at 10am
                  duration: 15               # for 15 minutes
                - starts_before: '14 days'   # activates 14 days before sunset
                  cron: '0 */4 * * *'        # every 4 hours
                  duration: 30               # for 30 minutes
                - starts_before: '7 days'    # activates 7 days before sunset
                  cron: '0 * * * *'          # every hour
                  duration: 45               # for 45 minutes
```

Usage
-----

[](#usage)

### Simple deprecation

[](#simple-deprecation)

Add the `Deprecation` header to an endpoint:

```
use Tiime\ApiDeprecationBundle\Attribute\ApiDeprecated;

class UserController
{
    #[ApiDeprecated(since: '2024-06-01')]
    public function list(): Response
    {
        // ...
    }
}
```

Response:

```
HTTP/1.1 200 OK
Deprecation: @1717200000

```

### With sunset and link to deprecation documentation

[](#with-sunset-and-link-to-deprecation-documentation)

```
#[ApiDeprecated(
    since: '2024-06-01',
    sunset: '2025-01-01',
    link: 'https://docs.example.com/api/v1/users-deprecation',
)]
public function list(): Response
{
    // ...
}
```

Response:

```
HTTP/1.1 200 OK
Deprecation: @1717200000
Sunset: Wed, 01 Jan 2025 00:00:00 GMT
Link: ; rel="deprecation"; type="text/html"

```

### On an entire controller

[](#on-an-entire-controller)

The attribute can be placed on the class. Methods without their own attribute inherit from the class:

```
#[ApiDeprecated(since: '2024-06-01', sunset: '2025-06-01')]
class LegacyUserController
{
    public function list(): Response { /* ... */ }
    public function show(): Response { /* ... */ }
}
```

A method-level attribute always takes priority over the class-level one.

Brownouts
---------

[](#brownouts)

Brownouts are planned, temporary interruptions of a deprecated endpoint. During a brownout window, the endpoint returns `410 Gone` instead of the normal response. This forces API consumers to migrate to the new endpoint.

A brownout strategy is composed of **phases**. Each phase defines a cron expression, a duration, and how long before sunset it activates. This allows you to progressively increase pressure on consumers as the sunset date approaches.

### Defining a strategy

[](#defining-a-strategy)

```
api_deprecation:
    brownout_strategies:
        progressive:
            phases:
                - starts_before: '30 days'
                  cron: '0 10 * * 1'      # Monday at 10am
                  duration: 15
                - starts_before: '7 days'
                  cron: '0 */2 * * *'     # every 2 hours
                  duration: 30
```

### Referencing the strategy in the attribute

[](#referencing-the-strategy-in-the-attribute)

The `brownout` parameter references the name of a strategy defined in the configuration. A `sunset` date is required when a brownout is configured (phases activate relative to that date).

```
#[ApiDeprecated(
    since: '2024-06-01',
    sunset: '2025-01-01',
    link: 'https://docs.example.com/api/v1/users-deprecation',
    brownout: 'progressive',
)]
public function list(): Response
{
    // ...
}
```

### Behavior during a brownout

[](#behavior-during-a-brownout)

During the brownout window, the response is:

```
HTTP/1.1 410 Gone
Retry-After: 540
Deprecation: @1717200000
Sunset: Wed, 01 Jan 2025 00:00:00 GMT
Link: ; rel="deprecation"; type="text/html"

This endpoint is deprecated and currently unavailable (brownout).

```

Outside the window, the endpoint works normally with deprecation headers.

Behavior after sunset
---------------------

[](#behavior-after-sunset)

If `gone_after_sunset` is enabled (default), the endpoint permanently returns `410 Gone` once the sunset date has passed.

Customizing the error response
------------------------------

[](#customizing-the-error-response)

Two Symfony events are dispatched before the default `410 Gone` response is returned:

- `ApiSunsetEvent` — dispatched when the sunset date has passed
- `ApiBrownoutEvent` — dispatched during a brownout window

An event listener can call `$event->setResponse()` to replace the default 410 with a custom response. Both events expose the `ApiDeprecated` attribute and the deprecation headers that will be added to the response.

### Example: returning a Problem Details response (RFC 9457)

[](#example-returning-a-problem-details-response-rfc-9457)

```
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\JsonResponse;
use Tiime\ApiDeprecationBundle\Event\ApiBrownoutEvent;
use Tiime\ApiDeprecationBundle\Event\ApiSunsetEvent;

#[AsEventListener]
final class DeprecationProblemDetailsListener
{
    public function __invoke(ApiSunsetEvent|ApiBrownoutEvent $event): void
    {
        $response = new JsonResponse([
            'type' => 'https://docs.example.com/errors/gone',
            'title' => 'Gone',
            'status' => 410,
            'detail' => sprintf(
                'This endpoint was deprecated on %s and is no longer available.',
                $event->attribute->since,
            ),
        ], 410, ['Content-Type' => 'application/problem+json']);

        $event->setResponse($response);
    }
}
```

The `$event->headers` array contains the computed deprecation headers (`Deprecation`, `Sunset`, `Link`, `Retry-After`) — they are automatically added to whatever response is returned.

If no listener sets a response, the default `410 Gone` with a plain-text body is returned (backward compatible).

Attribute parameters
--------------------

[](#attribute-parameters)

ParameterTypeDefaultDescription`since``string|null``null`Deprecation date (ISO 8601)`sunset``string|null``null`Removal date (ISO 8601)`link``string|null``null`URL to deprecation documentation (RFC 9745 §3)`brownout``string|null``null`Name of a brownout strategy defined in the configurationRequirements
------------

[](#requirements)

- PHP &gt;= 8.3
- Symfony 6.4 or 7.x or 8.x

Tests
-----

[](#tests)

```
docker compose run --rm php vendor/bin/phpunit
```

License
-------

[](#license)

MIT

###  Health Score

22

—

LowBetter than 21% of packages

Maintenance56

Moderate activity, may be stable

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity22

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% 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.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/5444185?v=4)[Flavien Rodrigues](/maintainers/rflavien)[@rflavien](https://github.com/rflavien)

---

Top Contributors

[![rflavien](https://avatars.githubusercontent.com/u/5444185?v=4)](https://github.com/rflavien "rflavien (13 commits)")

### Embed Badge

![Health badge](/badges/tiime-api-deprecation-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/tiime-api-deprecation-bundle/health.svg)](https://phpackages.com/packages/tiime-api-deprecation-bundle)
```

###  Alternatives

[exsyst/swagger

A php library to manipulate Swagger specifications

35816.3M7](/packages/exsyst-swagger)[hubspot/api-client

Hubspot API client

24015.5M18](/packages/hubspot-api-client)[pocketmine/bedrock-protocol

An implementation of the Minecraft: Bedrock Edition protocol in PHP

172437.8k11](/packages/pocketmine-bedrock-protocol)[botman/driver-telegram

Telegram driver for BotMan

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

PHPackages © 2026

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