Installation
composer require "cos/rest-client-bundle": "dev-master"
Register the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3):
Cos\RestClientBundle\CosRestClientBundle::class => ['all' => true],
Basic Configuration
Add minimal config in config/packages/cos_rest_client.yaml (Symfony 4+):
cos_rest_client:
clients:
default: { baseUri: 'https://api.example.com' }
First Use Case: Define a REST Resource Interface Create an interface with annotations to define endpoints:
namespace App\Rest;
use Cos\RestClientBundle\Annotation\Endpoint;
use Cos\RestClientBundle\Annotation\Path;
interface UserClientInterface
{
/**
* @Endpoint(method="GET", path="/users/{id}")
* @Path("id", param="id")
*/
public function getUser(int $id);
}
Generate Proxy Client Use the bundle’s command to generate a proxy client:
php bin/console cos:rest-client:generate App\Rest\UserClientInterface
This creates a service (user_client) ready for dependency injection.
Defining REST Clients
@Endpoint, @Path, @Query, @Form, etc.interface ProductClientInterface
{
/**
* @Endpoint(method="POST", path="/products")
* @Query("category", param="category")
* @Form("data", param="productData")
*/
public function createProduct(string $category, array $productData);
}
Dependency Injection Inject the generated client into services/controllers:
class UserController extends AbstractController
{
public function __construct(private UserClientInterface $userClient) {}
public function show(int $id)
{
$user = $this->userClient->getUser($id);
// ...
}
}
Handling Responses
Use @Json to automatically decode JSON responses:
/**
* @Endpoint(method="GET", path="/posts")
* @Json
*/
public function getPosts(): array;
Dynamic Clients
Configure multiple clients in config/packages/cos_rest_client.yaml:
cos_rest_client:
clients:
api_v1: { baseUri: 'https://api.example.com/v1' }
api_v2: { baseUri: 'https://api.example.com/v2' }
Generate proxies for each and inject the specific client where needed.
Authentication Use Guzzle middleware or bundle config to add auth headers:
cos_rest_client:
clients:
auth_client:
baseUri: 'https://secure-api.example.com'
middleware: ['auth_middleware'] # Custom middleware service ID
Error Handling Extend the bundle’s proxy generator to add custom error handling:
// src/Rest/Exception/ApiException.php
class ApiException extends \RuntimeException {}
Override the proxy generator to throw ApiException on HTTP errors.
Testing Mock the client in tests using PHPUnit:
$mockClient = $this->createMock(UserClientInterface::class);
$mockClient->method('getUser')->willReturn(['id' => 1, 'name' => 'Test']);
$this->container->set('user_client', $mockClient);
Dynamic Paths
Use @Path with regex for flexible routing:
/**
* @Endpoint(method="GET", path="/users/{id:\d+}")
* @Path("id", param="id")
*/
public function getUser(int $id);
Outdated Bundle
Annotation Processing
@AnnotationReader. If misconfigured, endpoints won’t generate.annotation_reader is correctly set in config:
cos_rest_client:
annotation_reader: annotation_reader_service_id
Proxy Generation
src/Rest directory is in autoload:
// composer.json
"autoload": {
"psr-4": {
"App\\": "src/",
"Cos\\RestClientBundle\\": "vendor/cos/rest-client-bundle/"
}
}
Caching Proxies
php bin/console cos:rest-client:generate App\Rest\UserClientInterface --output=src/Rest/Generated
Guzzle Middleware
services:
auth_middleware:
class: App\Rest\Middleware\AuthMiddleware
arguments: ['%env(API_KEY)%']
tags: ['cos_rest_client.middleware']
Check Generated Proxies
Inspect var/cache/dev/ for generated proxy classes to verify annotations are parsed correctly.
Enable Guzzle Debugging Add Guzzle’s debug middleware temporarily:
// config/packages/cos_rest_client.yaml
cos_rest_client:
clients:
debug_client:
baseUri: 'https://api.example.com'
middleware: ['guzzle.http_debug_stack']
Annotation Validation Use PHPStan or Psalm to validate annotations before generation:
vendor/bin/phpstan analyse src --level=5
Symfony Cache Clear After config changes, clear the cache:
php bin/console cache:clear
Custom Proxy Generator Override the generator to add features (e.g., OpenAPI docs):
// src/Rest/Generator/CustomProxyGenerator.php
class CustomProxyGenerator extends \Cos\RestClientBundle\Generator\ProxyGenerator
{
protected function generateMethod(): string
{
// Custom logic
}
}
Update the service config to use your generator.
Dynamic Base URIs Use environment variables for base URIs:
cos_rest_client:
clients:
dynamic_client: { baseUri: '%env(API_BASE_URL)%' }
Event Listeners Attach listeners to modify requests/responses:
// src/Rest/EventListener/ApiListener.php
class ApiListener implements \Cos\RestClientBundle\EventListener\ApiEventSubscriberInterface
{
public function onRequest(\Cos\RestClientBundle\Event\RequestEvent $event)
{
$event->getRequest()->setHeader('X-Custom-Header', 'value');
}
}
Register the listener in services:
services:
api_listener:
class: App\Rest\EventListener\ApiListener
tags: ['cos_rest_client.event_subscriber']
Logging Log requests/responses via a subscriber:
class LoggingSubscriber implements \Cos\RestClientBundle\EventListener\ApiEventSubscriberInterface
{
public function onResponse(\Cos\RestClientBundle\Event\ResponseEvent $event)
{
\Monolog\Logger::getInstance()->info(
'API Response',
['status' => $event->getResponse()->getStatusCode()]
);
}
}
How can I help you explore Laravel packages today?