diff --git a/README.md b/README.md index 05754f3..2e15efb 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,14 @@

Openapi® client for PHP

The perfect starting point to integrate Openapi® within your PHP project

- [![Build Status](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml/badge.svg)](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml) - [![Packagist Version](https://img.shields.io/packagist/v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) - [![PHP Version](https://img.shields.io/packagist/php-v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) - [![License](https://img.shields.io/github/license/openapi/openapi-php-sdk?v=2)](LICENSE) - [![Downloads](https://img.shields.io/packagist/dt/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) -
+[![Build Status](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml/badge.svg)](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml) +[![Packagist Version](https://img.shields.io/packagist/v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) +[![PHP Version](https://img.shields.io/packagist/php-v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) +[![License](https://img.shields.io/github/license/openapi/openapi-php-sdk?v=2)](LICENSE) +[![Downloads](https://img.shields.io/packagist/dt/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) +
[![Linux Foundation Member](https://img.shields.io/badge/Linux%20Foundation-Silver%20Member-003778?logo=linux-foundation&logoColor=white)](https://www.linuxfoundation.org/about/members) + ## Overview @@ -27,9 +28,10 @@ Before using the Openapi PHP Client, you will need an account at [Openapi](https - **Agnostic Design**: No API-specific classes, works with any OpenAPI service - **Minimal Dependencies**: Only requires PHP 8.0+ and cURL -- **OAuth Support**: Built-in OAuth client for token management +- **OAuth Support**: Built-in OAuth client for token management - **HTTP Primitives**: GET, POST, PUT, DELETE, PATCH methods - **Clean Interface**: Similar to the Rust SDK design +- **Built-in DotEnv Support**: Lightweight environment loader with safe fallback behavior ## What you can do @@ -81,7 +83,7 @@ $client = new Client($token); $params = ['denominazione' => 'Stellantis', 'provincia' => 'TO']; $response = $client->get('https://test.company.openapi.com/IT-advanced', $params); -// POST request +// POST request $payload = ['limit' => 10, 'query' => ['country_code' => 'IT']]; $response = $client->post('https://test.postontarget.com/fields/country', $payload); @@ -91,6 +93,70 @@ $response = $client->delete($url); $response = $client->patch($url, $payload); ``` +## Custom HTTP Clients (Guzzle, Laravel, etc.) + +By default, the SDK uses an internal cURL-based transport. +However, you can now inject your own HTTP client, allowing full control over the request pipeline. + +This is especially useful in frameworks like Laravel, where you may want to reuse an existing HTTP client with middleware such as retry, caching, logging, or tracing. + +Using a custom HTTP client (e.g. Guzzle) + +You can pass any PSR-18 compatible client (such as Guzzle) directly to the SDK: + +```php +use OpenApi\Client; +use GuzzleHttp\Client as GuzzleClient; + +$guzzle = new GuzzleClient([ + 'timeout' => 10, + // You can configure middleware, retry logic, caching, etc. here +]); + +$client = new Client($token, $guzzle); + +$response = $client->get('https://test.company.openapi.com/IT-advanced', [ + 'denominazione' => 'Stellantis', +]); +``` + +### Why this matters + +When using the default transport, requests are executed via cURL and bypass any framework-level HTTP configuration. + +By injecting your own client, you can: + +- ✅ Reuse your existing HTTP middleware stack (e.g. Laravel retry/cache) +- ✅ Centralize logging, tracing, and observability +- ✅ Apply custom headers, timeouts, or authentication strategies +- ✅ Maintain consistency with your application's HTTP layer + +### Custom Transport Interface + +If needed, you can also implement your own transport by using the provided interface: + +```php +use OpenApi\Interfaces\HttpTransportInterface; + +class MyTransport implements HttpTransportInterface +{ + public function request( + string $method, + string $url, + mixed $payload = null, + ?array $params = null + ): string { + // Your custom implementation + } +} +``` + +And inject it: + +```php +$client = new Client($token, new MyTransport()); +``` + ## Architecture This SDK follows a minimal approach with only essential components: @@ -100,6 +166,59 @@ This SDK follows a minimal approach with only essential components: - `Exception`: Error handling - `Cache\CacheInterface`: Optional caching interface +## Environment Configuration (.env support) + +This SDK includes a lightweight and framework-agnostic .env loader to simplify configuration in non-framework environments. + +### Automatic loading + +When installed via Composer, the SDK will automatically attempt to load a .env file from the project root. + +This happens only when no existing environment configuration is detected (e.g. Laravel, Symfony, CI environments). + +- ✅ Does not override existing environment variables +- ✅ Works out of the box in plain PHP projects +- ✅ Compatible with Laravel, Symfony, and other frameworks +- ✅ Safe fallback mechanism + +### Supported variables + +The following environment variables are commonly used: + +```env +OPENAPI_BASE_URL=https://example.com +OPENAPI_OAUTH_USERNAME=your_username +OPENAPI_OAUTH_APIKEY=your_api_key +OPENAPI_OAUTH_URL=https://api.com +OPENAPI_OAUTH_TEST_URL=https://api.com +``` + +### Framework compatibility + +If you are using a framework like Laravel or Symfony: + +- The SDK will not override your existing environment +- Your framework's configuration system remains the source of truth +- The internal loader acts only as a fallback + +### Manual usage + +If you prefer full control, you can use the DotEnv loader manually: + +```php +use OpenApi\Environment\DotEnv\DotEnv; + +$dotenv = new DotEnv(__DIR__ . '/.env'); +$dotenv->load(); + +``` + +### Notes + +- The loader is intentionally minimal and does not aim to fully replace libraries like vlucas/phpdotenv +- Designed for performance, predictability, and zero external dependencies +- Suitable for CLI tools, microservices, and lightweight integrations + ## Requirements - PHP 8.0 or higher @@ -134,7 +253,6 @@ composer run test composer run test:unit ``` - ## Contributing Contributions are always welcome! Whether you want to report bugs, suggest new features, improve documentation, or contribute code, your help is appreciated. @@ -165,9 +283,9 @@ Meet our partners using Openapi or contributing to this SDK: ## Our Commitments -We believe in open source and we act on that belief. We became Silver Members -of the Linux Foundation because we wanted to formally support the ecosystem -we build on every day. Open standards, open collaboration, and open governance +We believe in open source and we act on that belief. We became Silver Members +of the Linux Foundation because we wanted to formally support the ecosystem +we build on every day. Open standards, open collaboration, and open governance are part of how we work and how we think about software. ## License @@ -179,4 +297,3 @@ The MIT License is a permissive open-source license that allows you to freely us In short, you are free to use this SDK in your personal, academic, or commercial projects, with minimal restrictions. The project is provided "as-is", without any warranty of any kind, either expressed or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. For more details, see the full license text at the [MIT License page](https://choosealicense.com/licenses/mit/). - diff --git a/composer.json b/composer.json index 5e513da..1094f7a 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "openapi/openapi-sdk", + "name": "seraphim/openapi-sdk", "description": "Minimal and agnostic PHP SDK for Openapi® (https://openapi.com)", "license": "MIT", "authors": [ @@ -12,7 +12,8 @@ "require": { "php": ">=8.0.0", "ext-curl": "*", - "ext-json": "*" + "ext-json": "*", + "psr/http-client": "^1.0" }, "require-dev": { "symfony/dotenv": "^5.3", @@ -20,7 +21,20 @@ }, "autoload": { "psr-4": { - "OpenApi\\": "src" + "Openapi\\": "src" + }, + "files": [ + "src/OpenapiBootstrap.php" + ] + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests" } }, "scripts": { diff --git a/examples/api_calls.php b/examples/api_calls.php index 4be6279..5ff9660 100644 --- a/examples/api_calls.php +++ b/examples/api_calls.php @@ -2,11 +2,11 @@ require_once __DIR__ . '/../vendor/autoload.php'; -use OpenApi\Client; +use OpenApi\OpenapiClient; try { $token = ''; - $client = new Client($token); + $client = new OpenapiClient($token); // GET request with parameters $params = [ diff --git a/examples/complete_workflow.php b/examples/complete_workflow.php index a6389cf..43eca3d 100644 --- a/examples/complete_workflow.php +++ b/examples/complete_workflow.php @@ -2,16 +2,16 @@ require_once __DIR__ . '/../vendor/autoload.php'; -use OpenApi\OauthClient; -use OpenApi\Client; -use OpenApi\Exception; +use OpenApi\OpenapiOauthClient; +use OpenApi\OpenapiClient; +use OpenApi\OpenapiException; try { echo "=== OpenAPI PHP SDK Complete Workflow Example ===" . PHP_EOL . PHP_EOL; // Step 1: Create OAuth client echo "Step 1: Creating OAuth client..." . PHP_EOL; - $oauthClient = new OauthClient('', '', true); + $oauthClient = new OpenapiOauthClient('', '', true); echo "✓ OAuth client created" . PHP_EOL . PHP_EOL; // Step 2: Generate token @@ -25,7 +25,7 @@ $tokenData = json_decode($tokenResult, true); if (!isset($tokenData['token'])) { - throw new Exception('Failed to generate token: ' . $tokenResult); + throw new OpenapiException('Failed to generate token: ' . $tokenResult); } $token = $tokenData['token']; @@ -33,7 +33,7 @@ // Step 3: Create API client echo "Step 3: Creating API client..." . PHP_EOL; - $apiClient = new Client($token); + $apiClient = new OpenapiClient($token); echo "✓ API client created" . PHP_EOL . PHP_EOL; // Step 4: Make API calls @@ -62,7 +62,7 @@ echo "=== Workflow completed successfully! ===" . PHP_EOL; -} catch (Exception $e) { +} catch (OpenapiException $e) { echo "✗ Error: " . $e->getMessage() . PHP_EOL; if ($e->getHttpCode()) { diff --git a/examples/token_generation.php b/examples/token_generation.php index 79c08b2..24b30ea 100644 --- a/examples/token_generation.php +++ b/examples/token_generation.php @@ -2,10 +2,10 @@ require_once __DIR__ . '/../vendor/autoload.php'; -use OpenApi\OauthClient; +use OpenApi\OpenapiOauthClient; try { - $oauthClient = new OauthClient('', '', true); + $oauthClient = new OpenapiOauthClient('', '', true); $scopes = [ 'GET:test.imprese.openapi.it/advance', diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..d8d04ba --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,20 @@ + + + + + + tests + + + + + + + + + + + \ No newline at end of file diff --git a/src/Cache/ArrayCache.php b/src/Cache/OpenapiArrayCache.php similarity index 93% rename from src/Cache/ArrayCache.php rename to src/Cache/OpenapiArrayCache.php index c52170e..87f5f0b 100644 --- a/src/Cache/ArrayCache.php +++ b/src/Cache/OpenapiArrayCache.php @@ -1,12 +1,12 @@ token = $token; - } - - /** - * Execute HTTP request - * - * @param string $method HTTP method (GET, POST, PUT, DELETE, PATCH) - * @param string $url Target URL - * @param mixed $payload Request body (for POST/PUT/PATCH) - * @param array|null $params Query parameters (for GET) or form data (for other methods) - * @return string Response body - */ - public function request(string $method, string $url, mixed $payload = null, ?array $params = null): string - { - // Append query parameters for GET requests - if ($params && $method === 'GET') { - $url .= '?' . http_build_query($params); - } - - $ch = curl_init(); - - curl_setopt_array($ch, [ - CURLOPT_URL => $url, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_CUSTOMREQUEST => $method, - CURLOPT_TIMEOUT => 30, - CURLOPT_HTTPHEADER => [ - 'Content-Type: application/json', - 'Authorization: Bearer ' . $this->token - ] - ]); - - // Add JSON payload for POST/PUT/PATCH requests - if ($payload && in_array($method, ['POST', 'PUT', 'PATCH'])) { - curl_setopt($ch, CURLOPT_POSTFIELDS, is_string($payload) ? $payload : json_encode($payload)); - } - - // Add form data for non-GET requests - if ($params && $method !== 'GET') { - curl_setopt($ch, CURLOPT_POSTFIELDS, - is_string($params) ? $params : http_build_query($params)); - } - - $response = curl_exec($ch); - $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - $error = curl_error($ch); - curl_close($ch); - - // TODO: Provide more graceful error message with connection context (timeout, DNS, SSL, etc.) - if ($response === false) { - throw new Exception("cURL Error: " . $error); - } - - // TODO: Parse response body and provide structured error details (error code, message, request ID) - if ($httpCode >= 400) { - throw new Exception("HTTP Error {$httpCode}: " . $response); - } - - return $response; - } - - /** - * Perform GET request - */ - public function get(string $url, ?array $params = null): string - { - return $this->request('GET', $url, null, $params); - } - - /** - * Perform POST request - */ - public function post(string $url, mixed $payload = null): string - { - return $this->request('POST', $url, $payload); - } - - /** - * Perform PUT request - */ - public function put(string $url, mixed $payload = null): string - { - return $this->request('PUT', $url, $payload); - } - - /** - * Perform DELETE request - */ - public function delete(string $url): string - { - return $this->request('DELETE', $url); - } - - /** - * Perform PATCH request - */ - public function patch(string $url, mixed $payload = null): string - { - return $this->request('PATCH', $url, $payload); - } -} \ No newline at end of file diff --git a/src/Environment/OpenapiDotEnv.php b/src/Environment/OpenapiDotEnv.php new file mode 100644 index 0000000..bba69cf --- /dev/null +++ b/src/Environment/OpenapiDotEnv.php @@ -0,0 +1,133 @@ +path = $path; + } + + /** + * Loads environment variables from the configured .env file. + * + * Empty lines and comment lines are ignored. Only lines containing a key-value + * separator are processed. Variables that already exist in {@see $_ENV}, + * {@see $_SERVER}, or the process environment are left untouched. + * + * @return void + * + * @throws \RuntimeException Thrown when the file is not readable. + * @throws \RuntimeException Thrown when the file contents cannot be read. + */ + public function load() :void + { + if (!is_readable($this->path)) { + throw new \RuntimeException(sprintf('%s file is not readable', $this->path)); + } + + $lines = file($this->path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + + if ($lines === false) { + throw new \RuntimeException(sprintf('Unable to read %s', $this->path)); + } + + foreach ($lines as $line) { + $line = trim($line); + + if ($line === '' || strpos($line, '#') === 0) { + continue; + } + + if (strpos($line, '=') === false) { + continue; + } + + [$name, $value] = explode('=', $line, 2); + + $name = trim($name); + $value = $this->normalizeValue(trim($value)); + + if ($name === '') { + continue; + } + + if ($this->isLoaded($name)) { + continue; + } + + putenv(sprintf('%s=%s', $name, $value)); + $_ENV[$name] = $value; + $_SERVER[$name] = $value; + } + } + + /** + * Determines whether the given environment variable is already available. + * + * A variable is considered loaded when it exists in {@see $_ENV}, + * {@see $_SERVER}, or the process environment. + * + * @param string $name Environment variable name. + * + * @return bool True when the variable is already present; otherwise false. + */ + private function isLoaded(string $name): bool + { + return array_key_exists($name, $_ENV) + || array_key_exists($name, $_SERVER) + || getenv($name) !== false; + } + + /** + * Normalizes a parsed environment variable value. + * + * Matching single or double quotes wrapping the full value are removed. + * All other values are returned unchanged. + * + * @param string $value Raw environment variable value. + * + * @return string Normalized environment variable value. + */ + private function normalizeValue(string $value): string + { + $length = strlen($value); + + if ($length >= 2) { + $first = $value[0]; + $last = $value[$length - 1]; + + if (($first === '"' && $last === '"') || ($first === "'" && $last === "'")) { + return substr($value, 1, -1); + } + } + + return $value; + } +} diff --git a/src/Interfaces/OpenapiDotEnvInterface.php b/src/Interfaces/OpenapiDotEnvInterface.php new file mode 100644 index 0000000..e685ca5 --- /dev/null +++ b/src/Interfaces/OpenapiDotEnvInterface.php @@ -0,0 +1,7 @@ +getFileName(), 2); + $projectRoot = dirname($vendorDir); + + return is_file($projectRoot . DIRECTORY_SEPARATOR . '.env') ? $projectRoot : null; + } +} + +$envFile = findProjectRoot(__DIR__) . DIRECTORY_SEPARATOR . ".env"; +if (is_file($envFile)) { + (new OpenapiDotEnv($envFile))->load(); +} \ No newline at end of file diff --git a/src/OpenapiClient.php b/src/OpenapiClient.php new file mode 100644 index 0000000..8e78b30 --- /dev/null +++ b/src/OpenapiClient.php @@ -0,0 +1,89 @@ +token = $token ?? getenv('OPEN_API_TOKEN') ; + if(getenv("OPENAPI_BASE_URL")){ + $this->baseUrl = getenv("OPENAPI_BASE_URL"); + } + $this->transport = $transport ?? new OpenapiCurlTransport($token); + } + + + public function request( + string $method, + string $url, + mixed $payload = null, + ?array $params = null + ): string { + $isAbsolute = str_starts_with(strtolower($url), 'http'); + + // Wenn nicht absolut und baseUrl vorhanden -> Zusammenfügen + if (!$isAbsolute && !empty($this->baseUrl)) { + $url = rtrim($this->baseUrl, '/') . '/' . ltrim($url, '/'); + } + return $this->transport->request($method, $url, $payload, $params); + } + + /** + * Perform GET request + */ + public function get(string $url, ?array $params = null): string + { + return $this->request('GET', $url, null, $params); + } + + /** + * Perform POST request + */ + public function post(string $url, mixed $payload = null): string + { + return $this->request('POST', $url, $payload); + } + + /** + * Perform PUT request + */ + public function put(string $url, mixed $payload = null): string + { + return $this->request('PUT', $url, $payload); + } + + /** + * Perform DELETE request + */ + public function delete(string $url): string + { + return $this->request('DELETE', $url); + } + + /** + * Perform PATCH request + */ + public function patch(string $url, mixed $payload = null): string + { + return $this->request('PATCH', $url, $payload); + } +} diff --git a/src/Exception.php b/src/OpenapiException.php similarity index 93% rename from src/Exception.php rename to src/OpenapiException.php index 74650d1..7159666 100644 --- a/src/Exception.php +++ b/src/OpenapiException.php @@ -1,12 +1,12 @@ username = $username; - $this->apikey = $apikey; - $this->url = $test ? self::TEST_OAUTH_BASE_URL : self::OAUTH_BASE_URL; + $this->username = $username ?? getenv('OPENAPI_OAUTH_USERNAME') ; + $this->apikey = $apikey ?? getenv('OPENAPI_OAUTH_APIKEY'); + $this->url = $test ? getenv('OPENAPI_OAUTH_TEST_URL') ?? self::TEST_OAUTH_BASE_URL + : getenv('OPENAPI_OAUTH_URL') ?? self::OAUTH_BASE_URL; } /** @@ -126,12 +127,12 @@ private function request(string $method, string $url, array $body = null): strin // TODO: Provide more graceful error message with connection context (timeout, DNS, SSL, etc.) if ($response === false) { - throw new Exception("cURL Error: " . $error); + throw new OpenapiException("cURL Error: " . $error); } // TODO: Parse response body and provide structured error details with auth-specific hints (invalid credentials, expired key, etc.) if ($httpCode >= 400) { - throw new Exception("HTTP Error {$httpCode}: " . $response); + throw new OpenapiException("HTTP Error {$httpCode}: " . $response); } return $response; diff --git a/src/Transports/OpenapiCurlTransport.php b/src/Transports/OpenapiCurlTransport.php new file mode 100644 index 0000000..2bbec7d --- /dev/null +++ b/src/Transports/OpenapiCurlTransport.php @@ -0,0 +1,68 @@ + $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_TIMEOUT => 30, + CURLOPT_HTTPHEADER => [ + 'Content-Type: application/json', + 'Authorization: Bearer ' . $this->token, + ], + ]); + + if ($payload && in_array($method, ['POST', 'PUT', 'PATCH'], true)) { + curl_setopt($ch, CURLOPT_POSTFIELDS, is_string($payload) ? $payload : json_encode($payload)); + } + + if ($params && $method !== 'GET' && !$payload) { + curl_setopt($ch, CURLOPT_POSTFIELDS, is_string($params) ? $params : http_build_query($params)); + } + + $response = curl_exec($ch); + $error = curl_error($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $ch = null; + + if ($response === false) { + throw new \RuntimeException('cURL error: ' . $error); + } + + if ($httpCode >= 400) { + throw new \RuntimeException("HTTP error {$httpCode}: {$response}"); + } + + return $response; + } +} \ No newline at end of file diff --git a/tests/OauthClientTest.php b/tests/OauthClientTest.php index 4488619..77906b3 100644 --- a/tests/OauthClientTest.php +++ b/tests/OauthClientTest.php @@ -1,30 +1,54 @@ username, $this->apikey, true); - $this->assertInstanceOf(OauthClient::class, $client); + $client = new OpenapiOauthClient($this->username, $this->apikey, true); + $this->assertInstanceOf(OpenapiOauthClient::class, $client); + } + + public function testOauthClientCanBeCreatedFromEnvironmentVariables(): void + { + $username = getenv('OPENAPI_USERNAME'); + $apikey = getenv('OPENAPI_SANDBOX_KEY'); + + $this->assertNotFalse($username, 'OPENAPI_OAUTH_USERNAME is not set'); + $this->assertNotFalse($apikey, 'OPENAPI_OAUTH_APIKEY is not set'); + $this->assertNotSame('', $username, 'OPENAPI_OAUTH_USERNAME is empty'); + $this->assertNotSame('', $apikey, 'OPENAPI_OAUTH_APIKEY is empty'); + + $client = new OpenapiOauthClient($username, $apikey, true); + + $this->assertInstanceOf(OpenapiOauthClient::class, $client); } public function testOauthClientProductionMode(): void { - $client = new OauthClient($this->username, $this->apikey, false); - $this->assertInstanceOf(OauthClient::class, $client); + $client = new OpenapiOauthClient($this->username, $this->apikey, false); + $this->assertInstanceOf(OpenapiOauthClient::class, $client); + } + + public function testEnvironmentVariablesAreAvailable(): void + { + $this->assertSame('test_user', getenv('OPENAPI_USERNAME')); + $this->assertSame('test_key', getenv('OPENAPI_SANDBOX_KEY')); + $this->assertSame('https://api.com', getenv('OPENAPI_OAUTH_SANDBOX_URL')); + $this->assertSame('https://api.com', getenv('OPENAPI_OAUTH_URL')); + $this->assertSame('https://example.com', getenv('OPENAPI_BASE_URL')); } public function testCreateTokenWithScopes(): void { $this->markTestSkipped('Requires valid credentials for integration test'); - $client = new OauthClient($this->username, $this->apikey, true); + $client = new OpenapiOauthClient($this->username, $this->apikey, true); $scopes = [ 'GET:test.imprese.openapi.it/advance', 'POST:test.postontarget.com/fields/country' diff --git a/tests/ApiClientTest.php b/tests/OpenapiApiClientTest.php similarity index 81% rename from tests/ApiClientTest.php rename to tests/OpenapiApiClientTest.php index 89e926c..792fcda 100644 --- a/tests/ApiClientTest.php +++ b/tests/OpenapiApiClientTest.php @@ -1,6 +1,6 @@ testToken); - $this->assertInstanceOf(Client::class, $client); + $client = new OpenapiClient($this->testToken); + $this->assertInstanceOf(OpenapiClient::class, $client); } public function testGetRequest(): void { $this->markTestSkipped('Requires valid token for integration test'); - $client = new Client($this->testToken); + $client = new OpenapiClient($this->testToken); $params = [ 'denominazione' => 'altravia', 'provincia' => 'RM', @@ -32,7 +32,7 @@ public function testPostRequest(): void { $this->markTestSkipped('Requires valid token for integration test'); - $client = new Client($this->testToken); + $client = new OpenapiClient($this->testToken); $payload = [ 'limit' => 10, 'query' => [ @@ -48,7 +48,7 @@ public function testPutRequest(): void { $this->markTestSkipped('Requires valid token for integration test'); - $client = new Client($this->testToken); + $client = new OpenapiClient($this->testToken); $payload = ['test' => 'data']; $result = $client->put('https://example.com/api', $payload); @@ -59,7 +59,7 @@ public function testDeleteRequest(): void { $this->markTestSkipped('Requires valid token for integration test'); - $client = new Client($this->testToken); + $client = new OpenapiClient($this->testToken); $result = $client->delete('https://example.com/api/123'); $this->assertIsString($result); @@ -69,7 +69,7 @@ public function testPatchRequest(): void { $this->markTestSkipped('Requires valid token for integration test'); - $client = new Client($this->testToken); + $client = new OpenapiClient($this->testToken); $payload = ['update' => 'data']; $result = $client->patch('https://example.com/api/123', $payload); diff --git a/tests/ArrayCacheTest.php b/tests/OpenapiArrayCacheTest.php similarity index 92% rename from tests/ArrayCacheTest.php rename to tests/OpenapiArrayCacheTest.php index 9e22756..fe6fd97 100644 --- a/tests/ArrayCacheTest.php +++ b/tests/OpenapiArrayCacheTest.php @@ -1,15 +1,15 @@ cache = new ArrayCache(); + $this->cache = new OpenapiArrayCache(); } public function testCacheImplementation(): void diff --git a/tests/OpenapiClientTest.php b/tests/OpenapiClientTest.php new file mode 100644 index 0000000..90b5788 --- /dev/null +++ b/tests/OpenapiClientTest.php @@ -0,0 +1,59 @@ +request( + 'POST', + 'https://example.com/api/users', + ['name' => 'John'], + ['page' => 1] + ); + + $this->assertSame('fake-response', $response); + + $this->assertSame('POST', $transport->lastMethod); + $this->assertSame('https://example.com/api/users', $transport->lastUrl); + $this->assertSame(['name' => 'John'], $transport->lastPayload); + $this->assertSame(['page' => 1], $transport->lastParams); + $this->assertSame(1, $transport->callCount); + } + + public function test_it_calls_transport_once_per_request(): void + { + $transport = new OpenapiFakeTransport(); + $client = new OpenapiClient('test-token', $transport); + + $client->request('GET', 'https://example.com/one'); + $client->request('GET', 'https://example.com/two'); + + $this->assertSame(2, $transport->callCount); + $this->assertSame('https://example.com/two', $transport->lastUrl); + } + + public function test_it_use_dot_env_for_request(): void + { + $transport = new OpenapiFakeTransport(); + $client = new OpenapiClient('test-token', $transport); + + $client->request('GET', '/one'); + $client->request('GET', 'https://example.com/two'); + + $this->assertSame(2, $transport->callCount); + $this->assertSame('https://example.com/two', $transport->lastUrl); + } +} + diff --git a/tests/ExceptionTest.php b/tests/OpenapiExceptionTest.php similarity index 82% rename from tests/ExceptionTest.php rename to tests/OpenapiExceptionTest.php index daa4438..55c070c 100644 --- a/tests/ExceptionTest.php +++ b/tests/OpenapiExceptionTest.php @@ -1,16 +1,16 @@ assertEquals($message, $exception->getMessage()); $this->assertEquals($code, $exception->getCode()); @@ -18,7 +18,7 @@ public function testExceptionCreation(): void public function testSetServerResponse(): void { - $exception = new Exception('Test message'); + $exception = new OpenapiException('Test message'); $response = ['error' => 'Server error']; $headers = 'Content-Type: application/json'; diff --git a/tests/Transports/OpenapiFakeTransport.php b/tests/Transports/OpenapiFakeTransport.php new file mode 100644 index 0000000..727ab53 --- /dev/null +++ b/tests/Transports/OpenapiFakeTransport.php @@ -0,0 +1,29 @@ +callCount++; + $this->lastMethod = $method; + $this->lastUrl = $url; + $this->lastPayload = $payload; + $this->lastParams = $params; + + return 'fake-response'; + } +} \ No newline at end of file