Download the PHP package jayanta/laravel-api-versionist without Composer

On this page you can find all versions of the php package jayanta/laravel-api-versionist. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package laravel-api-versionist

Laravel API Versionist

Your API changes. Your controllers don't.

Latest Version on Packagist PHP Version Tests codecov License Total Downloads

Inspired by Stripe's API versioning architecture — you write small transformer classes that describe what changed between versions. The package upgrades old requests and downgrades new responses automatically. Your controllers always speak the latest version.

Supports Laravel 10, 11, 12 & 13 · PHP 8.1–8.5


The problem, in short

You shipped v1. A mobile app depends on it. Now you need v2 with different field names. Your options are: duplicate every controller per version (bug fixes applied N times), scatter if/else version checks everywhere, or use this package — one controller, one version, transformers handle the rest.

A v1 client hits this endpoint and gets back username, role — automatically downgraded by the transformer you wrote once.


How it works

Old request comes in → upgraded to latest → controller processes it → response downgraded back to the client's version. Your controller never changes.


Installation

Laravel auto-discovers the service provider. No manual registration.

Supported versions

Laravel PHP Tested against
13.x 8.3 – 8.5 testbench 11, PHPUnit 12
12.x 8.3 – 8.5 testbench 10, PHPUnit 11
11.x 8.2 – 8.4 testbench 9, PHPUnit 11
10.x 8.1 – 8.4 testbench 8, PHPUnit 10

Quick start

1. Generate a transformer:

2. Define what changed:

3. Register it:

If you leave latest_version as 'v1' after adding a V2Transformer, no transformers will run. Always update this value.

4. Add middleware:

5. Test it:


Transformers in depth

Each transformer describes one version transition. A V2Transformer handles v1→v2. A V3Transformer handles v2→v3. The package chains them automatically.

Fields you don't touch pass through unchanged. A request with age, city, custom_field keeps all of them — transformers only modify what they explicitly reference.

Attribute-based metadata

Instead of overriding version(), description(), and releasedAt(), you can declare the same metadata with the #[ApiVersion] class attribute:

Method overrides always win over the attribute, so existing transformers are unaffected.

Constructor injection

Transformers are resolved through Laravel's service container, so DI works:

Keep DB access in transformers read-only and lightweight. If a transformer needs heavy queries, the version gap is probably too wide for this pattern.


When NOT to use transformers

Transformers handle data shape changes — field renames, restructures, type conversions.

For behavior changes, use the request macros the package provides:

Transformers = structure. Application code = behavior. If your breaking change is behavioral, separate controllers are probably cleaner.


Multi-version example

Three versions, showing the full upgrade/downgrade chain:

Version Fields
v1 username, role, is_active
v2 handle, role, is_active
v3 handle, roles[], status

A v1 client sends: { "username": "janedoe", "role": "admin", "is_active": true }

Upgrade chain:

  1. V2Transformer: username → handle
  2. V3Transformer: role → roles[], is_active → status
  3. Controller receives: { "handle": "janedoe", "roles": ["admin"], "status": "active" }

Downgrade chain (response goes back through V3 then V2):

  1. V3Transformer: roles[] → role, status → is_active
  2. V2Transformer: handle → username
  3. v1 client receives: { "username": "janedoe", "role": "admin", "is_active": true }

Version detection

Four strategies, tried in config order. First match wins.

Strategy Example
url_prefix GET /api/v2/users
header X-Api-Version: v2
query_param GET /api/users?version=v2
accept_header Accept: application/vnd.api+json;version=2

No version detected → falls back to default_version (usually 'v1'). Unknown version in strict mode → HTTP 400.


Configuration reference

Key Default Description
default_version 'v1' Fallback when no version detected
latest_version 'v1' Must match your highest transformer
transformers [] Array of transformer class names
deprecated_versions [] Version → sunset date map ('v1' => '2025-12-31' or 'v1' => ['deprecated_at' => ..., 'sunset' => ...])
rfc_compliant_headers false Emit Sunset as RFC 8594 HTTP-date and Deprecation as RFC 9745 timestamp
strict_mode false true = unknown versions throw HTTP 400
response_data_key 'data' Key to transform in responses. null = entire body
request_data_key null Key to transform in requests. null = entire body
add_version_headers true Adds X-Api-Version and X-Api-Latest-Version headers
detection_strategies [...] Ordered list of detection strategies
header_name 'X-Api-Version' Header name for header strategy
query_param 'version' Param name for query_param strategy
changelog.enabled false Expose version metadata as JSON endpoint
changelog.endpoint '/api/versions' Changelog URL path

Important: The default response_data_key is 'data'. If your controller returns flat JSON (not wrapped in {"data": {...}}), set this to null or transformers won't touch the response.


Response headers

With add_version_headers enabled:

For deprecated versions:

Mark versions as deprecated in config:

Headers follow RFC 8594. Deprecated versions still work normally.

Standards-compliant wire formats

By default the package emits the widely-used legacy formats shown above (Deprecation: true, Sunset as the raw configured date). Enable rfc_compliant_headers to switch to the standards-track formats:

The plain string form of deprecated_versions keeps working in both modes; without a deprecated_at date, Deprecation falls back to true.


Changelog endpoint

Enable changelog.enabled to register a JSON endpoint (route name api-versionist.changelog) that serves the same version metadata as php artisan api:changelog --format=json — minus internal transformer class names:

This is the endpoint the Link: rel="successor-version" deprecation header points clients to.


Request macros

After the middleware runs, every Request gets these:

Useful for version-specific behavior that doesn't belong in transformers:


Artisan commands


Envelope mode

If your API wraps responses in {"data": {...}, "meta": {...}}, set response_data_key to 'data' so transformers only touch the data portion:

Only "data" gets transformed. "meta", "links", pagination — all untouched.

If your controller returns flat JSON, set both to null.


Known limitations

Flat array responses — If you return [{...}, {...}] (a list of objects), the transformer sees the array, not individual items. Wrap lists in {"data": [...]} and use response_data_key => 'data'.

Nested keys — The package transforms one location (top-level or response_data_key). It won't recursively walk {"user": {...}, "company": {...}}. Keep transformable data at one level.

Lossy transforms — Some field changes can't be perfectly reversed. Converting an array to a scalar (e.g. roles[] → role) drops extra elements. Design transforms that round-trip cleanly, or accept the data loss and document it.

When separate controllers are the better choice

This pattern works best for structural changes — field renames, payload reshaping, type conversions.

Consider separate controllers when:

No universally correct approach. Transformers reduce duplication for structural versioning. Separate controllers give clearer isolation when behavior diverges.


Testing

Transformers are plain PHP — test them directly:

For transformers with constructor injection, mock the dependency:

Or validate everything at once: php artisan api:audit


FAQ

Do I need to change my controllers for every version? No. Controllers always return the latest version. You write one transformer per version step.

What if v1 and v3 are completely different? Write one transformer per step. V2Transformer handles v1→v2, V3Transformer handles v2→v3. The package chains them. You never write a combined v1→v3 transformer.

Can I use date-based versions like 2024-01-15? Yes. The parser accepts both numeric (v1, v2.1) and date-based (2024-01-15) formats. Dates are compared chronologically. You can even mix them — date versions sort higher than numeric ones.


Prior art

This pattern was publicly documented by Stripe in 2017 (Brandur Leach), adopted by Intercom in 2018, and open-sourced for Ruby by Keygen. This package brings the same idea to Laravel.

How it compares

Versionist request-migrations api-evolution vermillion
Laravel 10–13 / PHP 8.5 ✅ ❌ (dormant, Laravel ≤6 era) partial partial
Detection strategies (URL/header/Accept/query) ✅ 4 header only header only ✅
RFC 8594 + RFC 9745 deprecation headers ✅ ❌ ❌ ❌
JSON changelog endpoint ✅ ❌ ❌ ❌
Attribute-based registration ✅ ❌ ❌ ❌
Transformer audit CLI (api:audit) ✅ ❌ ❌ ❌
Date-based versions (Stripe-style) ✅ ❌ ❌ ✅

Coming from request-migrations? See the migration guide.


Credits


Contributing

Contributions welcome:

  1. Fork the repository
  2. Create a feature branch
  3. Write tests — all PRs must include tests
  4. Run composer test
  5. Submit a pull request

License

MIT. See LICENSE for details.


All versions of laravel-api-versionist with dependencies

PHP Build Version
Package Version
Requires php Version ^8.1
illuminate/console Version ^10.0|^11.0|^12.0|^13.0
illuminate/contracts Version ^10.0|^11.0|^12.0|^13.0
illuminate/filesystem Version ^10.0|^11.0|^12.0|^13.0
illuminate/http Version ^10.0|^11.0|^12.0|^13.0
illuminate/routing Version ^10.0|^11.0|^12.0|^13.0
illuminate/support Version ^10.0|^11.0|^12.0|^13.0
symfony/http-foundation Version ^6.2|^7.0|^8.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package jayanta/laravel-api-versionist contains the following files

Loading the files please wait ...