Skip to content

Commit

Permalink
Merge pull request #8 from andrei-ghenov/feature/T-005-api-client-test
Browse files Browse the repository at this point in the history
T-005-Refactor codebase for better readability and add PHPUnit tests
  • Loading branch information
andrei-ghenov authored Mar 2, 2024
2 parents 92f168e + 024aa4c commit ca25be3
Show file tree
Hide file tree
Showing 9 changed files with 353 additions and 129 deletions.
43 changes: 23 additions & 20 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
{
"name": "paymaster/quick-top-up-api",
"description": "QuickTopUpAPI is a PHP demo for connecting to transaction APIs, focusing on mobile top-up purchases and status checks. It's designed for easy integration and future scalability, offering a practical example for developers.",
"autoload": {
"psr-4": {
"QuickTopUpAPI\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"QuickTopUpAPI\\Tests\\": "tests/"
}
},
"authors": [
{
"name": "Andrei Ghenov"
}
],
"require": {
"guzzlehttp/guzzle": "^7.8",
"vlucas/phpdotenv": "^5.6"
"name": "paymaster/quick-top-up-api",
"description": "QuickTopUpAPI is a PHP demo for connecting to transaction APIs, focusing on mobile top-up purchases and status checks. It's designed for easy integration and future scalability, offering a practical example for developers.",
"autoload": {
"psr-4": {
"QuickTopUpAPI\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"QuickTopUpAPI\\Tests\\": "tests/"
}
},
"authors": [
{
"name": "Andrei Ghenov"
}
],
"require": {
"guzzlehttp/guzzle": "^7.8",
"vlucas/phpdotenv": "^5.6"
},
"require-dev": {
"phpunit/phpunit": "^11.0"
}
}
2 changes: 1 addition & 1 deletion public/index.php
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<?php

require_once __DIR__ . '/../src/bootstrap.php';
require_once __DIR__.'/../src/bootstrap.php';
155 changes: 104 additions & 51 deletions src/Api/ApiClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,59 +5,112 @@
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

class ApiClient
{
private $client;
private $apiUser;
private $apiPassword;
private $apiSecurityKey;

public function __construct()
{
$this->client = new Client([
'base_uri' => $_ENV['API_BASE_URL'],
]);
$this->apiUser = $_ENV['API_USER'];
$this->apiPassword = $_ENV['API_PASSWORD'];
$this->apiSecurityKey = $_ENV['API_SECURITY_KEY'];
}
/**
* Class ApiClient
*
* @package QuickTopUpAPI\Api
*
* A simple API client to send requests to the QuickTopUp API.
*/
class ApiClient {

private function generateAuthKey($timestamp)
{
// Generate the HMAC SHA256 hash of the timestamp using the API security key.
return base64_encode(hash_hmac('sha256', $timestamp, $this->apiSecurityKey, true));
}
/**
* @var Client
*
* The Guzzle HTTP client.
*/
private $client;

private function hashPassword()
{
// Hash the API password using SHA256.
return hash('sha256', $this->apiPassword);
}
/**
* @var string
*
* The API user.
*/
private $apiUser;

/**
* @var string
*
* The API password.
*/
private $apiPassword;

/**
* @var string
*
* The API security key.
*/
private $apiSecurityKey;

/**
* ApiClient constructor.
*/
public function __construct() {
$this->client = new Client([
'base_uri' => $_ENV['API_BASE_URL'],
]);
$this->apiUser = $_ENV['API_USER'];
$this->apiPassword = $_ENV['API_PASSWORD'];
$this->apiSecurityKey = $_ENV['API_SECURITY_KEY'];
}

/**
* Send a request to the QuickTopUp API.
*
* @param string $method
* The HTTP method to use for the request.
* @param string $endpoint
* The API endpoint to send the request to.
* @param array $data
* The request data.
*
* @return mixed
* The response from the API.
*/
public function sendRequest($method, $endpoint, array $data = []): mixed {
$timestamp = gmdate('c');
$authKey = $this->generateAuthKey($timestamp);
$hashedPassword = $this->hashPassword();

public function sendRequest($method, $endpoint, array $data = [])
{
$timestamp = gmdate('c');
$authKey = $this->generateAuthKey($timestamp);
$hashedPassword = $this->hashPassword();

// Add authentication parameters to the request data.
$data = array_merge($data, [
'DTime' => $timestamp,
'AuthKey' => $authKey,
'User' => $this->apiUser,
'Password' => $hashedPassword,
]);

try {
$response = $this->client->request($method, $endpoint, [
'json' => $data,
'headers' => [
'Content-Type' => 'application/json',
],
]);
return json_decode($response->getBody()->getContents(), true);
} catch (GuzzleException $e) {
return ['error' => $e->getMessage()];
}
// Add authentication parameters to the request data.
$data = array_merge($data, [
'DTime' => $timestamp,
'AuthKey' => $authKey,
'User' => $this->apiUser,
'Password' => $hashedPassword,
]);

try {
$response = $this->client->request($method, $endpoint, [
'json' => $data,
'headers' => [
'Content-Type' => 'application/json',
],
]);

return json_decode($response->getBody()->getContents(), TRUE);
}
catch (GuzzleException $e) {
return ['error' => $e->getMessage()];
}
}

/**
* Generate the authentication key using the API security key.
*/
private function generateAuthKey($timestamp): string {
return base64_encode(
hash_hmac(
'sha256', $timestamp, $this->apiSecurityKey, TRUE
)
);
}

/**
* Hash the API password using SHA256.
*/
private function hashPassword(): string {
return hash('sha256', $this->apiPassword);
}

}
70 changes: 56 additions & 14 deletions src/Model/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,60 @@

namespace QuickTopUpAPI\Model;

class Product
{
public $id;
public $name;
public $description;
public $amount;

public function __construct($id, $name, $description, $amount)
{
$this->id = $id;
$this->name = $name;
$this->description = $description;
$this->amount = $amount;
}
/**
* Class Product
*
* @package QuickTopUpAPI\Model
*
* A simple product model.
*/
class Product {

/**
* @var int
*
* The product ID.
*/
public $id;

/**
* @var string
*
* The product name.
*/
public $name;

/**
* @var string
*
* The product description.
*/
public $description;

/**
* @var float
*
* The product amount.
*/
public $amount;

/**
* Product constructor.
*
* @param int $id
* The product ID.
* @param string $name
* The product name.
* @param string $description
* The product description.
* @param float $amount
* The product amount.
*/
public function __construct($id, $name, $description, $amount) {
$this->id = $id;
$this->name = $name;
$this->description = $description;
$this->amount = $amount;
}

}
75 changes: 55 additions & 20 deletions src/Service/ProductService.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,59 @@

use QuickTopUpAPI\Api\ApiClient;

class ProductService
{
private $apiClient;

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

public function getAllProducts()
{
$endpoint = 'WSGetTopUpProducts';
return $this->apiClient->sendRequest('GET', $endpoint);
}

public function getProductById($productID)
{
$endpoint = "WSGetSingleTopUpProduct";
return $this->apiClient->sendRequest('GET', $endpoint, ['Product' => $productID]);
}
/**
* Class ProductService
*
* @package QuickTopUpAPI\Service
*
* A simple product service to handle product related operations.
*/
class ProductService {

/**
* @var ApiClient
*
* The API client.
*/
private $apiClient;

/**
* ProductService constructor.
*
* @param ApiClient $apiClient
* The API client.
*/
public function __construct(ApiClient $apiClient) {
$this->apiClient = $apiClient;
}

/**
* Get all products.
*
* @return array
* The products.
*/
public function getAllProducts() {
$endpoint = 'WSGetTopUpProducts';

return $this->apiClient->sendRequest('POST', $endpoint);
}

/**
* Get a product by its ID.
*
* @param int $productID
* The product ID.
*
* @return array
* The product.
*/
public function getProductById($productID) {
$endpoint = "WSGetSingleTopUpProduct";

return $this->apiClient->sendRequest(
'POST', $endpoint, ['Product' => $productID]
);
}

}
Loading

0 comments on commit ca25be3

Please sign in to comment.