Skip to content

Commit

Permalink
Merge pull request #2 from klever/feature/add_bearer_auth
Browse files Browse the repository at this point in the history
Feature/add bearer auth
  • Loading branch information
rdarcy1 authored Jan 18, 2019
2 parents 3c1fe85 + 6ed5656 commit 58e9aca
Show file tree
Hide file tree
Showing 10 changed files with 273 additions and 74 deletions.
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ A PHP SDK for communicating with the JustGiving API. Based on the [original SDK]

## Quick start
```php
$guzzleClient = GuzzleClientFactory::build('https://api.justgiving.com/', 'abcde1f2g', 1, '[email protected]', 'myPassword');
$auth = new AppAuth('abcde123');
$guzzleClient = (new GuzzleClientFactory($auth))->createClient();
$client = new JustGivingClient($guzzleClient);
```

Expand Down Expand Up @@ -38,18 +39,22 @@ See the [JustGiving API documentation](https://api.justgiving.com/docs) for more
The `JustGivingClient` should be instantiated with a suitable HTTP client passed in as a parameter. This client must adhere to the [PSR-7 interfaces](http://www.php-fig.org/psr/psr-7/), and should return from requests an instance of `JustGivingApiSdk\Support\Response`.
This class implements the PSR-7 `ResponseInterface` and adds support for dealing with JSON responses, as well as making it easy to access response data.

There is a helper class `GuzzleClientFactory`, that will create a correctly configured [Guzzle](http://docs.guzzlephp.org/en/latest/) client ready to be passed in. The usage of this is:
There is a helper class `GuzzleClientFactory`, that will create a correctly configured [Guzzle](http://docs.guzzlephp.org/en/latest/) client ready to be passed in.
The factory takes an authorisation object to set the auth headers on the HTTP client. The available classes are:
- `AppAuth($appId)` for unprotected endpoints
- `BasicAuth($appId, $username, $password)` for protected endpoints, where you have the username and password
- `BearerAuth($appId, $oAuthSecret, $token)` for protected endpoints, where you have a bearer token (from oAuth)

The API base URL and version are set automatically, but may be overridden by passing an associative array with keys `root_domain` and `api_version` as the $options argument.
Any options apart from this will be passed to Guzzle as custom options (e.g. custom headers or turning on debug mode).

```php
$guzzleClient = GuzzleClientFactory::build($rootDomain, $apiKey, $apiVersion, $username = '', $password = '', $options = []);
```
For example:
```php
$guzzleClient = GuzzleClientFactory::build('https://api.justgiving.com/', 'abcde1f2g', 1, '[email protected]', 'myPassword', ['debug' => true]);
$auth = new BasicAuth('abced123', '[email protected]', 'pass123');
$guzzleClient = (new GuzzleClientFactory($auth, ['api_version' => 2])->buildClient();

$client = new JustGivingClient($guzzleClient);
```
The `options` array is optional, and is merged with the existing configuration to allow for customisation of the Guzzle client configuration (e.g. turning on debug mode as above).

### Querying the API
The SDK defines a separate client class for each resource as define by the [API documentation](https://api.justgiving.com/docs), and each of those classes contain methods that correspond to API actions.
Expand Down
8 changes: 8 additions & 0 deletions src/Exceptions/InvalidPropertyException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Konsulting\JustGivingApiSdk\Exceptions;

class InvalidPropertyException extends \Exception
{

}
7 changes: 7 additions & 0 deletions src/ResourceClients/Models/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Konsulting\JustGivingApiSdk\ResourceClients\Models;

use Konsulting\JustGivingApiSdk\Exceptions\InvalidPropertyException;

class Model
{
/**
Expand Down Expand Up @@ -41,10 +43,15 @@ public function getAttributeNames()
*
* @param iterable $data
* @return $this
* @throws InvalidPropertyException
*/
public function fill($data)
{
foreach ($data as $key => $value) {
if (! property_exists($this, $key)) {
throw new InvalidPropertyException($key . ' is not a property on ' . get_class($this));
}

$this->$key = $value;
}

Expand Down
29 changes: 29 additions & 0 deletions src/Support/Auth/AppAuth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Konsulting\JustGivingApiSdk\Support\Auth;

class AppAuth implements AuthValue
{
/**
* The application ID.
*
* @see https://developer.justgiving.com/apidocs/documentation#AppId
* @var string
*/
protected $appId;

public function __construct($appId)
{
$this->appId = $appId;
}

/**
* Get the authentication headers.
*
* @return array
*/
public function getHeaders()
{
return ['x-api-key' => $this->appId];
}
}
13 changes: 13 additions & 0 deletions src/Support/Auth/AuthValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Konsulting\JustGivingApiSdk\Support\Auth;

interface AuthValue
{
/**
* Get the authentication headers.
*
* @return array
*/
public function getHeaders();
}
48 changes: 48 additions & 0 deletions src/Support/Auth/BasicAuth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace Konsulting\JustGivingApiSdk\Support\Auth;

class BasicAuth implements AuthValue
{
/**
* The application ID (also known as API key).
*
* @see https://developer.justgiving.com/apidocs/documentation#AppId
* @var string
*/
protected $appId;

/**
* The username of the JustGiving user being authenticated.
*
* @var string
*/
protected $username;

/**
* The password of the JustGiving user being authenticated.
*
* @var string
*/
protected $password;

public function __construct($appId, $username, $password)
{
$this->username = $username;
$this->password = $password;
$this->appId = $appId;
}

/**
* Get the authentication headers.
*
* @return array
*/
public function getHeaders()
{
return [
'Authorization' => 'Basic ' . base64_encode($this->username . ":" . $this->password),
'x-api-key' => $this->appId,
];
}
}
51 changes: 51 additions & 0 deletions src/Support/Auth/BearerAuth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace Konsulting\JustGivingApiSdk\Support\Auth;

class BearerAuth implements AuthValue
{
/**
* The application ID (also known as API key).
*
* @see https://developer.justgiving.com/apidocs/documentation#AppId
* @var string
*/
protected $appId;

/**
* The bearer token obtained via oAuth.
*
* @see https://justgivingdeveloper.zendesk.com/hc/en-us/articles/207071499-Getting-a-bearer-token
* @var string
*/
protected $token;

/**
* The oAuth secret provided by JustGiving (this currently has to be requested manually).
*
* @see https://justgivingdeveloper.zendesk.com/hc/en-us/articles/115002238925-How-do-I-get-a-secret-key-
* @var string
*/
protected $oAuthSecret;

public function __construct($appId, $oAuthSecret, $token)
{
$this->appId = $appId;
$this->token = $token;
$this->oAuthSecret = $oAuthSecret;
}

/**
* Get the authentication headers.
*
* @return array
*/
public function getHeaders()
{
return [
'Authorization' => 'Bearer ' . $this->token,
'x-api-key' => $this->appId,
'x-application-key' => $this->oAuthSecret,
];
}
}
72 changes: 16 additions & 56 deletions src/Support/GuzzleClientFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use Illuminate\Support\Arr;
use Konsulting\JustGivingApiSdk\Support\Auth\AuthValue;
use Psr\Http\Message\ResponseInterface;

/**
Expand All @@ -15,58 +17,30 @@
*/
class GuzzleClientFactory
{
/** @var string */
protected $apiKey;

/** @var string */
protected $apiVersion;

/** @var string */
protected $username;

/** @var string */
protected $password;

/** @var string */
protected $rootDomain;

/** @var array */
protected $userOptions;

/** @var AuthValue */
protected $auth;

/**
* GuzzleClientFactory constructor.
*
* @param string $rootDomain
* @param string $apiKey
* @param string $apiVersion
* @param string $username
* @param string $password
* @param array $options
* @param AuthValue $auth
* @param array $options
*/
public function __construct($rootDomain, $apiKey, $apiVersion, $username = '', $password = '', $options = [])
public function __construct(AuthValue $auth, $options = [])
{
$this->rootDomain = $rootDomain;
$this->apiKey = $apiKey;
$this->apiVersion = $apiVersion;
$this->username = $username;
$this->password = $password;
$this->rootDomain = Arr::pull($options, 'root_domain', 'https://api.justgiving.com');
$this->apiVersion = Arr::pull($options, 'api_version', 1);
$this->userOptions = $options;
}

/**
* Static method for easily creating a client. Requires the same parameters as the class constructor.
*
* @param string $rootDomain
* @param string $apiKey
* @param string $apiVersion
* @param string $username
* @param string $password
* @param array $options
* @return Client
*/
public static function build($rootDomain, $apiKey, $apiVersion, $username = '', $password = '', $options = [])
{
return (new static($rootDomain, $apiKey, $apiVersion, $username, $password, $options))->createClient();
$this->auth = $auth;
}

/**
Expand All @@ -81,15 +55,13 @@ public function createClient()
return new Response($response);
}));

$defaultHeaders = ['Accept' => 'application/json'];

return new Client(array_merge([
'http_errors' => false,
'handler' => $stack,
'base_uri' => $this->baseUrl(),
'headers' => [
'Accept' => 'application/json',
'Authorize' => 'Basic ' . $this->buildAuthenticationValue(),
'Authorization' => 'Basic ' . $this->buildAuthenticationValue(),
]
'headers' => array_merge($defaultHeaders, $this->auth->getHeaders()),
], $this->userOptions));
}

Expand All @@ -98,20 +70,8 @@ public function createClient()
*
* @return string
*/
public function baseUrl()
{
return $this->rootDomain . $this->apiKey . '/v' . $this->apiVersion . '/';
}

/**
* Build the base 64 encoded string that contains authentication credentials.
*
* @return string
*/
protected function buildAuthenticationValue()
protected function baseUrl()
{
return empty($this->username)
? ''
: base64_encode($this->username . ":" . $this->password);
return $this->rootDomain . '/v' . $this->apiVersion . '/';
}
}
12 changes: 10 additions & 2 deletions tests/Models/ModelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Konsulting\JustGivingApiSdk\Tests\Models;

use Konsulting\JustGivingApiSdk\ResourceClients\Models\CreateAccountRequest;
use Konsulting\JustGivingApiSdk\Exceptions\InvalidPropertyException;
use Konsulting\JustGivingApiSdk\ResourceClients\Models\Team;
use Konsulting\JustGivingApiSdk\Tests\TestCase;

Expand All @@ -27,7 +27,7 @@ protected function setUp()
'targetType' => 'target type',
'teamType' => 'team type',
'target' => 'target',
'teamMembers' => ['one', 'two']
'teamMembers' => ['one', 'two'],
];
$this->team = (new Team)->fill($this->teamData);
}
Expand All @@ -43,4 +43,12 @@ public function it_returns_a_list_of_attribute_names_on_the_model()
{
$this->assertEquals(array_keys($this->teamData), $this->team->getAttributeNames());
}

/** @test */
public function it_throws_an_exception_if_a_property_is_filled_that_does_not_exist()
{
$this->expectException(InvalidPropertyException::class);

(new Team)->fill(['Target' => 1]);
}
}
Loading

0 comments on commit 58e9aca

Please sign in to comment.