insideapps / api-proxy
Provides basics api proxy for symfony http client based
2.1.1
2025-05-26 11:56 UTC
Requires
- php: >=8.1
- symfony/cache: ^6.4
- symfony/dotenv: ^6.4
- symfony/http-client: ^6.4
Requires (Dev)
- phpunit/phpunit: >=9.5
- roave/security-advisories: dev-latest
- symfony/var-dumper: ^6.4
README
A lightweight and flexible proxy layer for making API requests using Symfony's HTTP client components.
Requirements
- PHP >= 8.1
- Symfony/HttpClient (6.4+)
- Symfony/Cache (6.4+)
- Symfony/DotEnv (6.4+)
- Symfony/Serializer (6.4+)
Installation
composer require insideapps/api-proxy
Features
- Bearer token authentication
- Automatic token refresh
- Request caching
- Support for all common HTTP methods (GET, POST, PUT, DELETE)
- Configurable timeout and retry options
Usage
Basic Setup
Bearer Token Authentication
use InsideApps\ApiProxy\Factory\ProxyFactory;
// Create a client with Bearer token authentication
$apiClient = ProxyFactory::bearerClient(
baseUrl: 'https://api.example.com/',
authUrl: 'https://api.example.com/auth',
credentialItems: [
'username' => 'your_username',
'password' => 'your_password'
]
);
// Make a simple GET request
$response = $apiClient->get('users/123');
// Access response data
$userData = $response->toArray();
Caching Responses
Enable caching for GET requests to improve performance:
// Parameters:
// 1. Endpoint
// 2. Enable cache (boolean)
// 3. Cache lifetime in seconds (default: 3600)
$response = $apiClient->get('products', true, 60);
HTTP Methods
The client supports all common HTTP methods:
// GET request
$response = $apiClient->get('users');
// POST request with data
$response = $apiClient->post('users', [
'name' => 'John Doe',
'email' => 'john@example.com'
]);
// PUT request
$response = $apiClient->put('users/123', [
'name' => 'Updated Name'
]);
// DELETE request
$response = $apiClient->delete('users/123');
Advanced Configuration
You can configure additional options when creating the client:
$apiClient = ProxyFactory::bearerClient(
baseUrl: 'https://api.example.com/',
authUrl: 'https://api.example.com/auth',
credentialItems: [
'username' => 'your_username',
'password' => 'your_password'
],
options: [
'timeout' => 30,
'max_retries' => 3
]
);
Symfony Integration
Environment Variables
Add the required environment variables to your .env
file:
# .env
# Common API settings
API_BASE_URL=https://api.example.com
API_AUTH_URL=https://api.example.com/auth
API_USERNAME=your_username
API_PASSWORD=your_password
# Multiple API endpoints can be configured
USERS_API_BASE_URL=https://users-api.example.com
USERS_API_AUTH_URL=https://users-api.example.com/auth
USERS_API_USERNAME=users_username
USERS_API_PASSWORD=users_password
PRODUCTS_API_BASE_URL=https://products-api.example.com
PRODUCTS_API_AUTH_URL=https://products-api.example.com/auth
PRODUCTS_API_USERNAME=products_username
PRODUCTS_API_PASSWORD=products_password
Service Configuration
You can easily integrate the API Proxy into your Symfony application by defining repositories as services in your services.yaml
file:
# config/services.yaml
parameters:
# Define common API parameters
app.api.base_url: '%env(API_BASE_URL)%'
app.api.auth_url: '%env(API_AUTH_URL)%'
app.api.username: '%env(API_USERNAME)%'
app.api.password: '%env(API_PASSWORD)%'
# Define specific API parameters for different endpoints
app.users_api.base_url: '%env(USERS_API_BASE_URL)%'
app.users_api.auth_url: '%env(USERS_API_AUTH_URL)%'
app.users_api.username: '%env(USERS_API_USERNAME)%'
app.users_api.password: '%env(USERS_API_PASSWORD)%'
app.products_api.base_url: '%env(PRODUCTS_API_BASE_URL)%'
app.products_api.auth_url: '%env(PRODUCTS_API_AUTH_URL)%'
app.products_api.username: '%env(PRODUCTS_API_USERNAME)%'
app.products_api.password: '%env(PRODUCTS_API_PASSWORD)%'
services:
# Factory service
InsideApps\ApiProxy\Factory\ProxyFactory:
public: true
# Abstract repository service
App\Repository\AbstractApiRepository:
abstract: true
# User repository service
App\Repository\UserRepository:
arguments:
$baseUrl: '%app.users_api.base_url%'
$authUrl: '%app.users_api.auth_url%'
$username: '%app.users_api.username%'
$password: '%app.users_api.password%'
$serializer: '@serializer'
$endpoint: 'users'
# Product repository service
App\Repository\ProductRepository:
arguments:
$baseUrl: '%app.products_api.base_url%'
$authUrl: '%app.products_api.auth_url%'
$username: '%app.products_api.username%'
$password: '%app.products_api.password%'
$serializer: '@serializer'
$endpoint: 'products'
Creating an Abstract Repository
Here's an example of creating an abstract repository class that uses the API Proxy with Symfony's Serializer component:
<?php
namespace App\Repository;
use InsideApps\ApiProxy\ApiProxy;
use InsideApps\ApiProxy\Factory\ProxyFactory;
use Symfony\Component\Serializer\SerializerInterface;
/**
* Abstract API repository with common functionality
*/
abstract class AbstractApiRepository
{
protected ApiProxy $apiClient;
protected SerializerInterface $serializer;
protected string $endpoint;
protected string $entityClass;
/**
* Create a new repository instance with API client
*/
public function __construct(
string $baseUrl,
string $authUrl,
string $username,
string $password,
SerializerInterface $serializer,
string $endpoint,
string $entityClass = null
) {
// Create the API client in the constructor
$this->apiClient = ProxyFactory::bearerClient(
baseUrl: $baseUrl,
authUrl: $authUrl,
credentialItems: [
'username' => $username,
'password' => $password
]
);
$this->serializer = $serializer;
$this->endpoint = $endpoint;
$this->entityClass = $entityClass ?? 'App\\Entity\\' . ucfirst(substr($endpoint, -1) === 's' ? substr($endpoint, 0, -1) : $endpoint);
}
/**
* Get all resources
*/
public function findAll(bool $useCache = true, int $cacheLifetime = 3600): array
{
$response = $this->apiClient->get($this->endpoint, $useCache, $cacheLifetime);
return $this->serializer->deserialize($response, $this->entityClass . '[]', 'json');
}
/**
* Find a resource by ID
*/
public function find(int $id, bool $useCache = true, int $cacheLifetime = 3600): ?object
{
$response = $this->apiClient->get($this->endpoint . '/' . $id, $useCache, $cacheLifetime);
return $this->serializer->deserialize($response, $this->entityClass, 'json');
}
/**
* Create a new resource
*/
public function create(array $data): object
{
$response = $this->apiClient->post($this->endpoint, $data);
return $this->serializer->deserialize($response, $this->entityClass, 'json');
}
/**
* Update an existing resource
*/
public function update(int $id, array $data): object
{
$response = $this->apiClient->put($this->endpoint . '/' . $id, $data);
return $this->serializer->deserialize($response, $this->entityClass, 'json');
}
/**
* Delete a resource
*/
public function delete(int $id): bool
{
$this->apiClient->delete($this->endpoint . '/' . $id);
return true;
}
}
Implementing a Concrete Repository
<?php
namespace App\Repository;
/**
* User API repository
*/
class UserRepository extends AbstractApiRepository
{
// You can override methods or add custom ones specific to users
/**
* Find users by role
*/
public function findByRole(string $role, bool $useCache = true): array
{
$response = $this->apiClient->get($this->endpoint . '/role/' . $role, $useCache);
return $this->serializer->deserialize($response, $this->entityClass . '[]', 'json');
}
}
Using the Repository in a Controller
<?php
namespace App\Controller;
use App\Repository\UserRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class UserController extends AbstractController
{
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
#[Route('/api/users', name: 'api_users_index', methods: ['GET'])]
public function index(): JsonResponse
{
$users = $this->userRepository->findAll();
return $this->json($users);
}
#[Route('/api/users/{id}', name: 'api_users_show', methods: ['GET'])]
public function show(int $id): JsonResponse
{
$user = $this->userRepository->find($id);
return $this->json($user);
}
#[Route('/api/users', name: 'api_users_create', methods: ['POST'])]
public function create(Request $request): JsonResponse
{
$data = json_decode($request->getContent(), true);
$user = $this->userRepository->create($data);
return $this->json($user, 201);
}
#[Route('/api/users/role/{role}', name: 'api_users_by_role', methods: ['GET'])]
public function findByRole(string $role): JsonResponse
{
$users = $this->userRepository->findByRole($role);
return $this->json($users);
}
}
License
MIT