verifySsl = false; return $this; } /** * Host 헤더 설정 (Docker 내부 통신용) */ public function setHostHeader(string $host): self { $this->hostHeader = $host; return $this; } /** * 기본 URL 설정 */ public function setBaseUrl(string $url): self { $this->baseUrl = rtrim($url, '/'); return $this; } /** * 타임아웃 설정 (초) */ public function setTimeout(int $seconds): self { $this->timeout = $seconds; return $this; } /** * 기본 헤더 설정 */ public function setDefaultHeaders(array $headers): self { $this->defaultHeaders = $headers; return $this; } /** * API 키 설정 (X-API-KEY 헤더) */ public function setApiKey(string $apiKey): self { $this->apiKey = $apiKey; return $this; } /** * Bearer 토큰 설정 */ public function setBearerToken(string $token): self { $this->bearerToken = $token; return $this; } /** * HTTP 요청 실행 * * @param string $method HTTP 메서드 * @param string $endpoint 엔드포인트 * @param array $options 옵션 ['headers' => [], 'body' => [], 'query' => []] * @return array ['status' => int, 'headers' => array, 'body' => array, 'duration' => int] */ public function request(string $method, string $endpoint, array $options = []): array { $startTime = microtime(true); $url = $this->buildUrl($endpoint); $headers = $this->buildHeaders($options['headers'] ?? []); try { $request = Http::timeout($this->timeout) ->withHeaders($headers); // SSL 검증 비활성화 (Docker 내부 통신용) if (! $this->verifySsl) { $request = $request->withoutVerifying(); } // Host 헤더 추가 (Docker 내부 통신용) if ($this->hostHeader) { $request = $request->withHeaders(['Host' => $this->hostHeader]); } // API 키 추가 if ($this->apiKey) { $request = $request->withHeaders(['X-API-KEY' => $this->apiKey]); } // Bearer 토큰 추가 (스텝 헤더에 Authorization이 없는 경우에만) if ($this->bearerToken && ! isset($headers['Authorization'])) { $request = $request->withToken($this->bearerToken); } // 쿼리 파라미터 if (! empty($options['query'])) { $url .= '?'.http_build_query($options['query']); } // 요청 실행 $response = match (strtoupper($method)) { 'GET' => $request->get($url), 'POST' => $request->post($url, $options['body'] ?? []), 'PUT' => $request->put($url, $options['body'] ?? []), 'PATCH' => $request->patch($url, $options['body'] ?? []), 'DELETE' => $request->delete($url, $options['body'] ?? []), default => throw new Exception("Unsupported HTTP method: {$method}"), }; $duration = (int) ((microtime(true) - $startTime) * 1000); return [ 'status' => $response->status(), 'headers' => $response->headers(), 'body' => $response->json() ?? [], 'duration' => $duration, 'success' => $response->successful(), 'error' => null, ]; } catch (Exception $e) { $duration = (int) ((microtime(true) - $startTime) * 1000); return [ 'status' => 0, 'headers' => [], 'body' => [], 'duration' => $duration, 'success' => false, 'error' => $e->getMessage(), ]; } } /** * GET 요청 */ public function get(string $endpoint, array $query = [], array $headers = []): array { return $this->request('GET', $endpoint, [ 'query' => $query, 'headers' => $headers, ]); } /** * POST 요청 */ public function post(string $endpoint, array $body = [], array $headers = []): array { return $this->request('POST', $endpoint, [ 'body' => $body, 'headers' => $headers, ]); } /** * PUT 요청 */ public function put(string $endpoint, array $body = [], array $headers = []): array { return $this->request('PUT', $endpoint, [ 'body' => $body, 'headers' => $headers, ]); } /** * PATCH 요청 */ public function patch(string $endpoint, array $body = [], array $headers = []): array { return $this->request('PATCH', $endpoint, [ 'body' => $body, 'headers' => $headers, ]); } /** * DELETE 요청 */ public function delete(string $endpoint, array $body = [], array $headers = []): array { return $this->request('DELETE', $endpoint, [ 'body' => $body, 'headers' => $headers, ]); } /** * 전체 URL 구성 */ private function buildUrl(string $endpoint): string { $endpoint = ltrim($endpoint, '/'); if (empty($this->baseUrl)) { return $endpoint; } return $this->baseUrl.'/'.$endpoint; } /** * 헤더 병합 */ private function buildHeaders(array $additionalHeaders): array { return array_merge( [ 'Accept' => 'application/json', 'Content-Type' => 'application/json', ], $this->defaultHeaders, $additionalHeaders ); } }