Skip to content

Commit

Permalink
feat: added Abstract api service
Browse files Browse the repository at this point in the history
  • Loading branch information
florianv committed Apr 11, 2021
1 parent 5b986a5 commit 5d9aadf
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 9 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Looking for a simple library based on Exchanger ? Check out [Swap](https://githu

## Sponsors :heart_eyes:

We are proudly supported by the following echange rate providers offering *free plans up to 1,000 requests per day*:
We are proudly supported by the following echange rate providers offering *free plans*:

<img src="https://s3.amazonaws.com/swap.assets/fixer_icon.png?v=2" height="20px" width="20px"/> **[Fixer](https://fixer.io)**

Expand All @@ -35,6 +35,8 @@ Here is the complete list of the currently implemented services:
|---------------------------------------------------------------------------|----------------------|----------------|----------------|
| [Fixer](https://fixer.io) | EUR (free, no SSL), * (paid) | * | Yes |
| [currencylayer](https://currencylayer.com) | USD (free), * (paid) | * | Yes |
| [exchangeratesapi](https://exchangeratesapi.io) | USD (free), * (paid) | * | Yes |
| [Abstract](https://www.abstractapi.com) | * | * | No |
| [coinlayer](https://coinlayer.com) | * Crypto (Limited standard currencies) | * Crypto (Limited standard currencies) | Yes |
| [European Central Bank](https://www.ecb.europa.eu/home/html/index.en.html) | EUR | * | Yes |
| [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 |
Expand Down
6 changes: 4 additions & 2 deletions doc/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,13 +378,15 @@ use Exchanger\Service\RussianCentralBank;
use Exchanger\Service\Cryptonator;
use Exchanger\Service\CoinLayer;
use Exchanger\Service\XchangeApi;
use Exchanger\Service\AbstractApi;

$service = new Chain([
new Fixer($client, null, ['access_key' => 'YOUR_KEY']),
new CurrencyLayer($client, null, ['access_key' => 'access_key', 'enterprise' => false]),
new ExchangeRatesApi(),
new AbstractApi($client, null, ['api_key' => 'api_key']),
new CoinLayer($client, null, ['access_key' => 'access_key', 'paid' => false]),
new EuropeanCentralBank(),
new ExchangeRatesApi(),
new NationalBankOfRomania(),
new CentralBankOfRepublicTurkey(),
new CentralBankOfCzechRepublic(),
Expand Down Expand Up @@ -415,7 +417,7 @@ $service = new Chain([

### Sponsors

We are proudly supported by the following echange rate providers offering *free plans up to 1,000 requests per day*:
We are proudly supported by the following echange rate providers offering *free plans*:

<img src="https://s3.amazonaws.com/swap.assets/fixer_icon.png?v=2" height="20px" width="20px"/> **[Fixer](https://fixer.io)**

Expand Down
88 changes: 88 additions & 0 deletions src/Service/AbstractApi.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

declare(strict_types=1);

/*
* This file is part of Exchanger.
*
* (c) Florian Voutzinos <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Exchanger\Service;

use Exchanger\Contract\ExchangeRateQuery;
use Exchanger\Contract\HistoricalExchangeRateQuery;
use Exchanger\Exception\UnsupportedCurrencyPairException;
use Exchanger\StringUtil;
use Exchanger\Contract\ExchangeRate as ExchangeRateContract;

/**
* Abstract API Service.
*
* @author Florian Voutzinos <[email protected]>
*/
final class AbstractApi extends HttpService
{
const API_KEY_OPTION = 'api_key';

const LATEST_URL = 'https://currency.abstractapi.com/v1/latest?api_key=%s&base=%s';

/**
* {@inheritdoc}
*/
public function processOptions(array &$options): void
{
if (!isset($options[self::API_KEY_OPTION])) {
throw new \InvalidArgumentException('The "api_key" option must be provided to use abstractapi.com');
}
}

/**
* {@inheritdoc}
*/
public function getExchangeRate(ExchangeRateQuery $exchangeRateQuery): ExchangeRateContract
{
$currencyPair = $exchangeRateQuery->getCurrencyPair();

$url = sprintf(
self::LATEST_URL,
$this->options[self::API_KEY_OPTION],
$currencyPair->getBaseCurrency()
);

$content = $this->request($url);
$data = StringUtil::jsonToArray($content);

if (isset($data['exchange_rate'][$currencyPair->getQuoteCurrency()])) {
$date = new \DateTime(
$data['last_updated_utc'],
new \DateTimeZone('UTC')
);

$rate = $data['exchange_rate'][$currencyPair->getQuoteCurrency()];

return $this->createRate($currencyPair, (float) $rate, $date);
}

throw new UnsupportedCurrencyPairException($currencyPair, $this);
}

/**
* {@inheritdoc}
*/
public function supportQuery(ExchangeRateQuery $exchangeQuery): bool
{
return !$exchangeQuery instanceof HistoricalExchangeRateQuery;
}

/**
* {@inheritdoc}
*/
public function getName(): string
{
return 'abstract_api';
}
}
9 changes: 3 additions & 6 deletions src/Service/Cryptonator.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use Exchanger\Contract\ExchangeRateQuery;
use Exchanger\Exception\Exception;
use Exchanger\HistoricalExchangeRateQuery;
use Exchanger\StringUtil;
use Exchanger\Contract\ExchangeRate as ExchangeRateContract;

Expand Down Expand Up @@ -62,15 +63,11 @@ public function getExchangeRate(ExchangeRateQuery $exchangeQuery): ExchangeRateC
}

/**
* Tells if the service supports the exchange rate query.
*
* @param ExchangeRateQuery $exchangeQuery
*
* @return bool
* {@inheritdoc}
*/
public function supportQuery(ExchangeRateQuery $exchangeQuery): bool
{
return true;
return !$exchangeQuery instanceof HistoricalExchangeRateQuery;
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/Service/Registry.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public static function getServices(): array
'coin_layer' => CoinLayer::class,
'xchangeapi' => XchangeApi::class,
'fastforex' => FastForex::class,
'abstract_api' => AbstractApi::class,
];
}
}
13 changes: 13 additions & 0 deletions tests/Fixtures/Service/AbstractApi/success.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"base": "USD",
"last_updated_unix": "1593614038",
"last_updated_utc": "Wed, 01 Jul 2020 14:33:58 +0000",
"exchange_rate": {
"EUR": 0.889758,
"CAD": 1.35676,
"AUD": 1.44753,
"GBP": 0.807175,
"CHF": 0.946451,
"CNY": 7.06409
}
}
75 changes: 75 additions & 0 deletions tests/Tests/Service/AbstractApiTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

declare(strict_types=1);

/*
* This file is part of Exchanger.
*
* (c) Florian Voutzinos <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Exchanger\Tests\Service;

use Exchanger\Exception\Exception;
use Exchanger\HistoricalExchangeRateQuery;
use Exchanger\CurrencyPair;
use Exchanger\ExchangeRateQuery;
use Exchanger\Service\AbstractApi;

class AbstractApiTest extends ServiceTestCase
{
/**
* @test
*/
public function it_does_not_support_all_queries()
{
$service = new AbstractApi($this->createMock('Http\Client\HttpClient'), null, ['api_key' => 'secret']);

$this->assertTrue($service->supportQuery(new ExchangeRateQuery(CurrencyPair::createFromString('EUR/USD'))));
$this->assertFalse($service->supportQuery(new HistoricalExchangeRateQuery(CurrencyPair::createFromString('EUR/USD'), new \DateTime())));
}

/**
* @test
*/
public function it_throws_an_exception_when_rate_not_supported()
{
$this->expectException(Exception::class);
$url = 'https://currency.abstractapi.com/v1/latest?api_key=secret&base=USD';
$content = file_get_contents(__DIR__.'/../../Fixtures/Service/AbstractApi/success.json');
$service = new AbstractApi($this->getHttpAdapterMock($url, $content), null, ['api_key' => 'secret']);

$service->getExchangeRate(new ExchangeRateQuery(CurrencyPair::createFromString('USD/ZZZ')));
}

/**
* @test
*/
public function it_fetches_a_rate()
{
$pair = CurrencyPair::createFromString('USD/GBP');
$url = 'https://currency.abstractapi.com/v1/latest?api_key=secret&base=USD';
$content = file_get_contents(__DIR__.'/../../Fixtures/Service/AbstractApi/success.json');
$service = new AbstractApi($this->getHttpAdapterMock($url, $content), null, ['api_key' => 'secret']);

$rate = $service->getExchangeRate(new ExchangeRateQuery($pair));

$this->assertSame(0.807175, $rate->getValue());
$this->assertEquals('2020-07-01', $rate->getDate()->format('Y-m-d'));
$this->assertEquals('abstract_api', $rate->getProviderName());
$this->assertSame($pair, $rate->getCurrencyPair());
}

/**
* @test
*/
public function it_has_a_name()
{
$service = new AbstractApi($this->createMock('Http\Client\HttpClient'), null, ['api_key' => 'secret']);

$this->assertSame('abstract_api', $service->getName());
}
}

0 comments on commit 5d9aadf

Please sign in to comment.