kleijnweb/php-api-routing-bundle
Laravel-friendly bundle for building API routing with a structured approach. Helps organize route definitions, controllers, and versioned endpoints into a cleaner setup for small to medium PHP APIs.
Installation Add the package via Composer in your Laravel project (though originally for Symfony, it can be adapted via Laravel’s Symfony bridge):
composer require kleijnweb/php-api-routing-bundle
Note: Since this is a Symfony bundle, you’ll need to manually bridge it with Laravel’s service container or use a Symfony-compatible facade.
Basic Setup
config/openapi_routes.yaml):
paths:
/api/users:
get:
tags: [Users]
summary: Get all users
operationId: getUsers
First Use Case
use Symfony\Component\Routing\Loader\YamlFileLoader;
use Symfony\Component\Routing\RouteCollection;
$loader = new YamlFileLoader();
$collection = $loader->load('config/openapi_routes.yaml');
$router = new Symfony\Component\Routing\Router($collection);
$request = $this->getRequest();
$context = new Symfony\Component\Routing\RequestContext();
$matcher = new Symfony\Component\Routing\Matcher\UrlMatcher($collection, $context);
try {
$matcher->match($request->getPathInfo());
// Proceed if route exists in OpenAPI spec
} catch (\Exception $e) {
abort(404, 'Route not documented in OpenAPI spec.');
}
API Documentation-Driven Routing
// In a Laravel service provider's boot method
$this->app->singleton('openapi.router', function () {
$loader = new YamlFileLoader();
$collection = $loader->load(storage_path('openapi_routes.yaml'));
return new Symfony\Component\Routing\Router($collection);
});
Request Validation
public function handle(Request $request, Closure $next) {
$router = app('openapi.router');
$context = new RequestContext();
$matcher = new UrlMatcher($router->getRouteCollection(), $context);
$matcher->match($request->path());
return $next($request);
}
Register this middleware globally or per-route group (e.g., api).Dynamic Route Generation
$generator = new Symfony\Component\Routing\Generator\UrlGenerator($router, $context);
$url = $generator->generate('getUsers', [], UrlGeneratorInterface::ABSOLUTE_URL);
CI/CD Integration
phpunit or a custom script).php artisan openapi:validate
(Note: Requires custom artisan command to bridge Symfony router with Laravel routes.)IDE Autocompletion
Laravel-Symfony Bridge
symfony/http-foundation and symfony/routing packages to avoid direct bundle integration:
composer require symfony/http-foundation symfony/routing
Router in a Laravel service provider for dependency injection.OpenAPI Schema Validation
zircote/swagger-php to validate request/response schemas:
use Zircote\Swagger\Scanner;
$openapi = Scanner::scan([base_path('routes')]);
$validator = new \Zircote\Swagger\Validator();
$validator->validate($openapi);
Archived Package
darkaonline/l5-swagger (Laravel-focused).nelmio/api-doc-bundle (Symfony).Symfony Dependency Overhead
symfony/routing in isolation to avoid bloat:
composer require symfony/routing --ignore-platform-reqs
YAML/JSON Parsing Quirks
Middleware vs. Controller Validation
$match = $matcher->match($request->path());
\Log::debug('Matched OpenAPI route:', ['route' => $match]);
Route Matching Failures
RouteCollection to verify routes:
dd($router->getRouteCollection()->getResources());
operationId or path definitions in your YAML.Circular Dependencies
php artisan route:cache), clear it after updating OpenAPI specs:
php artisan route:clear
Custom Route Loaders
YamlFileLoader to support additional file formats (e.g., JSON) or remote specs:
class JsonFileLoader extends FileLoader {
public function load($resource, $type = null) { /* ... */ }
}
Laravel Route Integration
// app/Console/Commands/SyncOpenApiRoutes.php
public function handle() {
$openapiRoutes = $this->loadOpenApiRoutes();
foreach ($openapiRoutes as $path => $methods) {
foreach ($methods as $method) {
Route::{$method}($path, fn() => 'OpenAPI Controller');
}
}
}
OpenAPI Server Validation
$request = $this->getRequest();
$router = app('openapi.router');
try {
$router->getMatcher()->match($request->getPathInfo());
// Proceed to Laravel routing
} catch (\Exception $e) {
abort(400, 'Request does not match OpenAPI spec.');
}
Partial Adoption
darkaonline/l5-swagger (Laravel).swagger-api/swagger-ui (UI).Performance
RouteCollection in Laravel’s cache:
$collection = Cache::remember('openapi.routes', now()->addHours(1), function() {
return $loader->load('config/openapi_routes.yaml');
});
Testing
public function testOpenApiRouteCoverage() {
$router = app('openapi.router');
$this->assertTrue($router->getRouteCollection()->has('getUsers'));
}
How can I help you explore Laravel packages today?