Skip to content

feat: 어드민 Bruno API 테스트베드 개선#526

Merged
manNomi merged 2 commits into
mainfrom
feat/admin-bruno-api-testbed
May 25, 2026
Merged

feat: 어드민 Bruno API 테스트베드 개선#526
manNomi merged 2 commits into
mainfrom
feat/admin-bruno-api-testbed

Conversation

@manNomi
Copy link
Copy Markdown
Contributor

@manNomi manNomi commented May 25, 2026

관련 이슈

  • resolves: #이슈 번호

작업 내용

  • Bruno codegen이 테스트베드용 API registry를 생성하도록 확장했습니다.
  • 어드민 /bruno 화면을 generated registry 기반으로 변경해 API 목록, 도메인/메서드 필터, 요청 editor 자동 초기화를 지원합니다.
  • Path/Query/Body/Headers를 수정해 실제 API 요청을 보낼 수 있게 하고, 응답 body/header/status/duration을 확인할 수 있게 했습니다.
  • 원격 API 서버 경고, 변경성 메서드 실행 전 confirm, multipart-form API 실행 제한을 추가했습니다.

특이 사항

  • 생성된 packages/api-schema/src/apiDefinitionRegistry.ts는 admin 테스트베드가 사용하는 self-contained registry입니다.
  • 파일 업로드 API는 v1 테스트베드에서는 실행하지 않고 안내만 표시합니다.
  • packages/api-schema/src/apis/ 전체 생성물은 기존 ignore 정책에 따라 커밋하지 않았습니다.

리뷰 요구사항 (선택)

  • Bruno parser의 params:query/body block 파싱 보강이 기존 codegen 산출물에 부작용이 없는지 봐주세요.
  • 실제 API 호출 테스트베드라서 mutating method confirm 및 원격 API 경고 UX가 충분한지 확인 부탁드립니다.

검증

  • pnpm --filter bruno-api-typescript build
  • BRUNO_COLLECTION_DIR='/Users/manwook-han/Desktop/hmw/code/solid-connect/api-docs/Solid Connection' BRUNO_SOURCE_MODE=local pnpm --filter @solid-connect/api-schema run verify:schema
  • pnpm --filter @solid-connect/api-schema run typecheck
  • pnpm --filter @solid-connect/admin lint:check
  • pnpm --filter @solid-connect/admin typecheck
  • pnpm --filter @solid-connect/admin build
  • commit/push hook CI parity checks passed

@manNomi manNomi requested review from enunsnv and wibaek as code owners May 25, 2026 09:30
@vercel
Copy link
Copy Markdown

vercel Bot commented May 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
solid-connect-web-admin Ready Ready Preview, Comment May 25, 2026 10:13am
solid-connection-web Ready Ready Preview, Comment May 25, 2026 10:13am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 25, 2026

Review Change Stack

Warning

Review limit reached

@manNomi, we couldn't start this review because you've used your available PR reviews for now.

Your plan includes 1 review of capacity. Refill in 19 minutes and 5 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more review capacity refills, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: cce683a6-034f-4fbf-9f70-5c24bb1bf244

📥 Commits

Reviewing files that changed from the base of the PR and between 11a626b and a1795b7.

📒 Files selected for processing (8)
  • apps/admin/src/components/features/bruno/BrunoApiPageContent.tsx
  • apps/web/src/apis/image-upload/api.ts
  • packages/api-schema/src/apiDefinitionRegistry.ts
  • packages/bruno-api-typescript/src/generator/apiClientGenerator.ts
  • packages/bruno-api-typescript/src/generator/apiDefinitionGenerator.ts
  • packages/bruno-api-typescript/src/generator/apiFactoryGenerator.ts
  • packages/bruno-api-typescript/src/parser/bruParser.ts
  • packages/bruno-api-typescript/tests/cli.test.js

👀 Walkthrough

이 PR은 API 정의 시스템을 동적 파싱 방식에서 정적 레지스트리 기반으로 전환하는 대규모 인프라 개선입니다. 다음과 같이 진행됩니다:

  1. 파서 확장 — 브루 파일에서 쿼리 파라미터를 별도 블록으로 인식하고, 본문 타입을 유연하게 처리하며, 중첩 중괄호 깊이를 정확히 추적합니다.

  2. 생성기 강화 — 메타데이터 스키마에 표시명, 소스 파일, 파라미터/바디 예시, 바디 유무 및 타입을 추가하고, 이를 활용하여 정적 레지스트리 파일을 자동 생성합니다.

  3. 레지스트리 생성 — 생성된 메타데이터를 바탕으로 brunoApiDefinitionRegistry 상수에 수천 개의 API 엔드포인트를 타입 안전하게 저장합니다.

  4. 패키지 노출@solid-connect/api-schema 패키지의 export 맵을 설정하여 레지스트리를 ./api-definition-registry 서브패스로 접근 가능하게 합니다.

  5. UI 마이그레이션 — 관리자 앱이 새 레지스트리를 소비하도록 리팩토링하여 엔드포인트 정렬, 필터링, 요청 빌더 상태 관리, 요청 생성 및 응답 처리를 완전히 재구성합니다.


🎯 Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes


💡 Suggested reviewers

  • wibaek
  • enunsnv
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 전체 변경사항의 주요 목표를 명확하게 요약하고 있습니다. 어드민 Bruno API 테스트베드 개선이라는 핵심 의도가 간결하게 표현되었습니다.
Description check ✅ Passed PR 설명이 템플릿 구조를 따르며 필수 섹션(작업 내용, 특이 사항, 리뷰 요구사항)을 모두 포함하고 있고, 변경사항이 명확하게 작성되어 있습니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/admin-bruno-api-testbed

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the admin label May 25, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/bruno-api-typescript/src/generator/apiDefinitionGenerator.ts (1)

147-181: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

3. hasBodybody 타입 판정 기준을 하나로 맞춰 주세요.

여기서는 hasBody를 GET/HEAD만 제외하는 규칙으로 넓혔는데, body는 아직도 POST/PUT/PATCH만 허용합니다. 그래서 DELETE + body 엔드포인트는 hasBody: true인데도 bodyRecord<string, never>로 생성됩니다.

수정 예시
   const requestType = responseType.replace('Response', 'Request');
-  const hasBody = ['POST', 'PUT', 'PATCH'].includes(method) && Boolean(parsed.body?.content?.trim());
+  const hasBody = method !== 'GET' && method !== 'HEAD' && Boolean(parsed.body?.content?.trim());
   const bodyType = hasBody ? requestType : 'Record<string, never>';
@@
-    hasBody: method !== 'GET' && method !== 'HEAD' && Boolean(parsed.body?.content?.trim()),
+    hasBody,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/bruno-api-typescript/src/generator/apiDefinitionGenerator.ts` around
lines 147 - 181, The hasBody logic is inconsistent: hasBody is computed as
method !== 'GET' && method !== 'HEAD' but body/bodyType use POST/PUT/PATCH
logic, causing DELETE-with-body to produce hasBody: true but body:
Record<string, never>; update the code so the same hasBody boolean (computed
from method !== 'GET' && method !== 'HEAD' and
Boolean(parsed.body?.content?.trim())) is used everywhere—replace the
POST/PUT/PATCH check in bodyType and the body field with that hasBody variable,
and ensure bodyType uses requestType when hasBody is true while bodyTypeName
continues to reflect parsed.body?.type.
apps/admin/src/components/features/bruno/BrunoApiPageContent.tsx (1)

258-281: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

3. 실패 응답에도 성공 토스트가 뜹니다.

validateStatus: () => true 때문에 4xx/5xx도 catch로 가지 않는데, 아래에서 항상 toast.success("요청이 완료되었습니다.")를 호출하고 있습니다. HTTP 실패는 응답 패널에서 빨갛게 보이더라도 상단 토스트가 성공으로 찍혀서 상태를 반대로 전달합니다.

🔧 예시 수정 방향
-			toast.success("요청이 완료되었습니다.");
+			if (response.status >= 200 && response.status < 300) {
+				toast.success("요청이 완료되었습니다.");
+			} else {
+				toast.error(`요청이 실패했습니다. (HTTP ${response.status})`);
+			}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/admin/src/components/features/bruno/BrunoApiPageContent.tsx` around
lines 258 - 281, The request handler currently passes validateStatus: () => true
so all HTTP responses (including 4xx/5xx) go to the success path and always call
toast.success; update the logic after the axiosInstance.request call in
BrunoApiPageContent (the block that sets setRequestResult and calls toast) to
inspect response.status (or use axios.isAxiosError if preferred) and call
toast.success only for 2xx (e.g., status >=200 && status <300) and call
toast.error for non-2xx responses, leaving setRequestResult and response
header/body handling unchanged; ensure the validateStatus config remains if you
want raw responses, but branch the toast based on response.status.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/admin/src/components/features/bruno/BrunoApiPageContent.tsx`:
- Line 191: The current gating uses only selectedEndpoint?.definition.bodyType
=== "multipart-form" (selectedIsMultipart) which misses file-upload endpoints
whose generated metadata sets hasBody: false/bodyType: null; update the protocol
so the generated endpoint metadata includes an explicit execution flag (e.g.,
definition.canExecute or definition.isExecutable) and change the UI check to use
that flag (falling back to existing bodyType/hasBody heuristics if missing) when
computing selectedIsMultipart/allowed-to-execute for selectedEndpoint; locate
usages of selectedEndpoint, selectedIsMultipart, and selectedEndpoint.definition
to update the decision logic accordingly.
- Line 193: The remote-warning logic currently uses only apiServerUrl
(showRemoteWarning = isRemoteApiServer(apiServerUrl)); change it to prefer the
selected endpoint's URL when present: if selectedEndpoint?.definition?.path is
an absolute URL, pass that URL into isRemoteApiServer and use its result for
showRemoteWarning, otherwise fall back to apiServerUrl; update the code that
computes showRemoteWarning (and any banner/display logic that reads
showRemoteWarning) to reference the new computed value and add or reuse a small
isAbsoluteUrl check to detect absolute paths.

In `@packages/api-schema/src/apiDefinitionRegistry.ts`:
- Around line 770-776: The registry currently contains a real Slack webhook in
the api definition object (look for the entry with domain: "image-upload", name:
"postSlackNotification" and the definition.path field) — remove the actual
webhook value and replace it with a non-secret placeholder or an
environment-reference (e.g., "SLACK_WEBHOOK" placeholder) so no real secret is
committed; update the Bruno source/generation step that produces this entry to
strip or substitute the webhook value at generation time (ensure code that
serializes definition.path uses the placeholder), and coordinate to rotate the
exposed webhook immediately.

In `@packages/bruno-api-typescript/src/generator/apiDefinitionGenerator.ts`:
- Around line 71-95: extractPathParamTokens currently scans the entire URL
including the query string, causing query placeholders like {{default-size}} to
be treated as path params; modify extractPathParamTokens to operate only on the
path portion by trimming off the query string (everything after the first '?')
before running the brunoVarPattern and subsequent regexes, then proceed with the
existing logic (including the {{URL}} special-case and the later
removal/re-scan) so only true path tokens are returned.
- Around line 98-107: The extractInlineQueryParams function is incorrectly
filtering out query parameters with empty values (e.g., key-only params like
"nickname"); remove the value-based filter so keys with empty string values are
preserved. Locate extractInlineQueryParams in apiDefinitionGenerator.ts and
return the full set of entries from new URLSearchParams(queryString) (optionally
trim values but do not drop empty ones) so generated APIs like
getMentorApplicationList include key-only parameters.
- Around line 75-77: Replace the exec+assignment loop with matchAll iteration to
avoid implicit-any and assignment-in-conditional issues: remove the `let match;
while ((match = brunoVarPattern.exec(processedUrl)) !== null)` pattern and use
`for (const match of processedUrl.matchAll(brunoVarPattern)) { ... }`, keeping
the same body but referencing `match[1]` (or named captures) as before;
`brunoVarPattern` already has the /g flag so no other changes are needed.

---

Outside diff comments:
In `@apps/admin/src/components/features/bruno/BrunoApiPageContent.tsx`:
- Around line 258-281: The request handler currently passes validateStatus: ()
=> true so all HTTP responses (including 4xx/5xx) go to the success path and
always call toast.success; update the logic after the axiosInstance.request call
in BrunoApiPageContent (the block that sets setRequestResult and calls toast) to
inspect response.status (or use axios.isAxiosError if preferred) and call
toast.success only for 2xx (e.g., status >=200 && status <300) and call
toast.error for non-2xx responses, leaving setRequestResult and response
header/body handling unchanged; ensure the validateStatus config remains if you
want raw responses, but branch the toast based on response.status.

In `@packages/bruno-api-typescript/src/generator/apiDefinitionGenerator.ts`:
- Around line 147-181: The hasBody logic is inconsistent: hasBody is computed as
method !== 'GET' && method !== 'HEAD' but body/bodyType use POST/PUT/PATCH
logic, causing DELETE-with-body to produce hasBody: true but body:
Record<string, never>; update the code so the same hasBody boolean (computed
from method !== 'GET' && method !== 'HEAD' and
Boolean(parsed.body?.content?.trim())) is used everywhere—replace the
POST/PUT/PATCH check in bodyType and the body field with that hasBody variable,
and ensure bodyType uses requestType when hasBody is true while bodyTypeName
continues to reflect parsed.body?.type.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 94d727fb-9938-4f1e-8c0e-3e93a26dc4f0

📥 Commits

Reviewing files that changed from the base of the PR and between 46a58d9 and 11a626b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • apps/admin/package.json
  • apps/admin/src/components/features/bruno/BrunoApiPageContent.tsx
  • packages/api-schema/package.json
  • packages/api-schema/src/apiDefinitionRegistry.ts
  • packages/bruno-api-typescript/src/generator/apiDefinitionGenerator.ts
  • packages/bruno-api-typescript/src/generator/index.ts
  • packages/bruno-api-typescript/src/parser/bruParser.ts

Comment thread apps/admin/src/components/features/bruno/BrunoApiPageContent.tsx
Comment thread apps/admin/src/components/features/bruno/BrunoApiPageContent.tsx Outdated
Comment thread packages/api-schema/src/apiDefinitionRegistry.ts Outdated
Comment thread packages/bruno-api-typescript/src/generator/apiDefinitionGenerator.ts Outdated
Comment thread packages/bruno-api-typescript/src/generator/apiDefinitionGenerator.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant