feat: API Flow Tester 핵심 서비스 클래스 구현 (Day 2)
- VariableBinder: 변수 바인딩 엔진 ({{...}} 패턴 처리)
- DependencyResolver: 의존성 정렬 (Topological Sort)
- ResponseValidator: HTTP 응답 검증 (JSONPath, 연산자)
- HttpClient: Laravel HTTP Client 래퍼
- FlowExecutor: 플로우 실행 엔진
This commit is contained in:
226
app/Services/FlowTester/HttpClient.php
Normal file
226
app/Services/FlowTester/HttpClient.php
Normal file
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\FlowTester;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
/**
|
||||
* HTTP 클라이언트 래퍼
|
||||
*
|
||||
* Laravel HTTP Client를 래핑하여 플로우 테스터에 맞게 제공합니다.
|
||||
*/
|
||||
class HttpClient
|
||||
{
|
||||
private string $baseUrl = '';
|
||||
|
||||
private int $timeout = 30;
|
||||
|
||||
private array $defaultHeaders = [];
|
||||
|
||||
private ?string $apiKey = null;
|
||||
|
||||
private ?string $bearerToken = null;
|
||||
|
||||
/**
|
||||
* 기본 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);
|
||||
|
||||
// API 키 추가
|
||||
if ($this->apiKey) {
|
||||
$request = $request->withHeaders(['X-API-KEY' => $this->apiKey]);
|
||||
}
|
||||
|
||||
// Bearer 토큰 추가
|
||||
if ($this->bearerToken) {
|
||||
$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
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user