A Slim Framework 4 integration for the UniRate API — live currency exchange rates, conversion, supported-currency lists, and VAT rates.
It ships three pieces you can use together or separately:
UniRate\Slim\UniRateClient— a framework-agnostic client built on PSR-18 (HTTP client) and PSR-17 (request/URI factories), so it works with any HTTP client (Guzzle, Symfony HttpClient, …) and is trivial to mock.UniRate\Slim\UniRateMiddleware— PSR-15 middleware that attaches the client to the request as an attribute.registerUniRateRoutes()— a helper that adds ready-made JSON routes (/rate,/convert,/currencies,/vat) to your Slim app.
composer require unirate/slimYou also need a PSR-18 HTTP client and PSR-17 factories. For example, with Guzzle:
composer require guzzlehttp/guzzleGet a free API key at unirateapi.com.
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Psr7\HttpFactory;
use Slim\Factory\AppFactory;
use UniRate\Slim\UniRateClient;
use UniRate\Slim\UniRateConfig;
use UniRate\Slim\UniRateMiddleware;
use function UniRate\Slim\registerUniRateRoutes;
$guzzle = new GuzzleClient();
$factory = new HttpFactory();
$client = new UniRateClient(
new UniRateConfig(getenv('UNIRATE_API_KEY')),
$guzzle, // PSR-18 ClientInterface
$factory, // PSR-17 RequestFactoryInterface
$factory, // PSR-17 UriFactoryInterface
);
$app = AppFactory::create();
$app->add(new UniRateMiddleware($client));
registerUniRateRoutes($app); // adds /unirate/rate, /convert, /currencies, /vat
$app->run();See examples/app.php for a complete runnable server.
UniRateConfig takes the API key and an optional base URL, or build it from an
options array:
$config = new UniRateConfig('your-key'); // default base URL
$config = UniRateConfig::fromArray([
'api_key' => 'your-key',
'base_url' => 'https://api.unirateapi.com',
]);registerUniRateRoutes($app, $prefix = '/unirate', ?UniRateClient $client = null)
registers four GET routes returning JSON:
| Route | Query params | Response |
|---|---|---|
{prefix}/rate |
from (default USD), to (optional) |
{"rate": 0.92} or {"rate": {"EUR": 0.92, …}} |
{prefix}/convert |
from (default USD), to (required), amount (default 1) |
{"result": 92.5} |
{prefix}/currencies |
— | {"currencies": ["USD", "EUR", …]} |
{prefix}/vat |
country (optional) |
{"vat": {…}} |
Route handlers resolve the client from the request attribute set by
UniRateMiddleware. If you prefer not to use the middleware, pass the client as
the third argument to make the routes self-contained:
registerUniRateRoutes($app, '/unirate', $client);$rate = $client->getRate('USD', 'EUR'); // 0.92
$allRates = $client->getRate('USD'); // ['EUR' => 0.92, ...]
$converted = $client->convert('EUR', 100, 'USD'); // 92.5
$currencies = $client->getSupportedCurrencies(); // ['USD', 'EUR', ...]
$vat = $client->getVatRates('DE'); // ['country_name' => 'Germany', 'vat_rate' => 19.0]Inside a Slim handler, resolve the client from the request attribute:
use UniRate\Slim\UniRateClient;
use UniRate\Slim\UniRateMiddleware;
$app->get('/price', function ($request, $response) {
/** @var UniRateClient $unirate */
$unirate = $request->getAttribute(UniRateMiddleware::ATTRIBUTE);
$eur = $unirate->convert('EUR', 100, 'USD');
$response->getBody()->write("€{$eur}");
return $response;
});The client throws UniRate\Slim\UniRateException (base), with the HTTP status as
the exception code. Typed subclasses let you catch specific failures:
| Status | Exception | Meaning |
|---|---|---|
| 400 | Exception\InvalidDateException |
Invalid request parameters |
| 401 | Exception\AuthenticationException |
Missing or invalid API key |
| 403 | Exception\ApiException |
Endpoint requires a Pro subscription |
| 404 | Exception\InvalidCurrencyException |
Currency not found or no data available |
| 429 | Exception\RateLimitException |
Rate limit exceeded |
| 503 | Exception\ApiException |
Service unavailable |
| other | Exception\ApiException |
Generic API error (status + body) |
The registered routes map these to JSON error responses that mirror the API
status, e.g. 429 → {"error": "Rate limit exceeded."}.
Historical endpoints (getHistoricalRate) are Pro-gated and return 403
on the free tier.
Free-tier keys are rate limited; a 429 surfaces as RateLimitException.
composer install
./vendor/bin/phpunitThe suite mocks all HTTP traffic via php-http/mock-client —
no live API calls or key required.
MIT — see LICENSE.
Part of the official UniRate client family: Python, Node/TypeScript, Swift, Java, Go, Rust, Ruby, PHP, and .NET, plus framework integrations for Laravel, Symfony, Statamic, WordPress, and more.