Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Api Version Control Laravel Package

reindert-vetter/api-version-control

Laravel package for clean API versioning with version-specific controllers and routes. It detects the requested version from headers or URIs and dispatches requests accordingly, helping maintain backward-compatible endpoints without cluttering your application.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and configure the package in three steps:

composer require reindert-vetter/api-version-control
php artisan vendor:publish --tag=api-version-control

The published config controls how a version is detected and which versions are legal:

// config/api-version-control.php
return [
    'version_parameter' => 'version', // query/route parameter name
    'header'            => 'accept',  // header used for content negotiation
    'strict'            => false,     // false = fall back, true = reject unknown
    'versions'          => ['v1', 'v2'],
];

Apply the middleware to the routes you want versioned:

// routes/api.php
Route::middleware('api.version')->group(function () {
    Route::get('/users', 'UserController@index');
});

The first useful thing to try is versioning a single endpoint with the controller suffix convention: a method named indexV2 serves v2, while index (or indexV1) serves the fallback. Then call it with the configured header:

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

or ?version=v2, depending on which source you enabled. Where to look first: the package README (it is the source of truth for exact facade/helper names), the published config file, and the api.version middleware aliases registered by the service provider. Keep strict => false until you have real clients, then tighten it.

Implementation Patterns

  • Middleware group per API surface. Put api.version on the whole routes/api.php group, not on individual routes, so every endpoint gets consistent resolution and fallback. If you have public and internal APIs, use separate groups with different config or middleware parameters.

  • Suffix convention for endpoint upgrades. index → indexV2 → indexV3 is the lowest-friction path: new versions add methods, old methods remain for older clients. Keep fallbacks deliberate; don't rename the base method once clients depend on it.

  • Branch inside the controller when a whole method isn't warranted. For small differences, resolve the active version once and branch:

    if (\ReindertVetter\ApiVersionControl\Facades\ApiVersion::is('v2')) {
        // v2 shape
    }
    

    Use this for response shape tweaks, not for core business logic — versioning should live at the edge (controllers/resources/requests), not deep in services.

  • Version the inputs too. Form requests are an easy place to branch validation rules (rules() can check ApiVersion::is('v2')). If a v2 request has a renamed field, handle the rename in the request or a small mapper, not in the model.

  • Version the output, not the schema. Keep one database schema and use API Resources/transformers per version. This avoids migrations being driven by API contract changes and keeps the version boundary explicit.

  • Deprecation signalling. When you ship v3, add Deprecation/Sunset response headers for older versions from a small middleware wrapping the version group. Clients see the warning without breaking.

  • Test the contract, not just the code. Write feature tests that set the version header and assert the payload shape per version. A matrix test (v1/v2/v3 × a few endpoints) catches accidental fallbacks and suffix typos.

  • Documentation per version. Generate or maintain OpenAPI specs keyed by version. If you only have one spec, at least annotate which fields are version-gated.

Gotchas and Tips

  • 2.3.3 is an undocumented patch. The release notes are only a compare link with no listed changes, so there is no stated breaking change or feature to adopt. Treat it as a safe patch-level bump, but read the diff (compare/2.3.2...2.3.3) before upgrading a production API — patch releases occasionally contain dependency or middleware tweaks that aren't in the notes.
  • Silent fallbacks hide mistakes. With strict => false, a typo like indexV3 (when only indexV2 exists) falls back to an older method and may return a 200 with the wrong shape. Log the resolved version during development, and use strict => true in tests to catch invalid versions.
  • Version source precedence matters. If both a header and a query parameter can carry the version, define and document which wins. Ambiguity causes "works in Postman, fails in the SDK" bugs.
  • Accept parsing is not just a substring. Accept headers can include media type parameters and multiple values. Send clean headers in tests, and verify how the package handles application/json with no version — it should hit your default, not a 500.
  • Config and route caching. After changing versions or the header name, run php artisan config:clear (and route:clear if you altered route registration). Stale caches make version changes appear to do nothing.
  • Middleware ordering. Put auth/throttle outside the version group and version resolution inside, or the other way around deliberately. If a version-aware response (e.g., deprecation headers) needs to run on errors too, ensure the middleware wraps exception handling appropriately.
  • Extension points. The resolved version is exposed through the package's version resolver/facade; bind or alias it if you need it in services, and wrap the middleware if you need custom resolution (e.g., subdomain-based versioning). Prefer a thin custom middleware over forking the package.
  • Don't version everything at once. Start with the endpoints whose contract is actually changing. Blanket-versioning stable endpoints adds fallback chains and test matrix cost with no client benefit.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log