Skip to Content
Open APIPipelinesRun with File

Pipeline Run with File — 파일 업로드와 함께 파이프라인 실행

파일을 업로드하고 해당 파이프라인을 비동기로 실행합니다. 업로드된 파일은 data-connector 스토리지에 저장되고, 그 위치가 dag_run.conf로 주입되어 파이프라인의 retriever 노드가 참조합니다.

  • Endpoint: POST /open/v1/pipelines/{pipelineId}/runs/with-file
  • Tag: Open API
  • 인증: API Key (Authorization: Bearer {API_KEY})

응답 래퍼/에러 포맷은 공통 사항 문서를 참고하세요.


인증

Authorization: Bearer sk_live_xxxxxxxxxxxxxxxx
  • 인증 방식: API Key (회사 단위)
  • 회사 컨텍스트는 API Key에서 자동 resolve — 별도 tenant 헤더 불필요
  • 인증 실패: 401

Request

Path Parameters

Path param타입필수설명
pipelineIdstringY실행할 파이프라인(DAG) ID. 예: tenant__abc123. Pipeline Builder에서 deploy된 DAG ID.

Headers

Header타입필수설명
AuthorizationstringYBearer 토큰 형식의 API Key. Bearer {API_KEY}
Content-TypestringYmultipart/form-data (boundary는 클라이언트가 자동 생성)

Body (multipart/form-data)

Part필수Content-Type설명
fileYapplication/octet-stream / text/csv / text/tab-separated-values / application/json업로드할 데이터 파일. 최대 200MB
metadataNapplication/json선택적 메타데이터 JSON (OpenPipelineRunFileMetadataRequest)

metadata 스키마

{ "logicalDate": "2026-05-22T00:00:00+09:00", "note": "daily import from analytics", "conf": { "any_user_key": "any_value" } }
필드타입필수설명
logicalDatestring (ISO-8601)NAirflow DAG run의 logical date. 동일 logical date로도 새 run 생성됨 (run_id는 항상 unique 발급). 미지정 시 현재 시각.
notestringNDAG run에 붙는 메모. 미지정 시 "Triggered with uploaded file <원본파일명>" 자동 생성
confobjectN사용자 정의 dag_run.conf 키. 단, uploaded_file_* 접두 키는 서버가 항상 덮어씀

자동 주입되는 dag_run.conf (예약 키)

서버가 항상 덮어쓰므로 metadata.conf에 같은 키를 넣어도 무시됩니다.

타입
uploaded_file_pathstring스토리지 URI. s3://{container}/ingest/{companyId}/{uuid}.{ext} (Azure는 abfs://, Local은 file://)
uploaded_file_formatstringparquet / csv / tsv / json (정규화된 값)
uploaded_file_sizenumberbytes
uploaded_file_original_namestring클라이언트가 보낸 원본 파일명. 빈 문자열일 수 있음

DAG의 retriever 노드는 이 키들을 Jinja로 참조합니다:

DataRetrievalOperator( connection_id="tenant_{companyId}_uploaded_file_default", query="{{ dag_run.conf['uploaded_file_path'] }}", )

지원 파일 형식

확장자정규화 코드기본 MIME
.parquet, .pqparquetapplication/octet-stream
.csvcsvtext/csv
.tsvtsvtext/tab-separated-values
.jsonjsonapplication/json

⚠️ 파일 형식 판정은 파일명 확장자 기준입니다. 클라이언트가 보낸 Content-Type 헤더는 무시됩니다. 화이트리스트 외 확장자 → 400.


Response (data) — 200 OK

OpenPipelineRunResponse (공통 envelope {code, message, data, traceId} 안):

{ "code": "SUCCESS", "message": "OK", "data": { "dagRunId": "manual__<uuid>", "dagId": "tenant__abc123", "state": "QUEUED", "logicalDate": "2026-05-22T00:00:00+09:00", "startDate": null, "note": "Triggered with uploaded file sales.parquet" }, "traceId": "00-xxxxx-xxxxx-01" }
필드타입설명
dagRunIdstringAirflow DAG run ID. 폴링 / 조회 시 사용
dagIdstring실행한 파이프라인 ID (= request path의 pipelineId)
statestring | nullAirflow DagRunState enum name (QUEUED / RUNNING / SUCCESS / FAILED 등). 비동기라 응답 시점엔 QUEUED/null이 일반적
logicalDatestring | nullDAG run의 logical date
startDatestring | null시작 시각. 응답 시점엔 null일 수 있음
notestring | nullDAG run note

Airflow 내부 필드 (triggered_by, run_type, duration, endDate)는 외부 표면에서 의도적으로 제외.


Errors

HTTP메시지원인
400업로드된 파일이 비어 있습니다.file part 비어있음 (0 bytes)
400업로드 파일이 최대 허용 크기(200MB)를 초과했습니다.size cap 초과
400지원하지 않는 파일 형식입니다. 허용: parquet(.pq)/csv/tsv/json. 받은 파일명: foo.xlsx확장자 화이트리스트 외
401API Key required / Invalid API Key인증 실패
404(Airflow)pipelineId가 회사 소유 DAG가 아니거나 미배포
500(Airflow upstream)Airflow 또는 storage 백엔드 장애

비동기 모델 / 상태 폴링

이 엔드포인트는 DAG run을 트리거만 하고 즉시 반환합니다. 실제 실행 완료까지 기다리지 않습니다.

응답의 dagRunId로 별도 상태 조회가 필요한 경우, 현재는 keycloak 인증 측 엔드포인트(GET /pipelines/{pipelineId}/runs/{runId})를 사용해야 합니다. Open API 측 status 폴링은 후속 PR 예정.


Examples

curl — 기본 (파일만)

curl -X POST "${HOST}/open/v1/pipelines/${PIPELINE_ID}/runs/with-file" \ -H "Authorization: Bearer ${API_KEY}" \ -F "file=@./sales.parquet"

curl — metadata 포함

curl -X POST "${HOST}/open/v1/pipelines/${PIPELINE_ID}/runs/with-file" \ -H "Authorization: Bearer ${API_KEY}" \ -F "file=@./sales.parquet" \ -F 'metadata={"note":"daily","logicalDate":"2026-05-22T00:00:00+09:00","conf":{"source":"ga4"}};type=application/json'

JavaScript / fetch

const fd = new FormData(); fd.append("file", fileBlob, "sales.parquet"); // metadata는 별도 Blob으로 감싸야 Content-Type을 application/json으로 지정 가능 fd.append( "metadata", new Blob( [JSON.stringify({ note: "daily", conf: { source: "ga4" } })], { type: "application/json" } ) ); const res = await fetch( `${HOST}/open/v1/pipelines/${pipelineId}/runs/with-file`, { method: "POST", headers: { Authorization: `Bearer ${API_KEY}`, // Content-Type 절대 명시 금지 — fetch가 multipart boundary 자동 생성 }, body: fd, } ); const json = await res.json(); console.log(json.data.dagRunId); // "manual__<uuid>"

Python / requests

import requests, json with open("sales.parquet", "rb") as f: res = requests.post( f"{HOST}/open/v1/pipelines/{pipeline_id}/runs/with-file", headers={"Authorization": f"Bearer {API_KEY}"}, files={ "file": ("sales.parquet", f, "application/octet-stream"), "metadata": ( None, json.dumps({"note": "daily"}), "application/json", ), }, ) print(res.json()["data"]["dagRunId"])

사전 준비 (회사당 1회)

이 엔드포인트가 동작하려면 Airflow Connection이 사전에 시드되어 있어야 합니다.

  • conn_id: tenant_{companyId}_uploaded_file_default
  • conn_type: uploaded_file
  • 자격증명 필드: 비워둠 (실제 다운로드는 worker IAM/fsspec으로 처리)

후속 PR에서 DataConnectorService.ensureUploadedFileConnection(companyId)로 자동 시드 예정. 그 전까진 운영자가 Airflow UI에서 회사별로 1회 생성.


동작 흐름 (참고)

[Client] │ multipart: file + metadata [app-api] │ · 검증 (size, 확장자, 비어있음) │ · MultipartFile → temp file (메모리 적재 회피) │ · StorageService.streamUpload() → ingest/{companyId}/{uuid}.{ext} │ · DataConnectorService.triggerCompanyDagRun(pipelineId, conf={uploaded_file_*}) ▼ (Airflow REST API v2, 회사별 Bearer 토큰) [Airflow DAG (Pipeline Builder 생성)] │ · DataRetrievalOperator(conn_id=..., query="{{ dag_run.conf['uploaded_file_path'] }}") │ · 런타임에 UploadedFileConnector가 fsspec으로 스토리지에서 다운로드 + 파싱 [downstream transform/load operators — 기존 그대로]

제한 / 주의사항

  • 최대 파일 크기: 200MB (pipeline.ingest.max-file-size-mb 설정값)
  • 중복 실행 방지 없음: 같은 pipelineId로 연속 호출 시 각각 별개 DAG run 생성. 기존 /pipelines/{id}/run 엔드포인트의 “이미 실행 중” 차단은 이 엔드포인트엔 적용되지 않음
  • 파일 보존: 업로드 파일은 스토리지에 영구 저장됨 (별도 GC 없음). 운영 측에서 ingest/ prefix에 S3 lifecycle 규칙(N일 만료) 적용 권장
  • Content-Type 헤더 직접 명시 금지 (fetch/axios에서): multipart boundary가 자동 생성되도록 라이브러리에 맡길 것
Last updated on