Files
jobifygarden/app/Services/ApiClientService.php
T
2026-04-03 20:41:35 +03:00

172 lines
5.1 KiB
PHP

<?php
namespace App\Services;
use App\Models\ApiLog;
use App\Models\JobSource;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class ApiClientService
{
/**
* Make an API request with logging and retry logic
*/
public function makeRequest(
JobSource $source,
string $endpoint,
string $method = 'GET',
array $params = [],
int $maxRetries = 3
): array {
$startTime = microtime(true);
$attempt = 0;
$lastException = null;
while ($attempt < $maxRetries) {
$attempt++;
try {
$response = $this->executeRequest($method, $endpoint, $params);
$responseTime = (int)((microtime(true) - $startTime) * 1000);
// Log successful request
$this->logApiRequest($source, $endpoint, $method, $params, $response, $responseTime, true);
return [
'success' => true,
'data' => $response->json(),
'status_code' => $response->status(),
'response_time' => $responseTime,
];
} catch (\Exception $e) {
$lastException = $e;
// Log failed attempt
Log::warning("API request failed (attempt {$attempt}/{$maxRetries})", [
'source' => $source->name,
'endpoint' => $endpoint,
'error' => $e->getMessage(),
]);
if ($attempt < $maxRetries) {
// Exponential backoff: wait 2^attempt seconds
sleep(pow(2, $attempt));
}
}
}
$responseTime = (int)((microtime(true) - $startTime) * 1000);
// Log final failure
$this->logApiRequest(
$source,
$endpoint,
$method,
$params,
null,
$responseTime,
false,
$lastException->getMessage() ?? 'Unknown error'
);
return [
'success' => false,
'error' => $lastException->getMessage() ?? 'Unknown error',
'response_time' => $responseTime,
];
}
/**
* Execute the HTTP request
*/
private function executeRequest(string $method, string $endpoint, array $params): \Illuminate\Http\Client\Response
{
$http = Http::timeout(30)
->retry(1, 100)
->withHeaders([
'User-Agent' => 'JobifyGarden/1.0',
'Accept' => 'application/json',
]);
return match (strtoupper($method)) {
'GET' => $http->get($endpoint, $params),
'POST' => $http->post($endpoint, $params),
'PUT' => $http->put($endpoint, $params),
'DELETE' => $http->delete($endpoint, $params),
default => throw new \InvalidArgumentException("Unsupported HTTP method: {$method}"),
};
}
/**
* Log API request to database
*/
private function logApiRequest(
JobSource $source,
string $endpoint,
string $method,
array $params,
$response,
int $responseTime,
bool $success,
?string $errorMessage = null
): void {
try {
ApiLog::create([
'job_source_id' => $source->id,
'endpoint' => $endpoint,
'method' => $method,
'status_code' => $response?->status(),
'response_time_ms' => $responseTime,
'success' => $success,
'error_message' => $errorMessage,
'request_params' => !empty($params) ? $params : null,
'response_data' => $success && $response ? [
'status' => $response->status(),
'size' => strlen($response->body()),
] : null,
]);
} catch (\Exception $e) {
Log::error('Failed to log API request', [
'error' => $e->getMessage(),
'endpoint' => $endpoint,
]);
}
}
/**
* Check if source is rate limited
*/
public function isRateLimited(JobSource $source): bool
{
if (!$source->rate_limit) {
return false;
}
// Check requests in the last hour
$recentRequests = ApiLog::where('job_source_id', $source->id)
->where('created_at', '>=', now()->subHour())
->count();
return $recentRequests >= $source->rate_limit;
}
/**
* Get rate limit info for a source
*/
public function getRateLimitInfo(JobSource $source): array
{
$recentRequests = ApiLog::where('job_source_id', $source->id)
->where('created_at', '>=', now()->subHour())
->count();
return [
'limit' => $source->rate_limit,
'used' => $recentRequests,
'remaining' => max(0, $source->rate_limit - $recentRequests),
'reset_at' => now()->addHour()->startOfHour(),
];
}
}