Streaming & Upload

Core의 callApiStream은 NDJSON 응답을 줄 단위 JSON으로 읽어 Observable에서 순서대로 emit합니다.


Core에서 callApiStream 직접 사용

서버가 NDJSON(한 줄에 JSON 하나)을 내려줄 때 callApiStream을 사용합니다. Accept header가 없으면 application/x-ndjson을 기본값으로 설정하며, 다른 media type이 필요하면 per-request headers로 덮어쓸 수 있습니다.

ts
export const streamEvents = () => {
  return client.callApiStream<{
    eventName: string;
    content: unknown;
  }>({
    url: "/api/event/stream",
    method: "get",
    // headers: { Accept: "application/x-ndjson" },
  });
};

NDJSON 응답 형식

text
{"status":"STARTED","progress":0}
{"status":"PROGRESS","progress":35}
{"status":"PROGRESS","progress":80}
{"status":"DONE","progress":100}

callApiStream은 줄바꿈을 기준으로 응답을 나누고 각 줄을 JSON.parse합니다. 표준 SSE의 data: frame 형식이 아니라 NDJSON을 기대합니다.

Observable 구독과 해제

tsx
const subscription = streamEvents().subscribe({
  next: (event) => {
    setProgress(event.content);
  },
  error: (error) => {
    setErrorMessage(error.message);
  },
  complete: () => {
    setRunning(false);
  },
});

return () => subscription.unsubscribe();

unsubscribe()하면 내부 ReadableStream reader도 취소됩니다. React effect나 작업 cleanup에서 구독을 해제하세요.

선택: 생성된 stream service 사용

OpenAPI generator를 사용하는 프로젝트에서는 stream endpoint에 대해 생성된 service가 callApiStream을 호출하도록 만들 수 있습니다. 화면에서는 일반 생성 service와 같은 방식으로 import하고 subscribe합니다.

tsx
const subscription = jobProgress({
  path: { jobId },
}).subscribe({
  next: (event) => {
    setProgress(event.progress || 0);
  },
  error: (error) => {
    setErrorMessage(error.message);
  },
  complete: () => {
    setRunning(false);
  },
});

return () => subscription.unsubscribe();

uploadFile: 지정 URL에 파일 PUT

uploadFile.ts
ts
service.uploadFile({
  file,
  url: signedUploadUrl,
  headers: {
    "Content-Type": file.type || "application/octet-stream",
    "If-None-Match": "*",
  },
}).subscribe();
© 2026 Byeolnaerim. All rights reserved.소개개인정보처리방침