Skip to content

Commit

Permalink
Merge pull request #15 from evertharmeling/postcodes
Browse files Browse the repository at this point in the history
Make use of HTTPlug and implemented the /postcodes call
  • Loading branch information
Evert Harmeling authored Jan 5, 2017
2 parents faf2c54 + bf19113 commit ba24222
Show file tree
Hide file tree
Showing 10 changed files with 264 additions and 121 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
language: php

php:
- 5.4
- 5.5
- 5.6
- 7.0
- 7.1

before_script:
- composer install --dev
- composer install

script: phpunit --coverage-text

Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# CHANGELOG

## 3.0.0

* Dropped direct usage of Guzzle and now make use of [HTTPPlug](http://httplug.io/), see README.
* Added `getPostcodes()` call, to get postcodes based on provided `latitude, longitude`. Note that this call is only available with a premium account.

## 2.0.0

* Rewrite to support postcodeapi.nu version 2
Expand Down
53 changes: 49 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ by [Freshheads](https://www.freshheads.com) and will be maintained in sync with
Requirements
------------

FHPostcodeAPIClient works with PHP 5.4.0 or up. This library is dependent on the awesome [Guzzle](http://guzzlephp.org/) HTTP client library. Guzzle 5
version is used instead of the new Guzzle 6, as Guzzle 6 requires the php version to be higher than 5.5.0.
FHPostcodeAPIClient works with PHP 5.5.0 or up. This library depends on the [HTTPPlug](http://httplug.io/), see http://docs.php-http.org/en/latest/httplug/introduction.html.

Installation
------------
Expand All @@ -37,11 +36,57 @@ require_once 'vendor/autoload.php';

// initiate client
$apiKey = 'replace_with_your_own_api_key';
$client = new \FH\PostcodeAPI\Client(new \GuzzleHttp\Client(), $apiKey);
// In this example we made use of the Guzzle6 as HTTPClient in combination with an HTTPPlug compatible adapter.
$client = new \FH\PostcodeAPI\Client(
new Http\Adapter\Guzzle6\Client(
new GuzzleHttp\Client([
'headers' => [
'X-Api-Key' => $apiKey
]
])
)
);

// call endpoints
$response = $client->getAddresses('5041EB', 21);
$response = $client->getAddress('0855200000061001');

// Note that this call is only available with a premium account
$response = $client->getPostcodes('51.566405', '5.077171');
```

Note that to be able to run the example above you should have ran the following command, to have Guzzle6 and the Adapter available.

```bash
composer require php-http/guzzle6-adapter
```

Within Symfony project
----------------------

We recommend to use [Guzzle](https://github.com/guzzle/guzzle), to be able to use Guzzle in combination with the PostcodeApiClient you should also make use of the
[Guzzle6Adapter](https://github.com/php-http/guzzle6-adapter). By running the following command you automatically install Guzzle aswel.

```bash
composer require php-http/guzzle6-adapter
```

And add the following service definitions:
```yaml
project.http.guzzle.client:
class: GuzzleHttp\Client
arguments:
- { headers: { X-Api-Key: 'replace_with_your_own_api_key' } }

project.http.adapter.guzzle.client:
class: Http\Adapter\Guzzle6\Client
arguments:
- '@project.http.guzzle.client'

project.client.postal_code:
class: FH\PostcodeAPI\Client
arguments:
- '@project.http.adapter.guzzle.client'
```
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/freshheads/fhpostcodeapiclient/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
You should now be able use the `project.client.postal_code` service to make requests to the PostcodeAPI.
15 changes: 13 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,25 @@
],
"require": {
"php": ">=5.4.0",
"guzzlehttp/guzzle": "^5.3"
"php-http/httplug": "^1.1",
"guzzlehttp/psr7": "^1.3"
},
"require-dev": {
"phpunit/phpunit": "^4.3.5|^5.0",
"php-http/mock-client": "^0.3.0"
},
"suggest": {
"php-http/guzzle6-adapter": "An HTTPlug adapter for the Guzzle 6 HTTP client"
},
"autoload": {
"psr-0": { "FH\\PostcodeAPI": "lib/" }
},
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
"dev-master": "3.0.x-dev"
}
},
"scripts": {
"test": "./vendor/phpunit/phpunit/phpunit --coverage-text"
}
}
137 changes: 83 additions & 54 deletions lib/FH/PostcodeAPI/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,58 @@
namespace FH\PostcodeAPI;

use FH\PostcodeAPI\Exception\CouldNotParseResponseException;
use GuzzleHttp\Client as HTTPClient;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\ResponseInterface;
use FH\PostcodeAPI\Exception\InvalidApiKeyException;
use FH\PostcodeAPI\Exception\ServerErrorException;
use GuzzleHttp\Psr7\Request;
use Http\Client\HttpClient;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
* Client library for postcodeapi.nu 2.0 web service.
*
* @author Gijs Nieuwenhuis <[email protected]>
* @author Evert Harmeling <[email protected]>
*/
class Client
{
/** @var string */
const BASE_URI = 'https://postcode-api.apiwise.nl';
const POSTCODES_SORT_DISTANCE = 'distance';

/**
* @var HTTPClient
* @var null|string
*/
private $httpClient;
private $url = 'https://postcode-api.apiwise.nl';

/**
* @param ClientInterface $httpClient
* @param string $apiKey Required API key for authenticating client
* @var string
*/
public function __construct(ClientInterface $httpClient, $apiKey)
{
$this->httpClient = $this->prepareClient($httpClient, $apiKey);
}
private $version = 'v2';

/**
* @param ClientInterface $client
* @param string $apiKey
*
* @return HTTPClient
* @var HttpClient
*/
private function prepareClient(ClientInterface $client, $apiKey)
private $httpClient;


public function __construct(HttpClient $httpClient, $url = null)
{
if ($client->getDefaultOption('timeout') === null) {
$client->setDefaultOption('timeout', 5.0);
if (null !== $url) {
$this->url = $url;
}

$client->setDefaultOption('headers/X-Api-Key', $apiKey);

return $client;
$this->httpClient = $httpClient;
}

/**
* @param string|null $postcode
* @param string|null $number
* @param int $from
*
* @return \StdClass
* @return \stdClass
*/
public function getAddresses($postcode = null, $number = null, $from = 0)
{
return $this->get('/v2/addresses/', [
return $this->get('/addresses/', [
'postcode' => $postcode,
'number' => $number,
'from' => $from
Expand All @@ -69,61 +64,95 @@ public function getAddresses($postcode = null, $number = null, $from = 0)
/**
* @param string $id
*
* @return \StdClass
* @return \stdClass
*/
public function getAddress($id)
{
return $this->get("/v2/addresses/{$id}");
return $this->get(sprintf('/addresses/%s', $id));
}

/**
* @param string $latitude
* @param string $longitude
* @param string $sort
*
* @return \stdClass
*/
public function getPostcodesByCoordinates($latitude, $longitude, $sort = self::POSTCODES_SORT_DISTANCE)
{
return $this->get('/postcodes/', [
'coords' => [
'latitude' => $latitude,
'longitude' => $longitude
],
'sort' => $sort
]);
}

/**
* @param string $path
* @param array $queryParams
* @param array $params
*
* @return \StdClass
* @return \stdClass
*
* @throws RequestException
*/
private function get($path, array $queryParams = array())
private function get($path, array $params = [])
{
$url = self::BASE_URI . $path;
$request = $this->createHttpGetRequest($this->buildUrl($path), $params);

$request = $this->createHttpRequest('GET', $url, $queryParams);
$response = $this->httpClient->sendRequest($request);

$response = $this->httpClient->send($request);

return $this->parseResponse($response);
return $this->parseResponse($response, $request);
}

/**
* @param ResponseInterface $response
*
* @return \StdClass
*
* @throws CouldNotParseResponseException
* @param string $path
* @return string
*/
private function parseResponse(ResponseInterface $response)
private function buildUrl($path)
{
$out = json_decode((string) $response->getBody());

if (json_last_error() !== JSON_ERROR_NONE) {
throw new CouldNotParseResponseException('Could not parse resonse', $response);
}

return $out;
return sprintf('%s/%s%s', $this->url, $this->version, $path);
}

/**
* @param string $method
* @param string $path
* @param string $url
* @param array $queryParams
*
* @return Request
*/
private function createHttpRequest($method, $path, array $queryParams = array())
private function createHttpGetRequest($url, array $params = [])
{
$path = $path . (count($queryParams) > 0 ? '?' . http_build_query($queryParams) : '');
$url .= (count($params) > 0 ? '?' . http_build_query($params, null, '&', PHP_QUERY_RFC3986) : '');

return new Request('GET', $url);
}

/**
* @param ResponseInterface $response
*
* @return \stdClass
*
* @throws CouldNotParseResponseException
*/
private function parseResponse(ResponseInterface $response, RequestInterface $request)
{
$result = json_decode((string) $response->getBody()->getContents());

if (json_last_error() !== JSON_ERROR_NONE) {
throw new CouldNotParseResponseException('Could not parse response', $response);
}

if (property_exists($result, 'error')) {
switch ($result->error) {
case 'API key is invalid.':
throw new InvalidApiKeyException();
case 'An unknown server error occured.':
throw ServerErrorException::fromRequest($request);
}
}

return $this->httpClient->createRequest($method, $path);
return $result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

namespace FH\PostcodeAPI\Exception;

use GuzzleHttp\Message\ResponseInterface;
use Psr\Http\Message\ResponseInterface;

/**
* @author Gijs Nieuwenhuis <[email protected]>
*/
final class CouldNotParseResponseException extends \Exception
final class CouldNotParseResponseException extends \Exception implements PostcodeApiExceptionInterface
{
/**
* @var ResponseInterface
Expand Down
10 changes: 10 additions & 0 deletions lib/FH/PostcodeAPI/Exception/InvalidApiKeyException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace FH\PostcodeAPI\Exception;

/**
* @author Evert Harmeling <[email protected]>
*/
class InvalidApiKeyException extends \Exception implements PostcodeApiExceptionInterface
{
}
10 changes: 10 additions & 0 deletions lib/FH/PostcodeAPI/Exception/PostcodeApiExceptionInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace FH\PostcodeAPI\Exception;

/**
* @author Evert Harmeling <[email protected]>
*/
interface PostcodeApiExceptionInterface
{
}
Loading

0 comments on commit ba24222

Please sign in to comment.