Skip to content

Commit d18f7cb

Browse files
committed
docs: rewrite README for clarity and discoverability
Refresh the README around a clearer value proposition, with new sections that answer 'What is Swap?', 'When should you use Swap?', 'Why not call an exchange rate API directly?', and 'Which package should I use?'. Replace the introductory provider name-drops and quickstart with a neutral default (european_central_bank, free, no API key) so the example works end-to-end without external accounts. Reorganize the providers table into Public vs Commercial groups and add the registry-identifier column so the string passed to Builder::add() is documented. Simplify the Fixer rows. Fix the stale FlorianvSwapBundle links (now florianv/symfony-swap) and the 'Ukranie' typo. Cross-link to Exchanger, Laravel Swap, and Symfony Swap. Update composer.json description and keywords for Packagist SEO. No runtime changes; public API of Swap and Builder is unchanged.
1 parent 8ca53da commit d18f7cb

2 files changed

Lines changed: 177 additions & 73 deletions

File tree

README.md

Lines changed: 169 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,199 @@
1-
# <img src="https://s3.amazonaws.com/swap.assets/swap_logo.png" height="30px" width="30px"/> Swap
1+
# Swap
22

33
[![Tests](https://github.com/florianv/swap/actions/workflows/tests.yml/badge.svg)](https://github.com/florianv/swap/actions/workflows/tests.yml)
44
[![Psalm](https://github.com/florianv/swap/actions/workflows/psalm.yml/badge.svg)](https://github.com/florianv/swap/actions/workflows/psalm.yml)
55
[![Total Downloads](https://img.shields.io/packagist/dt/florianv/swap.svg?style=flat-square)](https://packagist.org/packages/florianv/swap)
66
[![Version](http://img.shields.io/packagist/v/florianv/swap.svg?style=flat-square)](https://packagist.org/packages/florianv/swap)
77

8-
Swap allows you to retrieve currency exchange rates from various services such as **[Fixer](https://fixer.io/)**, **[Currency Data](https://currencylayer.com)** or **[Exchange Rates Data](https://exchangeratesapi.io/)** and optionally cache the results.
9-
It is integrated to other libraries like [moneyphp/money](https://github.com/moneyphp/money) and provides
10-
a [Symfony Bundle](https://github.com/florianv/FlorianvSwapBundle) and a [Laravel Package](https://github.com/florianv/laravel-swap).
8+
> _The easy-to-use PHP currency conversion library. Retrieve exchange rates from 30 providers, with caching and fallback. Maintained since 2014._
119
12-
## QuickStart
10+
Swap is a mature PHP **currency conversion library** for retrieving and working with exchange rates. It provides a single, easy-to-use API on top of 30 exchange rate providers, ranging from public sources (the European Central Bank, several national banks, exchangerate.host) to commercial **exchange rate APIs** that require an API key. Caching, historical rates, and a fallback chain are built in. Used in real-world PHP applications since 2014.
11+
12+
## What is Swap?
13+
14+
- Swap is a PHP library for currency conversion and exchange rate retrieval.
15+
- It supports 30 exchange rate providers behind a common interface.
16+
- It caches results via PSR-16 SimpleCache.
17+
- It supports historical rates.
18+
- It supports a fallback chain. When a provider errors, the next provider in the chain is tried.
19+
20+
## When should you use Swap?
21+
22+
- Use Swap when you need to retrieve exchange rates in a PHP application: currency conversion workflows, multi-currency pricing, invoice totals, reconciliation, or historical FX data.
23+
- Use the lower-level [Exchanger](https://github.com/florianv/exchanger) library when Swap's defaults are too opinionated and you want finer control over chain composition, caching, or HTTP plumbing.
24+
25+
## Why not call an exchange rate API directly?
26+
27+
You can. Here is what Swap does for you so you don't have to build it again:
28+
29+
- **Provider abstraction.** Swap one provider for another without rewriting application code; all 30 providers expose the same interface.
30+
- **Fallback chain.** Try a primary provider first, fall back to others on error. Unsupported currency pairs are skipped silently.
31+
- **Caching.** PSR-16 SimpleCache integration with per-query TTL and per-query disable.
32+
- **Historical rates.** One method (`historical()`) regardless of the underlying endpoint shape.
33+
- **Typed result objects.** `getValue()`, `getDate()`, `getCurrencyPair()`, `getProviderName()` are uniform across providers, so no per-provider response parsing in your application code.
34+
- **HTTP plumbing.** PSR-18 / PSR-17 friendly, auto-discovered via `php-http/discovery`. Any compliant HTTP client (Symfony HTTP Client, Guzzle, etc.) works without custom wiring.
35+
36+
## Installation
37+
38+
Swap requires PHP 8.2 or newer.
1339

1440
```bash
15-
$ composer require php-http/curl-client nyholm/psr7 php-http/message florianv/swap
41+
composer require florianv/swap symfony/http-client nyholm/psr7
1642
```
1743

44+
`symfony/http-client` is the PSR-18 HTTP client and `nyholm/psr7` provides the PSR-17 factories. Any PSR-18 / PSR-17 implementation works (see the [documentation](doc/readme.md) for alternatives such as Guzzle).
45+
46+
## Quickstart
47+
1848
```php
1949
use Swap\Builder;
2050

21-
// Build Swap
51+
// Build Swap with the European Central Bank (free, no API key required).
2252
$swap = (new Builder())
53+
->add('european_central_bank')
54+
->build();
2355

24-
// Use the Fixer service as first level provider
25-
->add('apilayer_fixer', ['api_key' => 'Get your key here: https://fixer.io/'])
26-
27-
// Use the currencylayer service as first fallback
28-
->add('apilayer_currency_data', ['api_key' => 'Get your key here: https://currencylayer.com'])
29-
30-
// Use the exchangerates service as second fallback
31-
->add('apilayer_exchange_rates_data', ['api_key' => 'Get your key here: https://exchangeratesapi.io/'])
32-
->build();
33-
34-
// Get the latest EUR/USD rate
56+
// EUR → USD exchange rate
3557
$rate = $swap->latest('EUR/USD');
3658

37-
// 1.129
38-
$rate->getValue();
59+
$rate->getValue(); // e.g. 1.0823 (a float)
60+
$rate->getDate()->format('Y-m-d'); // e.g. 2026-04-29
61+
$rate->getProviderName(); // 'european_central_bank'
62+
63+
// Convert an amount using the returned rate
64+
$amountInEUR = 100.00;
65+
$amountInUSD = $amountInEUR * $rate->getValue();
66+
67+
// Retrieve a historical rate
68+
$past = $swap->historical('EUR/USD', new \DateTime('-15 days'));
69+
```
70+
71+
Swap retrieves the rate; your application multiplies the amount by `$rate->getValue()` to perform the conversion.
3972

40-
// 2016-08-26
41-
$rate->getDate()->format('Y-m-d');
73+
## Configuring multiple providers (fallback chain)
4274

43-
// Get the EUR/USD rate 15 days ago
44-
$rate = $swap->historical('EUR/USD', (new \DateTime())->modify('-15 days'));
75+
```php
76+
$swap = (new Builder())
77+
->add('your_primary_provider', ['api_key' => 'YOUR_KEY']) // see Providers below
78+
->add('your_fallback_provider', ['api_key' => 'YOUR_KEY'])
79+
->add('european_central_bank') // free fallback for EUR-base pairs
80+
->build();
4581
```
4682

83+
Providers are tried in order. If a provider does not support the requested currency pair, it is skipped silently. If a provider throws an error, the next provider is tried. If every provider fails, a `ChainException` is thrown with all collected errors.
84+
85+
## Common use cases
86+
87+
- Display localized prices in multi-currency storefronts.
88+
- Compute invoice totals across currencies.
89+
- Reconcile multi-currency ledgers using historical rates.
90+
- Power internal FX dashboards with rate history.
91+
- Build currency conversion infrastructure for fintech and ERP applications.
92+
93+
## Which package should I use?
94+
95+
The Swap ecosystem is a layered toolkit for currency conversion in PHP:
96+
97+
- **Swap.** The easy-to-use, high-level API (this package).
98+
- **Exchanger.** Lower-level, more granular alternative; direct access to the 30 provider implementations and the `ExchangeRateService` interface.
99+
- **Laravel Swap.** Laravel application of Swap.
100+
- **Symfony Swap.** Symfony integration of Swap.
101+
102+
All four packages are MIT-licensed and require PHP 8.2 or newer.
103+
104+
## Providers
105+
106+
Swap supports 30 exchange rate providers via [Exchanger](https://github.com/florianv/exchanger). Pass the **identifier** to `Builder::add()`.
107+
108+
### Public providers (no API key required)
109+
110+
| Service | Identifier | Base | Quote | Historical |
111+
| ------------------------------------------ | ------------------------------------- | -------------- | -------------- | ---------- |
112+
| Bulgarian National Bank | `bulgarian_national_bank` | * | BGN | Yes |
113+
| Central Bank of the Czech Republic | `central_bank_of_czech_republic` | * | CZK | Yes |
114+
| Central Bank of the Republic of Turkey | `central_bank_of_republic_turkey` | * | TRY | Yes |
115+
| Central Bank of the Republic of Uzbekistan | `central_bank_of_republic_uzbekistan` | * | UZS | Yes |
116+
| Cryptonator | `cryptonator` | * (crypto) | * (crypto) | No |
117+
| European Central Bank | `european_central_bank` | EUR | * | Yes |
118+
| exchangerate.host | `exchangeratehost` | * | * | Yes |
119+
| National Bank of Georgia | `national_bank_of_georgia` | * | GEL | Yes |
120+
| National Bank of Romania | `national_bank_of_romania` | (limited list) | (limited list) | Yes |
121+
| National Bank of the Republic of Belarus | `national_bank_of_republic_belarus` | * | BYN | Yes |
122+
| National Bank of Ukraine | `national_bank_of_ukraine` | * | UAH | Yes |
123+
| Russian Central Bank | `russian_central_bank` | * | RUB | Yes |
124+
| WebserviceX | `webservicex` | * | * | No |
125+
126+
### Commercial providers (require an API key)
127+
128+
| Service | Identifier | Base | Quote | Historical |
129+
| ------------------------------- | ------------------------------ | -------------------- | ----- | ---------- |
130+
| AbstractAPI | `abstract_api` | * | * | Yes |
131+
| coinlayer | `coin_layer` | * (crypto) | * | Yes |
132+
| Currency Converter API | `currency_converter` | * | * | Yes |
133+
| Currency Data (APILayer) | `apilayer_currency_data` | USD (free), * (paid) | * | Yes |
134+
| CurrencyDataFeed | `currency_data_feed` | * | * | No |
135+
| currencylayer (direct) | `currency_layer` | USD (free), * (paid) | * | Yes |
136+
| Exchange Rates Data (APILayer) | `apilayer_exchange_rates_data` | USD (free), * (paid) | * | Yes |
137+
| exchangeratesapi (direct) | `exchange_rates_api` | USD (free), * (paid) | * | Yes |
138+
| fastFOREX.io | `fastforex` | USD (free), * (paid) | * | No |
139+
| Fixer (APILayer) | `apilayer_fixer` | EUR (free), * (paid) | * | Yes |
140+
| Fixer (direct) | `fixer` | EUR (free), * (paid) | * | Yes |
141+
| 1Forge | `forge` | * | * | No |
142+
| Open Exchange Rates | `open_exchange_rates` | USD (free), * (paid) | * | Yes |
143+
| xChangeApi.com | `xchangeapi` | * | * | Yes |
144+
| Xignite | `xignite` | * | * | Yes |
145+
146+
You can also add your own provider by implementing the `Exchanger\Contract\ExchangeRateService` interface and passing the instance to `Builder::addExchangeRateService()`.
147+
148+
## Caching, HTTP client, and error handling
149+
150+
- **Caching.** Swap uses PSR-16 `SimpleCache`. Configure once on the builder:
151+
152+
```php
153+
$swap = (new Builder())->useSimpleCache($psr16Cache)->add('european_central_bank')->build();
154+
```
155+
156+
Disable caching for a single query: `$swap->latest('EUR/USD', ['cache' => false])`.
157+
Override the TTL for a single query: `$swap->latest('EUR/USD', ['cache_ttl' => 3600])`.
158+
159+
- **HTTP client.** Any PSR-18 client (`symfony/http-client`, `php-http/guzzle7-adapter`, etc.) is supported and auto-discovered via `php-http/discovery`. To pass an explicit instance, use `Builder::useHttpClient()`.
160+
161+
- **Errors.** When every configured provider has either skipped (unsupported pair) or thrown, Swap raises an `Exchanger\Exception\ChainException` containing all collected exceptions.
162+
47163
## Documentation
48164

49-
The documentation for the current branch can be found [here](https://github.com/florianv/swap/blob/master/doc/readme.md).
50-
51-
## Services
52-
53-
Here is the list of the currently implemented services:
54-
55-
| Service | Base Currency | Quote Currency | Historical |
56-
|---------------------------------------------------------------------------|----------------------|----------------|----------------|
57-
| [Fixer](https://fixer.io/) | EUR (free, no SSL), * (paid) | * | Yes |
58-
| [Currency Data](https://currencylayer.com) | USD (free), * (paid) | * | Yes |
59-
| [Exchange Rates Data](https://exchangeratesapi.io/) | USD (free), * (paid) | * | Yes |
60-
| [Abstract](https://www.abstractapi.com) | * | * | Yes |
61-
| [coinlayer](https://coinlayer.com) | * Crypto (Limited standard currencies) | * Crypto (Limited standard currencies) | Yes |
62-
| [Fixer](https://fixer.io) | EUR (free, no SSL), * (paid) | * | Yes |
63-
| [Currency Data](https://currencylayer.com) | USD (free), * (paid) | * | Yes |
64-
| [exchangeratesapi](https://exchangeratesapi.io) | USD (free), * (paid) | * | Yes |
65-
| [European Central Bank](https://www.ecb.europa.eu/home/html/index.en.html) | EUR | * | Yes |
66-
| [National Bank of Georgia](https://nbg.gov.ge) | * | GEL | Yes |
67-
| [National Bank of the Republic of Belarus](https://www.nbrb.by) | * | BYN (from 01-07-2016),<br>BYR (01-01-2000 - 30-06-2016),<br>BYB (25-05-1992 - 31-12-1999) | Yes |
68-
| [National Bank of Romania](http://www.bnr.ro) | RON, AED, AUD, BGN, BRL, CAD, CHF, CNY, CZK, DKK, EGP, EUR, GBP, HRK, HUF, INR, JPY, KRW, MDL, MXN, NOK, NZD, PLN, RSD, RUB, SEK, TRY, UAH, USD, XAU, XDR, ZAR | RON, AED, AUD, BGN, BRL, CAD, CHF, CNY, CZK, DKK, EGP, EUR, GBP, HRK, HUF, INR, JPY, KRW, MDL, MXN, NOK, NZD, PLN, RSD, RUB, SEK, TRY, UAH, USD, XAU, XDR, ZAR | Yes |
69-
| [National Bank of Ukranie](https://bank.gov.ua) | * | UAH | Yes |
70-
| [Central Bank of the Republic of Turkey](http://www.tcmb.gov.tr) | * | TRY | Yes |
71-
| [Central Bank of the Republic of Uzbekistan](https://cbu.uz) | * | UZS | Yes |
72-
| [Central Bank of the Czech Republic](https://www.cnb.cz) | * | CZK | Yes |
73-
| [Central Bank of Russia](https://cbr.ru) | * | RUB | Yes |
74-
| [Bulgarian National Bank](http://bnb.bg) | * | BGN | Yes |
75-
| [WebserviceX](http://www.webservicex.net) | * | * | No |
76-
| [1Forge](https://1forge.com) | * (free but limited or paid) | * (free but limited or paid) | No |
77-
| [Cryptonator](https://www.cryptonator.com) | * Crypto (Limited standard currencies) | * Crypto (Limited standard currencies) | No |
78-
| [CurrencyDataFeed](https://currencydatafeed.com) | * (free but limited or paid) | * (free but limited or paid) | No |
79-
| [Open Exchange Rates](https://openexchangerates.org) | USD (free), * (paid) | * | Yes |
80-
| [Xignite](https://www.xignite.com) | * | * | Yes |
81-
| [Currency Converter API](https://www.currencyconverterapi.com) | * | * | Yes (free but limited or paid) |
82-
| [xChangeApi.com](https://xchangeapi.com) | * | * | Yes |
83-
| [fastFOREX.io](https://www.fastforex.io) | USD (free), * (paid) | * | No |
84-
| [exchangerate.host](https://www.exchangerate.host) | * | * | Yes |
85-
| Array | * | * | Yes |
86-
87-
Additionally, you can add your own services as long as they implement the `ExchangeRateService` interface.
88-
89-
## Integrations
90-
91-
- A Symfony Bundle [FlorianvSwapBundle](https://github.com/florianv/FlorianvSwapBundle)
92-
- A Laravel Package [florianv/laravel-swap](https://github.com/florianv/laravel-swap)
165+
The full documentation is in [`doc/readme.md`](doc/readme.md), and is also published at [florianv.github.io/swap](https://florianv.github.io/swap/).
93166

94-
## Credits
167+
## Related packages
95168

96-
- [Florian Voutzinos](https://github.com/florianv)
97-
- [All Contributors](https://github.com/florianv/swap/contributors)
169+
The Swap ecosystem:
170+
171+
- [**Swap**](https://github.com/florianv/swap): easy-to-use PHP currency conversion library.
172+
- [**Exchanger**](https://github.com/florianv/exchanger): lower-level, more granular alternative; direct access to provider implementations.
173+
- [**Laravel Swap**](https://github.com/florianv/laravel-swap): Laravel application of Swap.
174+
- [**Symfony Swap**](https://github.com/florianv/symfony-swap): Symfony integration of Swap.
175+
176+
## Sponsorship
177+
178+
The Swap ecosystem is open to selected sponsorships from exchange rate API providers and financial infrastructure companies.
179+
180+
Sponsorship can include:
181+
182+
- Documentation visibility
183+
- Integration examples
184+
- Ecosystem-level visibility across Swap, Exchanger, Laravel Swap, and Symfony Swap
185+
186+
For inquiries, contact the maintainer via [GitHub](https://github.com/florianv).
187+
188+
## Contributing
189+
190+
Issues and pull requests are welcome. Please see the existing [issues](https://github.com/florianv/swap/issues) before opening a new one.
98191

99192
## License
100193

101194
The MIT License (MIT). Please see [LICENSE](https://github.com/florianv/swap/blob/master/LICENSE) for more information.
195+
196+
## Credits
197+
198+
- [Florian Voutzinos](https://github.com/florianv)
199+
- [All contributors](https://github.com/florianv/swap/contributors)

composer.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
{
22
"name": "florianv/swap",
3-
"description": "Exchange rates library for PHP",
3+
"description": "PHP currency conversion library for retrieving exchange rates from 30 providers, with caching and fallback.",
44
"license": "MIT",
55
"keywords": [
66
"currency",
77
"money",
88
"rate",
99
"conversion",
10-
"exchange rates"
10+
"exchange rates",
11+
"currency conversion",
12+
"currency conversion library",
13+
"php currency conversion",
14+
"exchange rate api",
15+
"forex",
16+
"forex api"
1117
],
1218
"authors": [
1319
{

0 commit comments

Comments
 (0)