Install the Package
composer require jane-php/open-api-2
Generate Client from OpenAPI Spec
Place your OpenAPI 2.0 spec (e.g., api-spec.yaml) in your project.
Run the generator:
vendor/bin/jane openapi:generate api-spec.yaml --output=app/Generated
This creates a PSR7/PSR18-compatible client in app/Generated/.
Integrate with Laravel
Bind the generated client to Laravel’s service container in AppServiceProvider:
use Generated\Client;
use Nyholm\Psr7\Factory\Psr17Factory;
public function register()
{
$this->app->singleton(Client::class, function ($app) {
$factory = new Psr17Factory();
return new Client(
$factory,
$factory,
$factory,
$factory,
config('services.api.base_uri') // Optional: Configure base URI
);
});
}
Make Your First API Call
use Generated\Client;
use Illuminate\Support\Facades\Http;
// Option 1: Direct usage
$client = app(Client::class);
$response = $client->get('/users/{id}', ['id' => 1]);
// Option 2: Laravel HTTP facade (if using PSR18 adapter)
$response = Http::withOptions(['base_uri' => config('services.api.base_uri')])
->get('/users/1');
Handle Responses
if ($response->getStatusCode() === 200) {
$data = json_decode($response->getBody(), true);
// Process data
} else {
throw new \RuntimeException('API request failed');
}
Pattern: Bind generated clients as Laravel services for dependency injection.
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->bind(Client::class, function ($app) {
$factory = new Psr17Factory();
$client = new Client(
$factory,
$factory,
$factory,
$factory,
config('services.api.base_uri')
);
// Add middleware (e.g., auth, logging)
$client = $client->withMiddleware([
new \Generated\Middleware\AuthMiddleware(config('services.api.token')),
]);
return $client;
});
}
Use Case: Inject the client into controllers or services:
use Generated\Client;
class UserController extends Controller
{
public function __construct(private Client $client) {}
public function show($id)
{
$response = $this->client->get('/users/{id}', ['id' => $id]);
// ...
}
}
Pattern: Extend generated clients with Laravel middleware.
// app/Http/Kernel.php
protected $middlewareGroups = [
'api' => [
\App\Http\Middleware\ValidateApiSpec::class,
\Generated\Middleware\AuthMiddleware::class,
],
];
// Custom middleware for generated clients
class ValidateApiSpec
{
public function handle($request, Closure $next)
{
// Validate request against OpenAPI spec
return $next($request);
}
}
Use Case: Wrap generated clients with middleware for cross-cutting concerns:
$client = app(Client::class)
->withMiddleware([
new \App\Http\Middleware\LogApiRequests(),
new \App\Http\Middleware\RetryFailedRequests(),
]);
Pattern: Use Laravel’s HTTP facade with a PSR18 adapter (e.g., Guzzle).
// config/services.php
'api' => [
'base_uri' => env('API_BASE_URI'),
'client' => \GuzzleHttp\Client::class,
],
// In a service
use Illuminate\Support\Facades\Http;
class ApiService
{
public function fetchUsers()
{
return Http::withOptions([
'base_uri' => config('services.api.base_uri'),
'handler' => new \GuzzleHttp\HandlerStack(),
])->get('/users');
}
}
Use Case: Leverage Laravel’s HTTP facade for familiar syntax while using generated clients under the hood.
Pattern: Bind generated models to Laravel’s Eloquent or API resources.
// app/Http/Resources/UserResource.php
namespace App\Http\Resources;
use Generated\Client\Model\User;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray($request)
{
$user = new User();
$user->id = $this->id;
$user->name = $this->name;
// Map Laravel model to generated model
return $user;
}
}
Use Case: Convert API responses to Laravel-compatible formats.
Pattern: Centralize API configuration in config/services.php.
'api' => [
'base_uri' => env('API_BASE_URI', 'https://api.example.com'),
'timeout' => 30,
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . env('API_TOKEN'),
],
],
Use Case: Pass config to generated clients:
$client = new Client(
$factory,
$factory,
$factory,
$factory,
config('services.api.base_uri'),
config('services.api.timeout'),
config('services.api.headers')
);
Pattern: Mock PSR18 clients in tests.
use Generated\Client;
use Nyholm\Psr7\Factory\Psr17Factory;
use Nyholm\Psr7\Response;
use PHPUnit\Framework\TestCase;
class ClientTest extends TestCase
{
public function testGetUsers()
{
$factory = new Psr17Factory();
$client = new Client($factory, $factory, $factory, $factory);
// Mock PSR18 client
$mockClient = $this->createMock(\Psr\Http\Client\ClientInterface::class);
$mockClient->method('sendRequest')
->willReturn(new Response(200, [], json_encode(['users' => []])));
// Inject mock (advanced: use DI container or reflection)
$reflection = new \ReflectionClass($client);
$property = $reflection->getProperty('client');
$property->setAccessible(true);
$property->setValue($client, $mockClient);
$response = $client->get('/users');
$this->assertEquals(200, $response->getStatusCode());
}
}
Use Case: Unit test generated clients without hitting external APIs.
Pattern: Auto-generate clients in CI/CD pipelines.
# .github/workflows/generate.yml
name: Generate API Clients
on: [push]
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-php@v3
with:
php-version: '8.2'
- run: composer install
- run: vendor/bin/jane openapi:generate api-spec.yaml --output=app/Generated
- run: git add app/Generated
- run: git diff --quiet || git commit -m "Regenerate API clients"
- run: git push
Use Case: Keep generated clients in sync with the OpenAPI spec.
OpenAPI 2.0 Only
openapi-client-php instead.vendor/bin/jane openapi:validate spec.yaml before generation.Generated Code Overrides
app/Generated) and add it to .gitignore if you prefer manual control.PSR18 Dependency
composer require guzzlehttp/guzzle php-http/guzzle9-adapter
Circular References in Models
User references Profile, which references User) may cause generation failures.How can I help you explore Laravel packages today?