unirate / slim
Slim Framework 4 integration for the UniRate API — a framework-agnostic PSR-18 client, PSR-15 middleware, and ready-made JSON routes for currency exchange rates, conversion, currencies, and VAT.
Requires
- php: >=8.1
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.1 || ^2.0
- slim/slim: ^4.0
Requires (Dev)
- nyholm/psr7: ^1.8
- php-http/mock-client: ^1.6
- phpunit/phpunit: ^10.5 || ^11.0
- slim/psr7: ^1.6
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is not auto-updated.
Last update: 2026-09-03 04:13:21 UTC
README
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.
Installation
composer require unirate/slim
You also need a PSR-18 HTTP client and PSR-17 factories. For example, with Guzzle:
composer require guzzlehttp/guzzle
Get a free API key at unirateapi.com.
Quick start
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.
Configuration
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', ]);
Routes
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);
Using the client directly
$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; });
Error handling
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.
Rate limits
Free-tier keys are rate limited; a 429 surfaces as RateLimitException.
Testing
composer install ./vendor/bin/phpunit
The suite mocks all HTTP traffic via php-http/mock-client —
no live API calls or key required.
License
MIT — see LICENSE.
Related clients
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.