Python FastAPI ์คํธ๋ฆฌ๋ฐ์ผ๋ก ํจ์จ์ ์ธ ๋์ฉ๋ ๋ฐ์ดํฐ ์ ์ก์ ๊ตฌํํ์ธ์. ์ด ๊ฐ์ด๋๋ ๋๊ท๋ชจ ์๋ต ์ฒ๋ฆฌ๋ฅผ ์ํ ๊ธฐ์ , ๋ชจ๋ฒ ์ฌ๋ก ๋ฐ ๊ธ๋ก๋ฒ ๊ณ ๋ ค ์ฌํญ์ ๋ค๋ฃน๋๋ค.
Python FastAPI์์ ๋์ฉ๋ ์๋ต ์ฒ๋ฆฌ ๋ง์คํฐํ๊ธฐ: ์คํธ๋ฆฌ๋ฐ์ ๋ํ ๊ธ๋ก๋ฒ ๊ฐ์ด๋
์ค๋๋ ์ ๋ฐ์ดํฐ ์ง์ฝ์ ์ธ ์ธ๊ณ์์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋นํ ์์ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ์ค์๊ฐ ๋ถ์, ๋์ฉ๋ ํ์ผ ๋ค์ด๋ก๋ ๋๋ ์ง์์ ์ธ ๋ฐ์ดํฐ ํผ๋ ๋ฑ ๋์ฉ๋ ์๋ต์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๊ฒ์ ๊ณ ์ฑ๋ฅ์ ํ์ฅ ๊ฐ๋ฅํ API๋ฅผ ๊ตฌ์ถํ๋ ๋ฐ ์์ด ์ค์ํ ์ธก๋ฉด์ ๋๋ค. ์๋์ ์ฌ์ฉ ํธ์์ฑ์ผ๋ก ์ ๋ช ํ Python์ FastAPI๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋๊ท๋ชจ ํ์ด๋ก๋๋ฅผ ๊ด๋ฆฌํ๊ณ ์ ๋ฌํ๋ ๋ฐฉ์์ ํฌ๊ฒ ๊ฐ์ ํ ์ ์๋ ๊ฐ๋ ฅํ ์คํธ๋ฆฌ๋ฐ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ์ํด ๋ง์ถคํ๋ ์ด ํฌ๊ด์ ์ธ ๊ฐ์ด๋๋ FastAPI ์คํธ๋ฆฌ๋ฐ์ ๋ณต์ก์ฑ์ ์์ธํ ์ดํด๋ณด๊ณ ์ ์ธ๊ณ ๊ฐ๋ฐ์๋ฅผ ์ํ ์ค์ฉ์ ์ธ ์์ ์ ์คํ ๊ฐ๋ฅํ ํต์ฐฐ๋ ฅ์ ์ ๊ณตํฉ๋๋ค.
๋์ฉ๋ ์๋ต์ ๊ณผ์
์ผ๋ฐ์ ์ผ๋ก API๊ฐ ๋๊ท๋ชจ ๋ฐ์ดํฐ ์ธํธ๋ฅผ ๋ฐํํด์ผ ํ ๋ ์ผ๋ฐ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ์ ์ฒด ์๋ต์ ๋ฉ๋ชจ๋ฆฌ์ ๊ตฌ์ฑํ ๋ค์ ๋จ์ผ HTTP ์์ฒญ์ผ๋ก ํด๋ผ์ด์ธํธ์ ๋ณด๋ด๋ ๊ฒ์ ๋๋ค. ์ด๋ ์ ๋นํ ์์ ๋ฐ์ดํฐ์๋ ํจ๊ณผ์ ์ด์ง๋ง ๋งค์ฐ ํฐ ๋ฐ์ดํฐ ์ธํธ๋ฅผ ์ฒ๋ฆฌํ ๋๋ ๋ช ๊ฐ์ง ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
- ๋ฉ๋ชจ๋ฆฌ ์๋น: ๊ธฐ๊ฐ๋ฐ์ดํธ์ ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋ํ๋ฉด ์๋ฒ ๋ฆฌ์์ค๊ฐ ๋น ๋ฅด๊ฒ ๊ณ ๊ฐ๋์ด ์ฑ๋ฅ ์ ํ, ์ถฉ๋ ๋๋ ์๋น์ค ๊ฑฐ๋ถ ์ํ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
- ๊ธด ์ง์ฐ ์๊ฐ: ํด๋ผ์ด์ธํธ๋ ์ ์ฒด ์๋ต์ด ์์ฑ๋ ๋๊น์ง ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ธฐ ์ํด ๊ธฐ๋ค๋ ค์ผ ํฉ๋๋ค. ์ด๋ ํนํ ๊ฑฐ์ ์ค์๊ฐ ์ ๋ฐ์ดํธ๊ฐ ํ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ ์ข์ง ์์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ด๋ํ ์ ์์ต๋๋ค.
- ์๊ฐ ์ด๊ณผ ๋ฌธ์ : ๋์ฉ๋ ์๋ต์ ์์ฑํ๊ธฐ ์ํ ์ฅ๊ธฐ ์คํ ์์ ์ ์๋ฒ ๋๋ ํด๋ผ์ด์ธํธ ์๊ฐ ์ด๊ณผ๋ฅผ ์ด๊ณผํ์ฌ ์ฐ๊ฒฐ์ด ๋์ด์ง๊ณ ๋ฐ์ดํฐ ์ ์ก์ด ๋ถ์์ ํด์ง ์ ์์ต๋๋ค.
- ํ์ฅ์ฑ ๋ณ๋ชฉ ํ์: ๋จ์ผ์ ํตํฉ๋ ์๋ต ์์ฑ ํ๋ก์ธ์ค๋ ๋ณ๋ชฉ ํ์์ด ๋์ด API๊ฐ ๋์ ์์ฒญ์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฅ๋ ฅ์ ์ ํํ ์ ์์ต๋๋ค.
์ด๋ฌํ ๋ฌธ์ ๋ ๊ธ๋ก๋ฒ ํ๊ฒฝ์์ ๋์ฑ ์ฆํญ๋ฉ๋๋ค. ๊ฐ๋ฐ์๋ ๋ค์ํ ๋คํธ์ํฌ ์กฐ๊ฑด, ์ฅ์น ๊ธฐ๋ฅ ๋ฐ ์๋ก ๋ค๋ฅธ ์ง์ญ์ ์๋ฒ ์ธํ๋ผ๋ฅผ ๊ณ ๋ คํด์ผ ํฉ๋๋ค. ๋ก์ปฌ ๊ฐ๋ฐ ๋จธ์ ์์ ์ ์๋ํ๋ API๋ ์ธํฐ๋ท ์๋์ ๋๊ธฐ ์๊ฐ์ด ๋ค๋ฅธ ์ง๋ฆฌ์ ์ผ๋ก ๋ค์ํ ์์น์ ์ฌ์ฉ์์๊ฒ ์๋น์ค๋ฅผ ์ ๊ณตํ๊ธฐ ์ํด ๋ฐฐํฌํ ๋ ์ด๋ ค์์ ๊ฒช์ ์ ์์ต๋๋ค.
FastAPI์ ์คํธ๋ฆฌ๋ฐ ์๊ฐ
FastAPI๋ Python์ ๋น๋๊ธฐ ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ ํจ์จ์ ์ธ ์คํธ๋ฆฌ๋ฐ์ ๊ตฌํํฉ๋๋ค. ์ ์ฒด ์๋ต์ ๋ฒํผ๋งํ๋ ๋์ ์คํธ๋ฆฌ๋ฐ์ ์ฌ์ฉํ๋ฉด ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ ๋๋ก ์ฒญํฌ ๋จ์๋ก ๋ณด๋ผ ์ ์์ต๋๋ค. ์ด๋ ๋ฉ๋ชจ๋ฆฌ ์ค๋ฒํค๋๋ฅผ ํฌ๊ฒ ์ค์ด๊ณ ํด๋ผ์ด์ธํธ๊ฐ ํจ์ฌ ๋ ๋นจ๋ฆฌ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ฅผ ์์ํ ์ ์๋๋ก ํ์ฌ ์ธ์ง๋ ์ฑ๋ฅ์ ํฅ์์ํต๋๋ค.
FastAPI๋ ์ฃผ๋ก ๋ ๊ฐ์ง ๋ฉ์ปค๋์ฆ์ ํตํด ์คํธ๋ฆฌ๋ฐ์ ์ง์ํฉ๋๋ค.
- ์์ฑ๊ธฐ ๋ฐ ๋น๋๊ธฐ ์์ฑ๊ธฐ: Python์ ๋ด์ฅ ์์ฑ๊ธฐ ํจ์๋ ์คํธ๋ฆฌ๋ฐ์ ์ ํฉํฉ๋๋ค. FastAPI๋ ์์ฑ๊ธฐ ๋ฐ ๋น๋๊ธฐ ์์ฑ๊ธฐ์์ ์๋ต์ ์๋์ผ๋ก ์คํธ๋ฆฌ๋ฐํ ์ ์์ต๋๋ค.
- `StreamingResponse` ํด๋์ค: ๋ณด๋ค ์ธ๋ถํ๋ ์ ์ด๋ฅผ ์ํด FastAPI๋ ์๋ต ๋ณธ๋ฌธ์ ์์ฑํ๊ธฐ ์ํด ์ฌ์ฉ์ ์ง์ ๋ฐ๋ณต๊ธฐ ๋๋ ๋น๋๊ธฐ ๋ฐ๋ณต๊ธฐ๋ฅผ ์ง์ ํ ์ ์๋ `StreamingResponse` ํด๋์ค๋ฅผ ์ ๊ณตํฉ๋๋ค.
์์ฑ๊ธฐ๋ฅผ ์ฌ์ฉํ ์คํธ๋ฆฌ๋ฐ
FastAPI์์ ์คํธ๋ฆฌ๋ฐ์ ๊ตฌํํ๋ ๊ฐ์ฅ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ ์๋ํฌ์ธํธ์์ ์์ฑ๊ธฐ ๋๋ ๋น๋๊ธฐ ์์ฑ๊ธฐ๋ฅผ ๋ฐํํ๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ฉด FastAPI๋ ์์ฑ๊ธฐ๋ฅผ ๋ฐ๋ณตํ๊ณ ์์ฑ๊ธฐ๊ฐ ์์ฑํ ํญ๋ชฉ์ HTTP ์๋ต ๋ณธ๋ฌธ์ ์ฒญํฌ๋ก ์คํธ๋ฆฌ๋ฐํฉ๋๋ค.
์ค ๋จ์๋ก ํฐ CSV ํ์ผ์ ์์ฑํ๋ ๊ฒ์ ์๋ฎฌ๋ ์ด์ ํ๋ ์๋ฅผ ๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
from fastapi import FastAPI
from typing import AsyncGenerator
app = FastAPI()
async def generate_csv_rows() -> AsyncGenerator[str, None]:
# Simulate generating header
yield "id,name,value\n"
# Simulate generating a large number of rows
for i in range(1000000):
yield f"{i},item_{i},{i*1.5}\n"
# In a real-world scenario, you might fetch data from a database, file, or external service here.
# Consider adding a small delay if you're simulating a very fast generator to observe streaming behavior.
# import asyncio
# await asyncio.sleep(0.001)
@app.get("/stream-csv")
async def stream_csv():
return generate_csv_rows()
์ด ์์์ generate_csv_rows๋ ๋น๋๊ธฐ ์์ฑ๊ธฐ์
๋๋ค. FastAPI๋ ์ด๋ฅผ ์๋์ผ๋ก ๊ฐ์งํ๊ณ ์์ฑ๊ธฐ๊ฐ ์์ฑํ ๊ฐ ๋ฌธ์์ด์ HTTP ์๋ต ๋ณธ๋ฌธ์ ์ฒญํฌ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ํด๋ผ์ด์ธํธ๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ง์ ์ผ๋ก ์์ ํ์ฌ ์๋ฒ์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ํฌ๊ฒ ์ค์
๋๋ค.
`StreamingResponse`๋ฅผ ์ฌ์ฉํ ์คํธ๋ฆฌ๋ฐ
`StreamingResponse` ํด๋์ค๋ ๋ ๋ง์ ์ ์ฐ์ฑ์ ์ ๊ณตํฉ๋๋ค. ๋ฐ๋ณต ๊ฐ๋ฅ ํญ๋ชฉ ๋๋ ๋น๋๊ธฐ ๋ฐ๋ณต๊ธฐ๋ฅผ ๋ฐํํ๋ ํธ์ถ ๊ฐ๋ฅ ํญ๋ชฉ์ ํด๋น ์์ฑ์์ ์ ๋ฌํ ์ ์์ต๋๋ค. ์ด๋ ์คํธ๋ฆฌ๋ฐ๋ ์ฝํ ์ธ ์ ํจ๊ป ์ฌ์ฉ์ ์ง์ ๋ฏธ๋์ด ์ ํ, ์ํ ์ฝ๋ ๋๋ ํค๋๋ฅผ ์ค์ ํด์ผ ํ๋ ๊ฒฝ์ฐ์ ํนํ ์ ์ฉํฉ๋๋ค.
`StreamingResponse`๋ฅผ ์ฌ์ฉํ์ฌ JSON ๋ฐ์ดํฐ๋ฅผ ์คํธ๋ฆฌ๋ฐํ๋ ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import json
from typing import AsyncGenerator
app = FastAPI()
def generate_json_objects() -> AsyncGenerator[str, None]:
# Simulate generating a stream of JSON objects
yield "["
for i in range(1000):
data = {
"id": i,
"name": f"Object {i}",
"timestamp": "2023-10-27T10:00:00Z"
}
yield json.dumps(data)
if i < 999:
yield ","
# Simulate asynchronous operation
# import asyncio
# await asyncio.sleep(0.01)
yield "]"
@app.get("/stream-json")
async def stream_json():
# We can specify the media_type to inform the client it's receiving JSON
return StreamingResponse(generate_json_objects(), media_type="application/json")
์ด `stream_json` ์๋ํฌ์ธํธ์์:
- JSON ๋ฌธ์์ด์ ์์ฑํ๋ ๋น๋๊ธฐ ์์ฑ๊ธฐ
generate_json_objects๋ฅผ ์ ์ํฉ๋๋ค. ์ ํจํ JSON์ ๊ฒฝ์ฐ ์ฌ๋ ๋๊ดํธ `[`, ๋ซ๋ ๋๊ดํธ `]` ๋ฐ ๊ฐ์ฒด ์ฌ์ด์ ์ผํ๋ฅผ ์๋์ผ๋ก ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค. - ์์ฑ๊ธฐ๋ฅผ ์ ๋ฌํ๊ณ
media_type์application/json์ผ๋ก ์ค์ ํ์ฌStreamingResponse๋ฅผ ์ธ์คํด์คํํฉ๋๋ค. ์ด๋ ํด๋ผ์ด์ธํธ๊ฐ ์คํธ๋ฆฌ๋ฐ๋ ๋ฐ์ดํฐ๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ํด์ํ๋ ๋ฐ ์ค์ํฉ๋๋ค.
์ด ์ ๊ทผ ๋ฐฉ์์ ํ ๋ฒ์ ํ๋์ JSON ๊ฐ์ฒด(๋๋ JSON ๋ฐฐ์ด์ ์์ ์ฒญํฌ)๋ง ๋ฉ๋ชจ๋ฆฌ์์ ์ฒ๋ฆฌํ๋ฉด ๋๋ฏ๋ก ๋งค์ฐ ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ ๋๋ค.
FastAPI ์คํธ๋ฆฌ๋ฐ์ ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก
FastAPI ์คํธ๋ฆฌ๋ฐ์ ๋งค์ฐ ๋ค์ฌ๋ค๋ฅํ๋ฉฐ ๊ด๋ฒ์ํ ์๋๋ฆฌ์ค์ ์ ์ฉํ ์ ์์ต๋๋ค.
1. ๋์ฉ๋ ํ์ผ ๋ค์ด๋ก๋
์ ์ฒด ๋์ฉ๋ ํ์ผ์ ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋ํ๋ ๋์ ํด๋น ๋ด์ฉ์ ํด๋ผ์ด์ธํธ์ ์ง์ ์คํธ๋ฆฌ๋ฐํ ์ ์์ต๋๋ค.
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import os
app = FastAPI()
# Assume 'large_file.txt' is a large file in your system
FILE_PATH = "large_file.txt"
async def iter_file(file_path: str):
with open(file_path, mode="rb") as file:
while chunk := file.read(8192): # Read in chunks of 8KB
yield chunk
@app.get("/download-file/{filename}")
async def download_file(filename: str):
if not os.path.exists(FILE_PATH):
return {"error": "File not found"}
# Set appropriate headers for download
headers = {
"Content-Disposition": f"attachment; filename=\"{filename}\""
}
return StreamingResponse(iter_file(FILE_PATH), media_type="application/octet-stream", headers=headers)
์ฌ๊ธฐ์ iter_file์ ํ์ผ์ ์ฒญํฌ ๋จ์๋ก ์ฝ๊ณ ์ต์ํ์ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๋ณด์ฅํ๋ฉด์ ํ์ผ์ ์์ฑํฉ๋๋ค. Content-Disposition ํค๋๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์ง์ ๋ ํ์ผ ์ด๋ฆ์ผ๋ก ๋ค์ด๋ก๋๋ฅผ ์์ฒญํ๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค.
2. ์ค์๊ฐ ๋ฐ์ดํฐ ํผ๋ ๋ฐ ๋ก๊ทธ
์ฃผ์ ์์ธ, ์ผ์ ํ๋ ๊ฐ ๋๋ ์์คํ ๋ก๊ทธ์ ๊ฐ์ด ์ง์์ ์ผ๋ก ์ ๋ฐ์ดํธ๋๋ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ ์คํธ๋ฆฌ๋ฐ์ด ์ด์์ ์ธ ์๋ฃจ์ ์ ๋๋ค.
์๋ฒ ์ ์ก ์ด๋ฒคํธ(SSE)
์๋ฒ ์ ์ก ์ด๋ฒคํธ(SSE)๋ ์๋ฒ๊ฐ ๋จ์ผ์ ์ฅ๊ธฐ ์คํ HTTP ์ฐ๊ฒฐ์ ํตํด ํด๋ผ์ด์ธํธ์ ๋ฐ์ดํฐ๋ฅผ ํธ์ํ ์ ์๋๋ก ํ๋ ํ์ค์ ๋๋ค. FastAPI๋ SSE์ ์ํํ๊ฒ ํตํฉ๋ฉ๋๋ค.
from fastapi import FastAPI, Request
from fastapi.responses import SSE
import asyncio
import time
app = FastAPI()
def generate_sse_messages(request: Request):
count = 0
while True:
if await request.is_disconnected():
print("Client disconnected")
break
now = time.strftime("%Y-%m-%dT%H:%M:%SZ")
message = f"{{'event': 'update', 'data': {{'timestamp': '{now}', 'value': {count}}}}}}"
yield f"data: {message}\n\n"
count += 1
await asyncio.sleep(1) # Send an update every second
@app.get("/stream-logs")
async def stream_logs(request: Request):
return SSE(generate_sse_messages(request), media_type="text/event-stream")
์ด ์์์:
generate_sse_messages๋ SSE ํ์์ผ๋ก ๋ฉ์์ง๋ฅผ ์ง์์ ์ผ๋ก ์์ฑํ๋ ๋น๋๊ธฐ ์์ฑ๊ธฐ์ ๋๋ค(data: ...).Request๊ฐ์ฒด๋ ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๊ฒฐ์ ๋์๋์ง ํ์ธํ๋ ๋ฐ ์ ๋ฌ๋์ด ์คํธ๋ฆผ์ ์ ์์ ์ผ๋ก ์ค์งํ ์ ์์ต๋๋ค.SSE์๋ต ์ ํ์ด ์ฌ์ฉ๋์ดmedia_type์text/event-stream์ผ๋ก ์ค์ ํฉ๋๋ค.
SSE๋ ๋๋ฆฌ ์ง์๋๋ HTTP๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ํจ์จ์ ์ด๋ฉฐ ์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก์ ๋จ๋ฐฉํฅ ํต์ ์ ์ํด WebSockets๋ณด๋ค ๊ตฌํํ๊ธฐ๊ฐ ๋ ๊ฐ๋จํฉ๋๋ค.
3. ๋๊ท๋ชจ ๋ฐ์ดํฐ ์ธํธ๋ฅผ ์ผ๊ด ์ฒ๋ฆฌ๋ก ์ฒ๋ฆฌ
๋๊ท๋ชจ ๋ฐ์ดํฐ ์ธํธ๋ฅผ ์ฒ๋ฆฌํ ๋(์: ๋ถ์ ๋๋ ๋ณํ) ์ ์ฒด ํ๋ก์ธ์ค๊ฐ ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋ ๋์ ๊ฐ ๋ฐฐ์น์ ๊ฒฐ๊ณผ๋ฅผ ๊ณ์ฐ๋๋ ๋๋ก ์คํธ๋ฆฌ๋ฐํ ์ ์์ต๋๋ค.
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import random
app = FastAPI()
def process_data_in_batches(num_batches: int, batch_size: int):
for batch_num in range(num_batches):
batch_results = []
for _ in range(batch_size):
# Simulate data processing
result = {
"id": random.randint(1000, 9999),
"value": random.random() * 100
}
batch_results.append(result)
# Yield the processed batch as a JSON string
import json
yield json.dumps(batch_results)
# Simulate time between batches
# import asyncio
# await asyncio.sleep(0.5)
@app.get("/stream-batches")
async def stream_batches(num_batches: int = 10, batch_size: int = 100):
# Note: For true async, the generator itself should be async.
# For simplicity here, we use a synchronous generator with `StreamingResponse`.
# A more advanced approach would involve an async generator and potentially async operations within.
return StreamingResponse(process_data_in_batches(num_batches, batch_size), media_type="application/json")
์ด๋ฅผ ํตํด ํด๋ผ์ด์ธํธ๋ ๋์ค์ ๋ฐฐ์น๊ฐ ์์ง ๊ณ์ฐ ์ค์ธ ๋์ ์ด์ ๋ฐฐ์น์ ๊ฒฐ๊ณผ๋ฅผ ์์ ํ๊ณ ์ฒ๋ฆฌ๋ฅผ ์์ํ ์ ์์ต๋๋ค. ๋ฐฐ์น ๋ด์์ ์ง์ ํ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ํด์๋ ์์ฑ๊ธฐ ํจ์ ์์ฒด๊ฐ ๋น๋๊ธฐ ์์ฑ๊ธฐ์ฌ์ผ ํ๋ฉฐ ๊ฒฐ๊ณผ๊ฐ ๋น๋๊ธฐ์ ์ผ๋ก ์ฌ์ฉ ๊ฐ๋ฅํ๊ฒ ๋๋ฉด ๊ฒฐ๊ณผ๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค.
FastAPI ์คํธ๋ฆฌ๋ฐ์ ๋ํ ๊ธ๋ก๋ฒ ๊ณ ๋ ค ์ฌํญ
๊ธ๋ก๋ฒ ๋์์ ์ํ ์คํธ๋ฆฌ๋ฐ API๋ฅผ ์ค๊ณํ๊ณ ๊ตฌํํ ๋๋ ๋ช ๊ฐ์ง ์์๊ฐ ์ค์ํฉ๋๋ค.
1. ๋คํธ์ํฌ ๋๊ธฐ ์๊ฐ ๋ฐ ๋์ญํญ
์ ์ธ๊ณ ์ฌ์ฉ์๋ ๋งค์ฐ ๋ค๋ฅธ ๋คํธ์ํฌ ์กฐ๊ฑด์ ๊ฒฝํํฉ๋๋ค. ์คํธ๋ฆฌ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ง์ ์ผ๋ก ์ ์กํ์ฌ ๋๊ธฐ ์๊ฐ์ ์ํํ๋ ๋ฐ ๋์์ด ๋์ง๋ง ์ ์ฒด์ ์ธ ๊ฒฝํ์ ์ฌ์ ํ ๋์ญํญ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ค. ๋ค์ ์ฌํญ์ ๊ณ ๋ คํ์ญ์์ค.
- ์ฒญํฌ ํฌ๊ธฐ: ์ต์ ์ ์ฒญํฌ ํฌ๊ธฐ๋ฅผ ์คํํฉ๋๋ค. ๋๋ฌด ์์ผ๋ฉด ๊ฐ ์ฒญํฌ์ ๋ํ HTTP ํค๋์ ์ค๋ฒํค๋๊ฐ ์ค์ํด์ง ์ ์์ต๋๋ค. ๋๋ฌด ํฌ๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋ฌธ์ ๋ ์ฒญํฌ ๊ฐ์ ๊ธด ๋๊ธฐ ์๊ฐ์ด ๋ค์ ๋ฐ์ํ ์ ์์ต๋๋ค.
- ์์ถ: HTTP ์์ถ(์: Gzip)์ ์ฌ์ฉํ์ฌ ์ ์ก๋๋ ๋ฐ์ดํฐ ์์ ์ค์
๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ ์ ์ ํ
Accept-Encodingํค๋๋ฅผ ๋ณด๋ด๋ฉด FastAPI๊ฐ ์ด๋ฅผ ์๋์ผ๋ก ์ง์ํฉ๋๋ค. - ์ฝํ ์ธ ์ ์ก ๋คํธ์ํฌ(CDN): ์บ์ํ ์ ์๋ ์ ์ ์์ฐ ๋๋ ๋์ฉ๋ ํ์ผ์ ๊ฒฝ์ฐ CDN์ ์ ์ธ๊ณ ์ฌ์ฉ์์๊ฒ ์ ์ก ์๋๋ฅผ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค.
2. ํด๋ผ์ด์ธํธ ์ธก ์ฒ๋ฆฌ
ํด๋ผ์ด์ธํธ๋ ์คํธ๋ฆฌ๋ฐ๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ค๋น๊ฐ ๋์ด ์์ด์ผ ํฉ๋๋ค. ์ฌ๊ธฐ์๋ ๋ค์์ด ํฌํจ๋ฉ๋๋ค.
- ๋ฒํผ๋ง: ํด๋ผ์ด์ธํธ๋ ํนํ ๊ตฌ๋ถ ๊ธฐํธ๊ฐ ์ค์ํ JSON ๋ฐฐ์ด๊ณผ ๊ฐ์ ํ์์ ๊ฒฝ์ฐ ์ฒ๋ฆฌํ๊ธฐ ์ ์ ๋ค์ด์ค๋ ์ฒญํฌ๋ฅผ ๋ฒํผ๋งํด์ผ ํ ์ ์์ต๋๋ค.
- ์ค๋ฅ ์ฒ๋ฆฌ: ์ฐ๊ฒฐ ๋๊น ๋๋ ๋ถ์์ ํ ์คํธ๋ฆผ์ ๋ํ ๊ฐ๋ ฅํ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ๊ตฌํํฉ๋๋ค.
- ๋น๋๊ธฐ ์ฒ๋ฆฌ: ํด๋ผ์ด์ธํธ ์ธก JavaScript(์น ๋ธ๋ผ์ฐ์ ์์)๋ ๋ฉ์ธ ์ค๋ ๋๋ฅผ ์ฐจ๋จํ์ง ์๊ณ ์คํธ๋ฆฌ๋ฐ๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๋น๋๊ธฐ ํจํด(์:
ReadableStream๋๋ SSE์ ๊ฒฝ์ฐ `EventSource`๊ฐ ์๋fetch)์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
์๋ฅผ ๋ค์ด ์คํธ๋ฆฌ๋ฐ๋ JSON ๋ฐฐ์ด์ ์์ ํ๋ JavaScript ํด๋ผ์ด์ธํธ๋ ์ฒญํฌ๋ฅผ ๊ตฌ๋ฌธ ๋ถ์ํ๊ณ ๋ฐฐ์ด ๊ตฌ์ฑ์ ๊ด๋ฆฌํด์ผ ํฉ๋๋ค.
3. ๊ตญ์ ํ(i18n) ๋ฐ ํ์งํ(l10n)
์คํธ๋ฆฌ๋ฐ๋ ๋ฐ์ดํฐ์ ํ ์คํธ๊ฐ ํฌํจ๋ ๊ฒฝ์ฐ ๋ค์ ์ฌํญ์ ์ํฅ์ ๊ณ ๋ คํ์ญ์์ค.
- ๋ฌธ์ ์ธ์ฝ๋ฉ: ๋ค์ํ ์ธ์ด์ ๊ด๋ฒ์ํ ๋ฌธ์๋ฅผ ์ง์ํ๊ธฐ ์ํด ํ ์คํธ ๊ธฐ๋ฐ ์คํธ๋ฆฌ๋ฐ ์๋ต์๋ ํญ์ UTF-8์ ์ฌ์ฉํฉ๋๋ค.
- ๋ฐ์ดํฐ ํ์: ๋ ์ง, ์ซ์ ๋ฐ ํตํ๊ฐ ์คํธ๋ฆฌ๋ฐ๋ ๋ฐ์ดํฐ์ ์ผ๋ถ์ธ ๊ฒฝ์ฐ ์๋ก ๋ค๋ฅธ ๋ก์ผ์ผ์ ๋ง๊ฒ ์ฌ๋ฐ๋ฅด๊ฒ ํ์์ด ์ง์ ๋์๋์ง ํ์ธํฉ๋๋ค. FastAPI๋ ์ฃผ๋ก ์์ ๋ฐ์ดํฐ๋ฅผ ์คํธ๋ฆฌ๋ฐํ์ง๋ง ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๋ ์ ํ๋ฆฌ์ผ์ด์ ๋ก์ง์ i18n/l10n์ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.
- ์ธ์ด๋ณ ์ฝํ ์ธ : ์คํธ๋ฆฌ๋ฐ๋ ์ฝํ ์ธ ๊ฐ ์ฌ๋์ด ์๋นํ๊ธฐ ์ํ ๊ฒ(์: ๋ฉ์์ง๊ฐ ์๋ ๋ก๊ทธ)์ธ ๊ฒฝ์ฐ ํด๋ผ์ด์ธํธ ๊ธฐ๋ณธ ์ค์ ์ ๋ฐ๋ผ ํ์งํ๋ ๋ฒ์ ์ ์ ๊ณตํ๋ ๋ฐฉ๋ฒ์ ๊ณ ๋ คํ์ญ์์ค.
4. API ์ค๊ณ ๋ฐ ์ค๋ช ์
๋ช ํํ ์ค๋ช ์๋ ๊ธ๋ก๋ฒ ์ฑํ์ ๊ฐ์ฅ ์ค์ํฉ๋๋ค.
- ์คํธ๋ฆฌ๋ฐ ๋์ ๋ฌธ์ํ: ์๋ํฌ์ธํธ๊ฐ ์คํธ๋ฆฌ๋ฐ๋ ์๋ต์ ๋ฐํํ๊ณ , ํ์์ด ๋ฌด์์ด๋ฉฐ, ํด๋ผ์ด์ธํธ๊ฐ ์ด๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ API ์ค๋ช ์์ ๋ช ์์ ์ผ๋ก ์ค๋ช ํฉ๋๋ค.
- ํด๋ผ์ด์ธํธ ์์ ์ ๊ณต: ์คํธ๋ฆฌ๋ฐ๋ ์๋ํฌ์ธํธ๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ฃผ๋ ์ธ๊ธฐ ์๋ ์ธ์ด(Python, JavaScript ๋ฑ)์ ์ฝ๋ ์ค๋ํซ์ ์ ๊ณตํฉ๋๋ค.
- ๋ฐ์ดํฐ ํ์ ์ค๋ช : ์ฌ์ฉ๋ ํน์ ๋ง์ปค ๋๋ ๊ตฌ๋ถ ๊ธฐํธ๋ฅผ ํฌํจํ์ฌ ์คํธ๋ฆฌ๋ฐ๋ ๋ฐ์ดํฐ์ ๊ตฌ์กฐ์ ํ์์ ๋ช ํํ๊ฒ ์ ์ํฉ๋๋ค.
๊ณ ๊ธ ๊ธฐ์ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
1. ์์ฑ๊ธฐ ๋ด์์ ๋น๋๊ธฐ ์์ ์ฒ๋ฆฌ
๋ฐ์ดํฐ ์์ฑ์ I/O ๋ฐ์ธ๋ฉ ์์ (์: ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ, ์ธ๋ถ API ํธ์ถ)์ด ํฌํจ๋๋ ๊ฒฝ์ฐ ์์ฑ๊ธฐ ํจ์๊ฐ ๋น๋๊ธฐ์ธ์ง ํ์ธํฉ๋๋ค.
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import asyncio
import httpx # A popular async HTTP client
app = FastAPI()
async def stream_external_data():
async with httpx.AsyncClient() as client:
try:
response = await client.get("https://api.example.com/large-dataset")
response.raise_for_status() # Raise an exception for bad status codes
# Assume response.iter_bytes() yields chunks of the response
async for chunk in response.aiter_bytes():
yield chunk
await asyncio.sleep(0.01) # Small delay to allow other tasks
except httpx.HTTPStatusError as e:
yield f"Error fetching data: {e}"
except httpx.RequestError as e:
yield f"Network error: {e}"
@app.get("/stream-external")
async def stream_external():
return StreamingResponse(stream_external_data(), media_type="application/octet-stream")
httpx.AsyncClient ๋ฐ response.aiter_bytes()๋ฅผ ์ฌ์ฉํ๋ฉด ๋คํธ์ํฌ ์์ฒญ์ด ์ฐจ๋จ๋์ง ์์ ์๋ฒ๊ฐ ์ธ๋ถ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ๋ค๋ฅธ ์์ฒญ์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
2. ๋๊ท๋ชจ JSON ์คํธ๋ฆผ ๊ด๋ฆฌ
์ ์ฒด JSON ๋ฐฐ์ด์ ์คํธ๋ฆฌ๋ฐํ๋ ค๋ฉด ์์์ ์ค๋ช ํ ๋๋ก ๋๊ดํธ์ ์ผํ๋ฅผ ์ฃผ์ํด์ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค. ๋งค์ฐ ํฐ JSON ๋ฐ์ดํฐ ์ธํธ์ ๊ฒฝ์ฐ ๋์ฒด ํ์ ๋๋ ํ๋กํ ์ฝ์ ๊ณ ๋ คํ์ญ์์ค.
- JSON Lines(JSONL): ํ์ผ/์คํธ๋ฆผ์ ๊ฐ ์ค์ ์ ํจํ JSON ๊ฐ์ฒด์ ๋๋ค. ์ด๋ ์ ์ง์ ์ผ๋ก ์์ฑํ๊ณ ๊ตฌ๋ฌธ ๋ถ์ํ๊ธฐ๊ฐ ๋ ๊ฐ๋จํฉ๋๋ค.
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import json
app = FastAPI()
def generate_json_lines():
for i in range(1000):
data = {
"id": i,
"name": f"Record {i}"
}
yield json.dumps(data) + "\n"
# Simulate async work if necessary
# import asyncio
# await asyncio.sleep(0.005)
@app.get("/stream-json-lines")
async def stream_json_lines():
return StreamingResponse(generate_json_lines(), media_type="application/x-jsonlines")
application/x-jsonlines ๋ฏธ๋์ด ์ ํ์ ์ข
์ข
JSON Lines ํ์์ ์ฌ์ฉ๋ฉ๋๋ค.
3. ์ฒญํฌ ๋ถํ ๋ฐ ๋ฐฑํ๋ ์
์ฒ๋ฆฌ๋์ด ๋ง์ ์๋๋ฆฌ์ค์์๋ ์์ฐ์(API)๊ฐ ์๋น์(ํด๋ผ์ด์ธํธ)๊ฐ ์ฒ๋ฆฌํ ์ ์๋ ๊ฒ๋ณด๋ค ๋ ๋น ๋ฅด๊ฒ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์ด๋ก ์ธํด ํด๋ผ์ด์ธํธ ๋๋ ์ค๊ฐ ๋คํธ์ํฌ ์ฅ์น์์ ๋ฉ๋ชจ๋ฆฌ ์ถ์ ์ด ๋ฐ์ํ ์ ์์ต๋๋ค. FastAPI ์์ฒด๋ ํ์ค HTTP ์คํธ๋ฆฌ๋ฐ์ ๋ํ ๋ช ์์ ์ธ ๋ฐฑํ๋ ์ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ์ง ์์ง๋ง ๋ค์์ ๊ตฌํํ ์ ์์ต๋๋ค.
- ์ ์ด๋ ์์ฑ: ํ์ํ ๊ฒฝ์ฐ ์์ฑ ์๋๋ฅผ ๋ฆ์ถ๊ธฐ ์ํด ์์ฑ๊ธฐ ๋ด์์ ์์ ์ง์ฐ(์์ ์์ ๋ณผ ์ ์์)์ ๋์ ํฉ๋๋ค.
- SSE๋ฅผ ์ฌ์ฉํ ํ๋ฆ ์ ์ด: SSE๋ ์ด๋ฒคํธ ๊ธฐ๋ฐ ํน์ฑ์ผ๋ก ์ธํด ์ด๋ฌํ ์ธก๋ฉด์์ ๋ณธ์ง์ ์ผ๋ก ๋ ๊ฐ๋ ฅํ์ง๋ง ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ๋ผ ๋ช ์์ ์ธ ํ๋ฆ ์ ์ด ๋ก์ง์ด ์ฌ์ ํ ํ์ํ ์ ์์ต๋๋ค.
- WebSockets: ๊ฐ๋ ฅํ ํ๋ฆ ์ ์ด๋ฅผ ํตํ ์๋ฐฉํฅ ํต์ ์ ๊ฒฝ์ฐ WebSockets๊ฐ ๋ ์ ํฉํ ์ ํ์ด์ง๋ง HTTP ์คํธ๋ฆฌ๋ฐ๋ณด๋ค ๋ ๋ณต์กํฉ๋๋ค.
4. ์ค๋ฅ ์ฒ๋ฆฌ ๋ฐ ์ฌ์ฐ๊ฒฐ
ํนํ ์ ์ฌ์ ์ผ๋ก ์ ๋ขฐํ ์ ์๋ ๋คํธ์ํฌ๋ฅผ ํตํด ๋ง์ ์์ ๋ฐ์ดํฐ๋ฅผ ์คํธ๋ฆฌ๋ฐํ ๋๋ ๊ฐ๋ ฅํ ์ค๋ฅ ์ฒ๋ฆฌ ๋ฐ ์ฌ์ฐ๊ฒฐ ์ ๋ต์ด ์ฐ์ํ ๊ธ๋ก๋ฒ ์ฌ์ฉ์ ํ๊ฒฝ์ ๋งค์ฐ ์ค์ํฉ๋๋ค.
- ๋ฉฑ๋ฑ์ฑ: ๊ฐ๋ฅํ ๊ฒฝ์ฐ ์คํธ๋ฆผ์ด ์ค๋จ๋๋ฉด ํด๋ผ์ด์ธํธ๊ฐ ์์ ์ ์ฌ๊ฐํ ์ ์๋๋ก API๋ฅผ ์ค๊ณํฉ๋๋ค.
- ์ค๋ฅ ๋ฉ์์ง: ์คํธ๋ฆผ ๋ด์ ์ค๋ฅ ๋ฉ์์ง๊ฐ ๋ช ํํ๊ณ ์ ์ตํ์ง ํ์ธํฉ๋๋ค.
- ํด๋ผ์ด์ธํธ ์ธก ์ฌ์๋: ์ฐ๊ฒฐ ์ฌ์๋ ๋๋ ์คํธ๋ฆผ ์ฌ๊ฐ๋ฅผ ์ํ ํด๋ผ์ด์ธํธ ์ธก ๋ก์ง์ ๊ถ์ฅํ๊ฑฐ๋ ๊ตฌํํฉ๋๋ค. SSE์ ๊ฒฝ์ฐ ๋ธ๋ผ์ฐ์ ์ `EventSource` API์๋ ๊ธฐ๋ณธ ์ ๊ณต ์ฌ์ฐ๊ฒฐ ๋ก์ง์ด ์์ต๋๋ค.
์ฑ๋ฅ ๋ฒค์น๋งํน ๋ฐ ์ต์ ํ
์คํธ๋ฆฌ๋ฐ API๊ฐ ๊ธ๋ก๋ฒ ์ฌ์ฉ์ ๊ธฐ๋ฐ์ ๋ํด ์ต์ ์ผ๋ก ์ํ๋๋๋ก ํ๋ ค๋ฉด ์ ๊ธฐ์ ์ธ ๋ฒค์น๋งํน์ด ํ์์ ์ ๋๋ค.
- ๋๊ตฌ:
wrk,locust๋๋ ํน์ ๋ก๋ ํ ์คํธ ํ๋ ์์ํฌ์ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ์๋ก ๋ค๋ฅธ ์ง๋ฆฌ์ ์์น์ ๋์ ์ฌ์ฉ์๋ฅผ ์๋ฎฌ๋ ์ด์ ํฉ๋๋ค. - ๋ฉํธ๋ฆญ: ์๋ฒ์์ ์๋ต ์๊ฐ, ์ฒ๋ฆฌ๋, ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ๋ฐ CPU ์ฌ์ฉ๋๊ณผ ๊ฐ์ ์ฃผ์ ๋ฉํธ๋ฆญ์ ๋ชจ๋ํฐ๋งํฉ๋๋ค.
- ๋คํธ์ํฌ ์๋ฎฌ๋ ์ด์
: ๋ธ๋ผ์ฐ์ ๊ฐ๋ฐ์ ๋๊ตฌ์
toxiproxy๋๋ ๋คํธ์ํฌ ์ ํ๊ณผ ๊ฐ์ ๋๊ตฌ๋ ๋ค์ํ ๋คํธ์ํฌ ์กฐ๊ฑด(๋๊ธฐ ์๊ฐ, ํจํท ์์ค)์ ์๋ฎฌ๋ ์ด์ ํ์ฌ API๊ฐ ์คํธ๋ ์ค ์ํ์์ ์ด๋ป๊ฒ ์๋ํ๋์ง ํ ์คํธํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค. - ํ๋กํ์ผ๋ง: Python ํ๋กํ์ผ๋ฌ(์:
cProfile,line_profiler)๋ฅผ ์ฌ์ฉํ์ฌ ์คํธ๋ฆฌ๋ฐ ์์ฑ๊ธฐ ํจ์ ๋ด์ ๋ณ๋ชฉ ํ์์ ์๋ณํฉ๋๋ค.
๊ฒฐ๋ก
Python FastAPI์ ์คํธ๋ฆฌ๋ฐ ๊ธฐ๋ฅ์ ๋์ฉ๋ ์๋ต์ ์ฒ๋ฆฌํ๊ธฐ ์ํ ๊ฐ๋ ฅํ๊ณ ํจ์จ์ ์ธ ์๋ฃจ์ ์ ์ ๊ณตํฉ๋๋ค. ๋น๋๊ธฐ ์์ฑ๊ธฐ ๋ฐ `StreamingResponse` ํด๋์ค๋ฅผ ํ์ฉํ์ฌ ๊ฐ๋ฐ์๋ ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ด๊ณ ์ฑ๋ฅ์ด ๋ฐ์ด๋๋ฉฐ ์ ์ธ๊ณ ์ฌ์ฉ์์๊ฒ ๋ ๋์ ๊ฒฝํ์ ์ ๊ณตํ๋ API๋ฅผ ๊ตฌ์ถํ ์ ์์ต๋๋ค.
๊ธ๋ก๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ด์ฌ๋ ๋ค์ํ ๋คํธ์ํฌ ์กฐ๊ฑด, ํด๋ผ์ด์ธํธ ๊ธฐ๋ฅ ๋ฐ ๊ตญ์ ํ ์๊ตฌ ์ฌํญ์ ๊ณ ๋ คํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค. ์ ์คํ ์ค๊ณ, ์ฒ ์ ํ ํ ์คํธ ๋ฐ ๋ช ํํ ์ค๋ช ์๋ฅผ ํตํด FastAPI ์คํธ๋ฆฌ๋ฐ API๊ฐ ์ ์ธ๊ณ ์ฌ์ฉ์์๊ฒ ๋๊ท๋ชจ ๋ฐ์ดํฐ ์ธํธ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ ๋ฌํ ์ ์์ต๋๋ค. ์คํธ๋ฆฌ๋ฐ์ ์์ฉํ๊ณ ๋ฐ์ดํฐ ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ฌ๋ ฅ์ ์ต๋ํ ํ์ฉํ์ญ์์ค.