1부에서는 kepler-http 구조와 fetcher가 어떤 식으로 동작하는지 설명했다.
2부에서는 이 구조가 실제로 컴포넌트에서 어떻게 사용되는지를
"프로필 이미지 업로드" 예제를 중심으로 보여주겠다.
ProfileContainer 컴포넌트에서는
유저가 프로필 이미지를 선택하면 서버에 업로드 요청을 보내고,
응답으로 이미지 id를 받아온다.
이때 사용하는 구조는 다음과 같다:
요청을 날리기 전에 필요한 Wing은 아래처럼 미리 정의해두었다.
import {Wing, Method} from "kepler-http";
import {ProfileCreateBody} from "../../schemas/profile/Body";
export const PostProfileWing = (body: ProfileCreateBody): Wing =>
new Wing(
`/v1/profiles`,
Method.POST,
true, // 인증 필요
{}, // param 없음
body // 요청 body
);
요청 url, method, 인증 여부, 파라미터, body 정보를 Wing 안에 모두 담는다.
import { KeplerBody } from 'kepler-http';
export interface ResourceBody extends KeplerBody {
image: FormData;
}
이 타입은 실제 FormData를 포함할 수 있도록 선언됨
서버에서는 multipart/form-data 형식으로 받아 이미지 리소스를 생성하는 방식
타입을 따로 정의해두면, 요청 시 정확한 구조를 명확하게 전달할 수 있고
launch 호출부에서 자동완성도 가능해진다.
const formData = new FormData();
formData.append('image', file);
const wing = PostProfileWing({ image: formData });
try {
const res = await shootingStar.launch<ResourceBody>(wing);
console.log('이미지 업로드 성공:', res.data.image);
} catch (err) {
console.error('업로드 실패:', err);
}
1. 유저가 이미지 파일 선택 → FormData 생성
2. FormData를 포함한 body로 PostProfileWing 생성
3. shootingStar.launch() 호출 → 서버에 전송
4. 응답 데이터에서 image id 추출
예전에는 직접 axios 요청을 만들고,
url/headers/body를 직접 조립해서 서버에 날려야 했다.
하지만 이제는
Wing 함수만 만들면 요청 단위가 정리되고,
Body 타입도 명확하게 분리돼서 가독성과 재사용성이 올라가고,
launch 하나만 호출하면 토큰 처리, 에러 핸들링까지 자동으로 된다.
결국 우리는 "비즈니스 로직만 집중하고, 통신은 kepler-http에 맡긴다"는 구조를 만들었다.