KLingo API - Editor Utility Widget 테스트 도구 설계 문서
프로젝트: Onepiece (POTENUP 최종 프로젝트) 목적: 언리얼 에디터 내에서 KLingo API를 테스트할 수 있는 Editor Utility Widget 도구 생성
문서 목표
이 문서는 Onepiece 프로젝트의 기존 UKLingoNetworkSystem을 활용하여 에디터 내에서 KLingo API를 테스트할 수 있는 Editor Utility Widget 기반 테스트 도구를 설계합니다.
시스템 개요
핵심 기능
- API 목록 관리: DataTable 기반 API 엔드포인트 관리
- API 선택: 드롭다운에서 API 선택 시 자동으로 엔드포인트 채우기
- JSON Payload 입력: 멀티라인 텍스트 박스에서 JSON 요청 본문 작성
- Mock Mode: 실제 서버 대신 Mock JSON 파일 사용
- Send Request: UKLingoNetworkSystem을 통한 실제 API 호출
- Response Display: Pretty Print된 JSON 응답 출력
시스템 구성도
┌─────────────────────────────────────────────────────────┐
│ Editor Utility Widget (EUW_KLingoAPITester) │
│ ┌───────────────────────────────────────────────────┐ │
│ │ [API 선택] [▼ /Login ] │ │
│ │ [Endpoint] /Login │ │
│ │ [Method] POST │ │
│ │ [Mock Mode] ☐ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ JSON Payload (Input) │ │ │
│ │ │ { │ │ │
│ │ │ "account": "player123" │ │ │
│ │ │ } │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ [Send Request] │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ Response (Output - Pretty Print) │ │ │
│ │ │ { │ │ │
│ │ │ "token": "abc123...", │ │ │
│ │ │ "playerInfo": { │ │ │
│ │ │ "nickname": "Player", │ │ │
│ │ │ "gold": 1000 │ │ │
│ │ │ } │ │ │
│ │ │ } │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────┘ │
│ ↓ │
│ UKLingoAPITestSubsystem (Editor Only) │
│ ↓ │
│ UKLingoNetworkSystem (Runtime) │
│ ↓ │
│ KLingo API Server │
└─────────────────────────────────────────────────────────┘
프로젝트 구조
Source/Onepiece/
├── Network/
│ ├── Public/
│ │ ├── KLingoAPITestEntry.h # DataTable Row 구조체
│ │ └── UKLingoAPITestSubsystem.h # 에디터 테스트 서브시스템
│ └── Private/
│ └── UKLingoAPITestSubsystem.cpp # 테스트 로직 구현
├── Utils/ # (신규)
│ ├── Public/
│ │ └── JsonPrettyPrinter.h # JSON Pretty Print 유틸리티
│ └── Private/
│ └── JsonPrettyPrinter.cpp
└── Onepiece.Build.cs
Content/
├── EditorUtilities/
│ └── EUW_KLingoAPITester # Editor Utility Widget
├── Data/
│ ├── DT_KLingoAPIList # DataTable Asset
│ └── MockResponses/ # Mock JSON 파일들
│ ├── Login.json
│ ├── CreateUser.json
│ └── ...
└── API/
└── KLingoAPIList.csv # CSV 소스 파일
생성할 파일 목록
C++ 파일
- KLingoAPITestEntry.h - DataTable Row 구조체
- UKLingoAPITestSubsystem.h/cpp - 에디터 테스트 서브시스템
- JsonPrettyPrinter.h/cpp - JSON 포맷팅 유틸리티
데이터 파일
- KLingoAPIList.csv - API 목록 CSV
- Mock JSON 파일들 - 각 API별 Mock 응답
에디터 에셋
- EUW_KLingoAPITester - Editor Utility Widget (UMG)
- DT_KLingoAPIList - DataTable Asset (CSV에서 생성)
Onepiece 프로젝트 컨벤션
1. 파일 헤더
// Copyright (c) 2025 Doppleddiggong. All rights reserved.
// Unauthorized copying, modification, or distribution of this file,
// via any medium is strictly prohibited. Proprietary and confidential.
2. 에디터 전용 코드
#if WITH_EDITOR
// 에디터 전용 코드
#endif
3. 서브시스템 구조
UEditorSubsystem상속 (에디터 전용)DEFINE_SUBSYSTEM_GETTER_INLINE매크로 사용 가능하나 에디터 전용이므로 조건부 사용
4. 로깅
NETWORK_LOG(ENetworkLogType::GET, TEXT("[API Test] %s"), *Message);
1. KLingoAPITestEntry.h 설계
목적: DataTable Row로 사용할 API 정보 구조체
파일 위치: Source/Onepiece/Network/Public/KLingoAPITestEntry.h
구조체 필드:
USTRUCT(BlueprintType)
struct FKLingoAPITestEntry : public FTableRowBase
{
GENERATED_BODY()
// API 이름 (UI 표시용)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "API")
FString APIName;
// 엔드포인트 경로
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "API")
FString Endpoint;
// HTTP 메서드 (GET, POST)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "API")
FString Method;
// 설명
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "API")
FString Description;
// 샘플 JSON Payload
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "API")
FString SamplePayload;
// Mock Response 파일 경로 (Content/ 기준 상대 경로)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "API")
FString MockResponsePath;
};
2. UKLingoAPITestSubsystem 설계
목적: Editor Utility Widget에서 호출할 API 테스트 로직 제공
파일 위치:
Source/Onepiece/Network/Public/UKLingoAPITestSubsystem.hSource/Onepiece/Network/Private/UKLingoAPITestSubsystem.cpp
주요 기능:
- API 호출 (실제 서버 또는 Mock)
- JSON Pretty Print
- 응답 델리게이트 전달
클래스 구조:
#if WITH_EDITOR
DECLARE_DELEGATE_TwoParams(FOnAPITestComplete, bool /*bSuccess*/, const FString& /*Response*/);
UCLASS()
class ONEPIECE_API UKLingoAPITestSubsystem : public UEditorSubsystem
{
GENERATED_BODY()
public:
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
/// @brief API 테스트 요청을 전송합니다.
/// @param Endpoint [in] API 엔드포인트입니다.
/// @param Method [in] HTTP 메서드 (GET, POST)입니다.
/// @param Payload [in] JSON 요청 본문입니다.
/// @param bMockMode [in] Mock 모드 활성화 여부입니다.
/// @param MockFilePath [in] Mock JSON 파일 경로입니다.
/// @param OnComplete [in] 완료 시 호출될 델리게이트입니다.
UFUNCTION(BlueprintCallable, Category = "KLingo API Test")
void SendAPIRequest(
const FString& Endpoint,
const FString& Method,
const FString& Payload,
bool bMockMode,
const FString& MockFilePath,
FOnAPITestComplete OnComplete
);
/// @brief JSON 문자열을 Pretty Print 합니다.
/// @param JsonString [in] JSON 문자열입니다.
/// @return Pretty Print된 JSON 문자열입니다.
UFUNCTION(BlueprintCallable, Category = "KLingo API Test")
FString PrettyPrintJSON(const FString& JsonString);
private:
/// @brief Mock JSON 파일을 읽어옵니다.
FString LoadMockResponse(const FString& FilePath);
};
#endif // WITH_EDITOR
3. JsonPrettyPrinter 설계
목적: JSON 문자열을 보기 좋게 포맷팅
파일 위치:
Source/Onepiece/Utils/Public/JsonPrettyPrinter.hSource/Onepiece/Utils/Private/JsonPrettyPrinter.cpp
함수:
class ONEPIECE_API FJsonPrettyPrinter
{
public:
/// @brief JSON 문자열을 Pretty Print 합니다.
/// @param JsonString [in] 포맷팅할 JSON 문자열입니다.
/// @return 포맷팅된 JSON 문자열입니다.
static FString PrettyPrint(const FString& JsonString);
};
구현 방법:
FJsonSerializer::Deserialize()로 JSON 파싱TJsonWriterFactory로 Pretty Writer 생성>::Create() FJsonSerializer::Serialize()로 포맷팅된 문자열 생성
4. API 목록 CSV 설계
파일 위치: Content/API/KLingoAPIList.csv
CSV 형식:
Name,APIName,Endpoint,Method,Description,SamplePayload,MockResponsePath
Login,Login,/Login,POST,사용자 로그인,"{\"account\":\"player123\"}",Data/MockResponses/Login.json
CreateUser,CreateUser,/CreateUserInfo,POST,새 사용자 생성,"{\"character\":0,\"characterColor\":0}",Data/MockResponses/CreateUser.json
RequestInterview,RequestInterview,/RequestInterview,GET,인터뷰 요청,"",Data/MockResponses/RequestInterview.json
SubmitInterview,SubmitInterview,/SubmitInterviewAnswer,POST,인터뷰 제출,"{\"answers\":[\"answer1\",\"answer2\"]}",Data/MockResponses/SubmitInterview.json
StartGame,StartGame,/StartGame,POST,게임 시작,"{\"playerList\":[\"p1\",\"p2\"],\"nicknames\":[\"n1\",\"n2\"]}",Data/MockResponses/StartGame.json
GameLogin,GameLogin,/GameLogin,POST,게임 로그인,"{\"token\":\"abc123\"}",Data/MockResponses/GameLogin.json
QuestAnswer,QuestAnswer,/QuestAnswer,POST,퀘스트 답변,"{\"questStep\":0,\"questAnswer\":1,\"playTime\":10.5}",Data/MockResponses/QuestAnswer.json
QuestFail,QuestFail,/QuestFail,POST,퀘스트 실패,"{\"questStep\":0}",Data/MockResponses/QuestFail.json
QuestWrite,QuestWrite,/QuestWrite,POST,Write 퀘스트,"{\"imagePaths\":[],\"textData\":[]}",Data/MockResponses/QuestWrite.json
QuestSpeak,QuestSpeak,/QuestSpeak,POST,Speak 퀘스트,"{\"speakStep\":0,\"wavFilePath\":\"\"}",Data/MockResponses/QuestSpeak.json
GameResult,GameResult,/GameResult,GET,게임 결과 조회,"",Data/MockResponses/GameResult.json
5. Mock JSON 파일 예제
Login.json
{
"token": "mock_auth_token_abc123",
"playerInfo": {
"userIndex": 1,
"nickname": "MockPlayer",
"gold": 1000,
"character": 0,
"characterColor": 0,
"unlockEquip": "",
"login": true
}
}
StartGame.json
{
"questRead": {
"readIndex": 1,
"difficulty": 1,
"questTarget": [
{ "findSymbol": "A", "findColor": "Red" },
{ "findSymbol": "B", "findColor": "Blue" }
],
"correctAnswerIndex": 0,
"wordData1": { "kor": "사과", "eng": "Apple", "pronunciation": "æpl" },
"wordData2": { "kor": "바나나", "eng": "Banana", "pronunciation": "bəˈnænə" },
"fullData": "Mock Full Data"
},
"questListen": {
"listenIndex": 1,
"difficulty": 1,
"questTarget": [
{ "findTarget1": "Listen1", "findTarget2": "Listen2" }
],
"correctAnswerIndex": 0,
"wordData1": { "kor": "듣기", "eng": "Listen", "pronunciation": "ˈlɪsən" },
"wordData2": { "kor": "말하기", "eng": "Speak", "pronunciation": "spiːk" },
"fullData": "Mock Listen Data"
},
"questWrite": {
"writeIndex": 1,
"difficulty": 1,
"questTarget": [
{ "textureData": "MockTexture" }
]
},
"questSpeak": {
"speakIndex": 1,
"difficulty": 1,
"answerPlayer": ["Player1", "Player2"],
"questTarget": ["Target1", "Target2"]
}
}
6. Editor Utility Widget 설계
UMG 레이아웃
┌─────────────────────────────────────────────────────────┐
│ KLingo API Tester │
├─────────────────────────────────────────────────────────┤
│ API Selection │
│ ┌─────────────────────────────────────────────────┐ │
│ │ ComboBox: [▼ Login ] │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ API Information │
│ Endpoint: [/Login ] │
│ Method: [POST ] │
│ ☐ Mock Mode │
│ │
│ Request Payload (JSON) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ { │ │
│ │ "account": "player123" │ │
│ │ } │ │
│ │ │ │
│ │ │ │
│ └─────────────────────────────────────────────────┘ │
│ [Send Request] │
│ │
│ Response (JSON) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ { │ │
│ │ "token": "abc123...", │ │
│ │ "playerInfo": { │ │
│ │ "nickname": "Player", │ │
│ │ "gold": 1000 │ │
│ │ } │ │
│ │ } │ │
│ │ │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
위젯 구성 요소
ComboBox_APIList (ComboBoxString)
- API 목록 표시
- OnSelectionChanged 이벤트 → API 정보 자동 채우기
TextBox_Endpoint (TextBox)
- ReadOnly
- API 선택 시 자동 채워짐
TextBox_Method (TextBox)
- ReadOnly
- API 선택 시 자동 채워짐
CheckBox_MockMode (CheckBox)
- Mock 모드 활성화 여부
MultiLineTextBox_Payload (MultiLineEditableTextBox)
- JSON 요청 본문 입력
- API 선택 시 샘플 자동 채워짐
Button_SendRequest (Button)
- OnClicked 이벤트 → API 요청 전송
MultiLineTextBox_Response (MultiLineEditableTextBox)
- ReadOnly
- Pretty Print된 응답 표시
7. Blueprint Graph 설계
Event: OnSelectionChanged (ComboBox_APIList)
[ComboBox_APIList - OnSelectionChanged]
↓
[Get DataTable Row (DT_KLingoAPIList)]
↓ (FKLingoAPITestEntry)
[Set Text (TextBox_Endpoint)] ← Row.Endpoint
[Set Text (TextBox_Method)] ← Row.Method
[Set Text (MultiLineTextBox_Payload)] ← Row.SamplePayload
Event: OnClicked (Button_SendRequest)
[Button_SendRequest - OnClicked]
↓
[Get EditorSubsystem (UKLingoAPITestSubsystem)]
↓
[Get Text (TextBox_Endpoint, TextBox_Method, MultiLineTextBox_Payload)]
[Get CheckBox State (CheckBox_MockMode)]
[Get Selected API Row] → MockResponsePath
↓
[SendAPIRequest]
├─ Endpoint
├─ Method
├─ Payload
├─ bMockMode
└─ MockFilePath
↓ (OnComplete Delegate)
[PrettyPrintJSON] ← Response String
↓
[Set Text (MultiLineTextBox_Response)]
8. 구현 체크리스트
C++ 파일
- [ ] KLingoAPITestEntry.h (DataTable Row 구조체)
- [ ] UKLingoAPITestSubsystem.h/cpp (에디터 서브시스템)
- [ ] JsonPrettyPrinter.h/cpp (JSON 포맷팅 유틸리티)
데이터 파일
- [ ] KLingoAPIList.csv (API 목록)
- [ ] Mock JSON 파일 11개 (각 API별)
에디터 에셋
- [ ] DT_KLingoAPIList (DataTable)
- [ ] EUW_KLingoAPITester (Editor Utility Widget)
빌드 설정
- [ ] Onepiece.Build.cs에 "EditorSubsystem" 모듈 추가 확인
9. 설치 및 사용 가이드
Step 1: C++ 파일 생성
- KLingoAPITestEntry.h 생성
- UKLingoAPITestSubsystem.h/cpp 생성
- JsonPrettyPrinter.h/cpp 생성
- 프로젝트 빌드
Step 2: CSV 및 Mock 파일 준비
Content/API/KLingoAPIList.csv생성Content/Data/MockResponses/폴더 생성- 각 API별 Mock JSON 파일 생성
Step 3: DataTable 생성
- Content Browser에서 우클릭 → Miscellaneous → Data Table
- Row Structure: FKLingoAPITestEntry 선택
- 이름: DT_KLingoAPIList
- Import CSV (KLingoAPIList.csv)
Step 4: Editor Utility Widget 생성
- Content Browser에서 우클릭 → Editor Utilities → Editor Utility Widget
- 이름: EUW_KLingoAPITester
- UMG 디자이너에서 위젯 레이아웃 구성
- Blueprint Graph에서 로직 구현
Step 5: 에디터 메뉴에 추가
- EUW_KLingoAPITester 우클릭 → Run Editor Utility Widget
- (선택) Tools 메뉴에 영구 추가 설정
10. 주의사항
에디터 전용 코드
#if WITH_EDITOR전처리기 사용UEditorSubsystem상속- Runtime 빌드에 포함되지 않도록 주의
Mock 모드
- Mock JSON 파일 경로는 Content/ 기준 상대 경로
FPaths::ProjectContentDir()사용하여 절대 경로 변환
실제 API 호출
- UKLingoNetworkSystem 활용
- 델리게이트 바인딩 시 Lambda 사용 권장
- 에디터에서 WorldContext 가져오기:
GEditor->GetEditorWorldContext()
최종 산출물
위 설계를 기반으로 다음 파일들을 생성해주세요:
- KLingoAPITestEntry.h
- UKLingoAPITestSubsystem.h
- UKLingoAPITestSubsystem.cpp
- JsonPrettyPrinter.h
- JsonPrettyPrinter.cpp
- KLingoAPIList.csv
- Mock JSON 샘플 (Login.json, StartGame.json)
- Editor Utility Widget 구성 가이드 (상세 Blueprint 노드 설명)
생성 조건:
- Onepiece 프로젝트 컨벤션 100% 준수
- 에디터 전용 코드 (#if WITH_EDITOR)
- 복사-붙여넣기로 즉시 사용 가능
- Doxygen 주석 포함
- 완전한 구현 (TODO 없음)