Client   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 195
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
wmc 29
eloc 74
c 1
b 0
f 1
dl 0
loc 195
rs 10

13 Methods

Rating   Name   Duplication   Size   Complexity  
A put() 0 4 1
A logResponse() 0 5 2
B makeRequest() 0 35 7
A logError() 0 5 2
A isCacheEnabled() 0 3 2
A logRequest() 0 5 2
A get() 0 17 4
A delete() 0 3 1
A handleError() 0 15 4
A getCacheKey() 0 4 1
A patch() 0 4 1
A __construct() 0 11 1
A post() 0 4 1
1
<?php
2
3
namespace UsamamuneerChaudhary\Daftravel\Http;
4
5
use GuzzleHttp\Client as GuzzleClient;
6
use GuzzleHttp\Exception\RequestException;
7
use Illuminate\Support\Facades\Cache;
8
use Illuminate\Support\Facades\Log;
9
use UsamamuneerChaudhary\Daftravel\Exceptions\AuthenticationException;
10
use UsamamuneerChaudhary\Daftravel\Exceptions\ValidationException;
11
use UsamamuneerChaudhary\Daftravel\Exceptions\RateLimitException;
12
use UsamamuneerChaudhary\Daftravel\Exceptions\ApiException;
13
14
class Client
15
{
16
    protected GuzzleClient $client;
17
    protected array $config;
18
    protected mixed $baseUrl;
19
    protected mixed $apiKey;
20
21
    public function __construct(array $config)
22
    {
23
        $this->config = $config;
24
        $this->baseUrl = $config['api_url'];
25
        $this->apiKey = $config['api_key'];
26
27
        $this->client = new GuzzleClient([
28
            'base_uri' => $this->baseUrl,
29
            'timeout' => $config['timeout'],
30
            'headers' => array_merge($config['default_headers'], [
31
                'Authorization' => 'Bearer ' . $this->apiKey,
32
            ]),
33
        ]);
34
    }
35
36
    /**
37
        * Send a GET request to the Daftra API.
38
     */
39
    public function get(string $endpoint, array $params = [])
40
    {
41
        $cacheKey = $this->getCacheKey('GET', $endpoint, $params);
42
43
        if ($this->isCacheEnabled() && Cache::has($cacheKey)) {
44
            return Cache::get($cacheKey);
45
        }
46
47
        $response = $this->makeRequest('GET', $endpoint, [
48
            'query' => $params,
49
        ]);
50
51
        if ($this->isCacheEnabled()) {
52
            Cache::put($cacheKey, $response, $this->config['cache']['ttl']);
53
        }
54
55
        return $response;
56
    }
57
58
    /**
59
     * Send a POST request to the Daftra API.
60
     */
61
    public function post(string $endpoint, array $data = [])
62
    {
63
        return $this->makeRequest('POST', $endpoint, [
64
            'json' => $data,
65
        ]);
66
    }
67
68
    /**
69
     * Send a PUT request to the Daftra API.
70
     */
71
    public function put(string $endpoint, array $data = [])
72
    {
73
        return $this->makeRequest('PUT', $endpoint, [
74
            'json' => $data,
75
        ]);
76
    }
77
78
    /**
79
     * Send a PATCH request to the Daftra API.
80
     */
81
    public function patch(string $endpoint, array $data = [])
82
    {
83
        return $this->makeRequest('PATCH', $endpoint, [
84
            'json' => $data,
85
        ]);
86
    }
87
88
    /**
89
     * Send a DELETE request to the Daftra API.
90
     */
91
    public function delete(string $endpoint)
92
    {
93
        return $this->makeRequest('DELETE', $endpoint);
94
    }
95
96
    /**
97
     * Make a request to the Daftra API with retry logic.
98
     */
99
    protected function makeRequest(string $method, string $endpoint, array $options = [])
100
    {
101
        $attempts = 0;
102
        $maxAttempts = $this->config['retry']['times'];
103
104
        while ($attempts < $maxAttempts) {
105
            try {
106
                $this->logRequest($method, $endpoint, $options);
107
108
                $response = $this->client->request($method, $endpoint, $options);
109
                $body = json_decode($response->getBody()->getContents(), true) ?? [];
110
111
                $this->logResponse($response->getStatusCode(), $body);
112
113
                return $body;
114
            } catch (RequestException $e) {
115
                $attempts++;
116
117
                if ($e->hasResponse()) {
118
                    $statusCode = $e->getResponse()->getStatusCode();
119
                    $responseBody = json_decode($e->getResponse()->getBody()->getContents(), true) ?? [];
120
121
                    $this->logError($method, $endpoint, $statusCode, $responseBody);
122
123
                    if ($attempts >= $maxAttempts) {
124
                        $this->handleError($statusCode, $responseBody, $e);
125
                    }
126
                } else {
127
                    if ($attempts >= $maxAttempts) {
128
                        throw new ApiException('Network error: ' . $e->getMessage(), 0, $e);
129
                    }
130
                }
131
132
                if ($attempts < $maxAttempts) {
133
                    usleep($this->config['retry']['delay'] * 1000);
134
                }
135
            }
136
        }
137
    }
138
139
    /**
140
     * Handle errors based on the status code and response body.
141
     */
142
    protected function handleError(int $statusCode, array $responseBody, RequestException $e)
143
    {
144
        $message = $responseBody['message'] ?? 'An error occurred';
145
146
        switch ($statusCode) {
147
            case 401:
148
                throw new AuthenticationException($message, $statusCode, $e, $responseBody, $statusCode);
149
            case 422:
150
                $errors = $responseBody['errors'] ?? [];
151
                throw new ValidationException($message, $errors, $statusCode, $e, $responseBody, $statusCode);
152
            case 429:
153
                $retryAfter = $e->getResponse()->getHeaderLine('Retry-After');
154
                throw new RateLimitException($message, $retryAfter, $statusCode, $e, $responseBody, $statusCode);
155
            default:
156
                throw new ApiException($message, $statusCode, $e, $responseBody, $statusCode);
157
        }
158
    }
159
160
    /**
161
     * Generate a cache key based on the request method, endpoint, and parameters.
162
     */
163
    protected function getCacheKey(string $method, string $endpoint, array $params = []): string
164
    {
165
        $key = $method . ':' . $endpoint . ':' . md5(json_encode($params));
166
        return $this->config['cache']['prefix'] . $key;
167
    }
168
169
    /**
170
     * Check if caching is enabled and the request method is cacheable.
171
     */
172
    protected function isCacheEnabled(): bool
173
    {
174
        return $this->config['cache']['enabled'] && in_array(request()->method(), ['GET']);
175
    }
176
177
    /**
178
     * Log the request details.
179
     */
180
    protected function logRequest(string $method, string $endpoint, array $options)
181
    {
182
        if ($this->config['logging']['enabled']) {
183
            Log::log($this->config['logging']['level'], "Daftra API Request: {$method} {$endpoint}", [
184
                'options' => $options,
185
            ]);
186
        }
187
    }
188
189
    /**
190
     * Log the response details.
191
     */
192
    protected function logResponse(int $statusCode, array $body)
193
    {
194
        if ($this->config['logging']['enabled']) {
195
            Log::log($this->config['logging']['level'], "Daftra API Response: {$statusCode}", [
196
                'body' => $body,
197
            ]);
198
        }
199
    }
200
201
    /**
202
     * Log error details.
203
     */
204
    protected function logError(string $method, string $endpoint, int $statusCode, array $body)
205
    {
206
        if ($this->config['logging']['enabled']) {
207
            Log::error("Daftra API Error: {$method} {$endpoint} - {$statusCode}", [
208
                'body' => $body,
209
            ]);
210
        }
211
    }
212
}
213