id(); // 기본 환경 초기화 $this->explorer->initializeDefaultEnvironments($userId); $endpoints = $this->parser->getEndpointsByTag(); $tags = $this->parser->getTags(); $bookmarks = $this->explorer->getBookmarks($userId); $environments = $this->explorer->getEnvironments($userId); $defaultEnv = $this->explorer->getDefaultEnvironment($userId); return view('dev-tools.api-explorer.index', compact( 'endpoints', 'tags', 'bookmarks', 'environments', 'defaultEnv' )); } /* |-------------------------------------------------------------------------- | Endpoint Operations (HTMX partial) |-------------------------------------------------------------------------- */ /** * 엔드포인트 목록 (필터/검색) */ public function endpoints(Request $request): View { $filters = [ 'search' => $request->input('search'), 'methods' => $request->input('methods', []), 'tags' => $request->input('tags', []), ]; $endpoints = $this->parser->filter($filters); $endpointsByTag = $endpoints->groupBy(fn ($e) => $e['tags'][0] ?? '기타'); $bookmarks = $this->explorer->getBookmarks(auth()->id()); return view('dev-tools.api-explorer.partials.sidebar', compact( 'endpointsByTag', 'bookmarks' )); } /** * 단일 엔드포인트 상세 (요청 패널) */ public function endpoint(string $operationId): View { $endpoint = $this->parser->getEndpoint($operationId); if (! $endpoint) { abort(404, '엔드포인트를 찾을 수 없습니다.'); } $userId = auth()->id(); $isBookmarked = $this->explorer->isBookmarked($userId, $endpoint['path'], $endpoint['method']); $templates = $this->explorer->getTemplates($userId, $endpoint['path'], $endpoint['method']); return view('dev-tools.api-explorer.partials.request-panel', compact( 'endpoint', 'isBookmarked', 'templates' )); } /* |-------------------------------------------------------------------------- | API Execution |-------------------------------------------------------------------------- */ /** * API 실행 (프록시) */ public function execute(Request $request): JsonResponse { $validated = $request->validate([ 'method' => 'required|string|in:GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS', 'url' => 'required|url', 'headers' => 'nullable|array', 'query' => 'nullable|array', 'body' => 'nullable|array', 'environment' => 'required|string', ]); // API 실행 $result = $this->requester->execute( $validated['method'], $validated['url'], $validated['headers'] ?? [], $validated['query'] ?? [], $validated['body'] ); // 히스토리 저장 $parsedUrl = parse_url($validated['url']); $endpoint = $parsedUrl['path'] ?? '/'; $this->explorer->logRequest(auth()->id(), [ 'endpoint' => $endpoint, 'method' => $validated['method'], 'request_headers' => $this->requester->maskSensitiveHeaders($validated['headers'] ?? []), 'request_body' => $validated['body'], 'response_status' => $result['status'], 'response_headers' => $result['headers'], 'response_body' => is_string($result['body']) ? $result['body'] : json_encode($result['body']), 'duration_ms' => $result['duration_ms'], 'environment' => $validated['environment'], ]); return response()->json($result); } /* |-------------------------------------------------------------------------- | Bookmarks |-------------------------------------------------------------------------- */ /** * 즐겨찾기 목록 */ public function bookmarks(): View { $bookmarks = $this->explorer->getBookmarks(auth()->id()); return view('dev-tools.api-explorer.partials.bookmarks', compact('bookmarks')); } /** * 즐겨찾기 추가/토글 */ public function addBookmark(Request $request): JsonResponse { $validated = $request->validate([ 'endpoint' => 'required|string|max:500', 'method' => 'required|string|max:10', 'display_name' => 'nullable|string|max:100', ]); $result = $this->explorer->toggleBookmark(auth()->id(), $validated); return response()->json($result); } /** * 즐겨찾기 제거 */ public function removeBookmark(int $id): JsonResponse { $this->explorer->removeBookmark($id); return response()->json(['success' => true]); } /** * 즐겨찾기 순서 변경 */ public function reorderBookmarks(Request $request): JsonResponse { $validated = $request->validate([ 'order' => 'required|array', 'order.*' => 'integer', ]); $this->explorer->reorderBookmarks(auth()->id(), $validated['order']); return response()->json(['success' => true]); } /* |-------------------------------------------------------------------------- | Templates |-------------------------------------------------------------------------- */ /** * 템플릿 목록 */ public function templates(Request $request): JsonResponse { $endpoint = $request->input('endpoint'); $method = $request->input('method'); $templates = $this->explorer->getTemplates(auth()->id(), $endpoint, $method); return response()->json($templates); } /** * 특정 엔드포인트의 템플릿 목록 */ public function templatesForEndpoint(string $endpoint): JsonResponse { $method = request('method'); $endpoint = urldecode($endpoint); $templates = $this->explorer->getTemplates(auth()->id(), $endpoint, $method); return response()->json($templates); } /** * 템플릿 저장 */ public function saveTemplate(Request $request): JsonResponse { $validated = $request->validate([ 'endpoint' => 'required|string|max:500', 'method' => 'required|string|max:10', 'name' => 'required|string|max:100', 'description' => 'nullable|string', 'headers' => 'nullable|array', 'path_params' => 'nullable|array', 'query_params' => 'nullable|array', 'body' => 'nullable|array', 'is_shared' => 'nullable|boolean', ]); $template = $this->explorer->saveTemplate(auth()->id(), $validated); return response()->json([ 'success' => true, 'template' => $template, ]); } /** * 템플릿 삭제 */ public function deleteTemplate(int $id): JsonResponse { $this->explorer->deleteTemplate($id); return response()->json(['success' => true]); } /* |-------------------------------------------------------------------------- | History |-------------------------------------------------------------------------- */ /** * 히스토리 목록 */ public function history(Request $request): View { $limit = $request->input('limit', 50); $histories = $this->explorer->getHistory(auth()->id(), $limit); return view('dev-tools.api-explorer.partials.history-drawer', compact('histories')); } /** * 히스토리 전체 삭제 */ public function clearHistory(): JsonResponse { $count = $this->explorer->clearHistory(auth()->id()); return response()->json([ 'success' => true, 'deleted' => $count, ]); } /** * 히스토리 재실행 */ public function replayHistory(int $id): JsonResponse { $history = $this->explorer->getHistoryItem($id); if (! $history) { return response()->json(['error' => '히스토리를 찾을 수 없습니다.'], 404); } return response()->json([ 'endpoint' => $history->endpoint, 'method' => $history->method, 'headers' => $history->request_headers, 'body' => $history->request_body, ]); } /* |-------------------------------------------------------------------------- | Environments |-------------------------------------------------------------------------- */ /** * 환경 목록 */ public function environments(): JsonResponse { $environments = $this->explorer->getEnvironments(auth()->id()); return response()->json($environments); } /** * 환경 저장 */ public function saveEnvironment(Request $request): JsonResponse { $validated = $request->validate([ 'id' => 'nullable|integer', 'name' => 'required|string|max:50', 'base_url' => 'required|url|max:500', 'api_key' => 'nullable|string|max:500', 'auth_token' => 'nullable|string', 'variables' => 'nullable|array', 'is_default' => 'nullable|boolean', ]); if (! empty($validated['id'])) { $environment = $this->explorer->updateEnvironment($validated['id'], $validated); } else { $environment = $this->explorer->saveEnvironment(auth()->id(), $validated); } return response()->json([ 'success' => true, 'environment' => $environment, ]); } /** * 환경 삭제 */ public function deleteEnvironment(int $id): JsonResponse { $this->explorer->deleteEnvironment($id); return response()->json(['success' => true]); } /** * 기본 환경 설정 */ public function setDefaultEnvironment(int $id): JsonResponse { $this->explorer->setDefaultEnvironment(auth()->id(), $id); return response()->json(['success' => true]); } }