--- /dev/null
+# ๋ฐ์ดํธ๋ฅผ Base64๋ก ํฌํจํ๋ JSON { #json-with-bytes-as-base64 }
+
+์ ํ๋ฆฌ์ผ์ด์
์์ JSON ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์์ผ ํ์ง๋ง ๊ทธ ์์ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ํฌํจํด์ผ ํ๋ค๋ฉด, base64๋ก ์ธ์ฝ๋ฉํด์ ํฌํจํ ์ ์์ต๋๋ค.
+
+## Base64์ ํ์ผ { #base64-vs-files }
+
+๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ ์
๋ก๋์๋ [์์ฒญ ํ์ผ](../tutorial/request-files.md)์, ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ ์ ์ก์๋ [์ปค์คํ
์๋ต - FileResponse](./custom-response.md#fileresponse--fileresponse-)๋ฅผ ์ฌ์ฉํ ์ ์๋์ง ๋จผ์ ๊ณ ๋ คํ์ธ์. JSON์ผ๋ก ์ธ์ฝ๋ฉํ๋ ๋์ ๋ง์
๋๋ค.
+
+JSON์ UTF-8๋ก ์ธ์ฝ๋ฉ๋ ๋ฌธ์์ด๋ง ํฌํจํ ์ ์์ผ๋ฏ๋ก, ์์ ๋ฐ์ดํธ๋ฅผ ๊ทธ๋๋ก ๋ด์ ์ ์์ต๋๋ค.
+
+Base64๋ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ๋ฌธ์์ด๋ก ์ธ์ฝ๋ฉํ ์ ์์ง๋ง, ์ด๋ฅผ ์ํด ์๋์ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ณด๋ค ๋ ๋ง์ ๋ฌธ์ ์๋ฅผ ์ฌ์ฉํด์ผ ํ๋ฏ๋ก ์ผ๋ฐ์ ์ธ ํ์ผ ์ ์ก๋ณด๋ค ๋นํจ์จ์ ์ผ ์ ์์ต๋๋ค.
+
+๋ฐ๋์ JSON ์์ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ํฌํจํด์ผ ํ๊ณ , ํ์ผ์ ์ฌ์ฉํ ์ ์์ ๋๋ง base64๋ฅผ ์ฌ์ฉํ์ธ์.
+
+## Pydantic `bytes` { #pydantic-bytes }
+
+`bytes` ํ๋๋ฅผ ๊ฐ์ง Pydantic ๋ชจ๋ธ์ ์ ์ธํ๊ณ , ๋ชจ๋ธ ์ค์ ์์ `val_json_bytes`๋ฅผ ์ฌ์ฉํ๋๋ก ์ง์ ํ๋ฉด ์
๋ ฅ JSON ๋ฐ์ดํฐ๋ฅผ base64๋ก โ๊ฒ์ฆโํ๋๋ก ํ ์ ์์ต๋๋ค. ์ด ๊ฒ์ฆ ๊ณผ์ ์ ์ผ๋ถ๋ก base64 ๋ฌธ์์ด์ ๋ฐ์ดํธ๋ก ๋์ฝ๋ฉํฉ๋๋ค.
+
+{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}
+
+`/docs`๋ฅผ ํ์ธํ๋ฉด `data` ํ๋๊ฐ base64๋ก ์ธ์ฝ๋ฉ๋ bytes๋ฅผ ๊ธฐ๋ํ๋ค๊ณ ํ์๋ฉ๋๋ค:
+
+<div class="screenshot">
+<img src="/img/tutorial/json-base64-bytes/image01.png">
+</div>
+
+์๋์ ๊ฐ์ ์์ฒญ์ ๋ณด๋ผ ์ ์์ต๋๋ค:
+
+```json
+{
+ "description": "Some data",
+ "data": "aGVsbG8="
+}
+```
+
+/// tip | ํ
+
+`aGVsbG8=`๋ `hello`์ base64 ์ธ์ฝ๋ฉ์
๋๋ค.
+
+///
+
+๊ทธ๋ฌ๋ฉด Pydantic์ด base64 ๋ฌธ์์ด์ ๋์ฝ๋ฉํ์ฌ ๋ชจ๋ธ์ `data` ํ๋์ ์๋ ๋ฐ์ดํธ๋ฅผ ์ ๊ณตํฉ๋๋ค.
+
+๋ค์๊ณผ ๊ฐ์ ์๋ต์ ๋ฐ๊ฒ ๋ฉ๋๋ค:
+
+```json
+{
+ "description": "Some data",
+ "content": "hello"
+}
+```
+
+## ์ถ๋ ฅ ๋ฐ์ดํฐ์ฉ Pydantic `bytes` { #pydantic-bytes-for-output-data }
+
+์ถ๋ ฅ ๋ฐ์ดํฐ์๋ ๋ชจ๋ธ ์ค์ ์์ `ser_json_bytes`์ ํจ๊ป `bytes` ํ๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ฉด Pydantic์ด JSON ์๋ต์ ์์ฑํ ๋ ๋ฐ์ดํธ๋ฅผ base64๋ก โ์ง๋ ฌํโํฉ๋๋ค.
+
+{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}
+
+## ์
๋ ฅ๊ณผ ์ถ๋ ฅ ๋ฐ์ดํฐ์ฉ Pydantic `bytes` { #pydantic-bytes-for-input-and-output-data }
+
+๋ฌผ๋ก , ๋์ผํ ๋ชจ๋ธ์ ์ฌ์ฉํด JSON ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ๋๋ `val_json_bytes`๋ก ์
๋ ฅ์ โ๊ฒ์ฆโํ๊ณ , JSON ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ผ ๋๋ `ser_json_bytes`๋ก ์ถ๋ ฅ์ โ์ง๋ ฌํโํ๋๋ก base64๋ฅผ ๋ชจ๋ ์ฒ๋ฆฌํ๊ฒ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
+
+{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}
--- /dev/null
+# ๋ฐ์ดํฐ ์คํธ๋ฆฌ๋ฐ { #stream-data }
+
+JSON์ผ๋ก ๊ตฌ์กฐํํ ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ์คํธ๋ฆฌ๋ฐํ๋ ค๋ฉด [JSON Lines ์คํธ๋ฆฌ๋ฐ](../tutorial/stream-json-lines.md)์ ์ฌ์ฉํ์ธ์.
+
+ํ์ง๋ง ์์ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ ๋ฌธ์์ด์ ์คํธ๋ฆฌ๋ฐํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํ๋ฉด ๋ฉ๋๋ค.
+
+/// info | ์ ๋ณด
+
+FastAPI 0.134.0์ ์ถ๊ฐ๋์์ต๋๋ค.
+
+///
+
+## ์ฌ์ฉ ์์ { #use-cases }
+
+์๋ฅผ ๋ค์ด AI LLM ์๋น์ค์ ์ถ๋ ฅ์์ ๋ฐ๋ก ์์ ๋ฌธ์์ด์ ์คํธ๋ฆฌ๋ฐํ๊ณ ์ถ๋ค๋ฉด ์ด๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
+
+๋ํ ํฐ ๋ฐ์ด๋๋ฆฌ ํ์ผ์ ์คํธ๋ฆฌ๋ฐํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค. ํ ๋ฒ์ ๋ชจ๋ ๋ฉ๋ชจ๋ฆฌ๋ก ์ฝ์ง ์๊ณ , ์ฝ๋ ์ฆ์ ๋ฐ์ดํฐ ์ฒญํฌ๋ฅผ ์์ฐจ์ ์ผ๋ก ์คํธ๋ฆฌ๋ฐํฉ๋๋ค.
+
+์ด ๋ฐฉ์์ผ๋ก ๋น๋์ค๋ ์ค๋์ค๋ฅผ ์คํธ๋ฆฌ๋ฐํ ์๋ ์์ผ๋ฉฐ, ์ฒ๋ฆฌํ๋ฉด์ ์์ฑ๋ ๋ฐ์ดํฐ๋ฅผ ๊ณง๋ฐ๋ก ์ ์กํ ์๋ ์์ต๋๋ค.
+
+## `yield`์ ํจ๊ป `StreamingResponse` ์ฌ์ฉํ๊ธฐ { #a-streamingresponse-with-yield }
+
+๊ฒฝ๋ก ์ฒ๋ฆฌ ํจ์์์ `response_class=StreamingResponse`๋ฅผ ์ ์ธํ๋ฉด `yield`๋ฅผ ์ฌ์ฉํด ๋ฐ์ดํฐ ์ฒญํฌ๋ฅผ ์์ฐจ์ ์ผ๋ก ๋ณด๋ผ ์ ์์ต๋๋ค.
+
+{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}
+
+FastAPI๋ ๊ฐ ๋ฐ์ดํฐ ์ฒญํฌ๋ฅผ ์๋ ๊ทธ๋๋ก `StreamingResponse`์ ์ ๋ฌํ๋ฉฐ, JSON ๋ฑ์ผ๋ก ๋ณํํ๋ ค๊ณ ํ์ง ์์ต๋๋ค.
+
+### async๊ฐ ์๋ ๊ฒฝ๋ก ์ฒ๋ฆฌ ํจ์ { #non-async-path-operation-functions }
+
+`async`๊ฐ ์๋ ์ผ๋ฐ `def` ํจ์์์๋ ๋์ผํ๊ฒ `yield`๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
+
+{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}
+
+### ํ์
์ ๋ํ
์ด์
์๋ตํ๊ธฐ { #no-annotation }
+
+๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์คํธ๋ฆฌ๋ฐํ ๋๋ ๋ฐํ ํ์
์ ๋ํ
์ด์
์ ๊ตณ์ด ์ ์ธํ ํ์๊ฐ ์์ต๋๋ค.
+
+FastAPI๋ ๋ฐ์ดํฐ๋ฅผ Pydantic์ผ๋ก JSON์ผ๋ก ๋ณํํ๊ฑฐ๋ ์ด๋ค ๋ฐฉ์์ผ๋ก๋ ์ง๋ ฌํํ์ง ์์ผ๋ฏ๋ก, ์ด ๊ฒฝ์ฐ ํ์
์ ๋ํ
์ด์
์ ํธ์ง๊ธฐ๋ ๋๊ตฌ๋ฅผ ์ํ ์ฉ๋์ผ ๋ฟ์ด๋ฉฐ FastAPI์์๋ ์ฌ์ฉ๋์ง ์์ต๋๋ค.
+
+{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}
+
+์ด๋ ๊ณง `StreamingResponse`๋ฅผ ์ฌ์ฉํ ๋ ํ์
์ ๋ํ
์ด์
๊ณผ ๋ฌด๊ดํ๊ฒ, ์ ์ก ๊ธฐ์ค์ ๋ง์ถฐ ๋ฐ์ดํธ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๊ณ ์ธ์ฝ๋ฉํ ์์ ์ ์ฑ
์์ด ์ฌ๋ฌ๋ถ์๊ฒ ์์์ ์๋ฏธํฉ๋๋ค. ๐ค
+
+### ๋ฐ์ดํธ ์คํธ๋ฆฌ๋ฐ { #stream-bytes }
+
+์ฃผ์ ์ฌ์ฉ ์ฌ๋ก ์ค ํ๋๋ ๋ฌธ์์ด ๋์ `bytes`๋ฅผ ์คํธ๋ฆฌ๋ฐํ๋ ๊ฒ์
๋๋ค. ๋ฌผ๋ก ๊ทธ๋ ๊ฒ ํ ์ ์์ต๋๋ค.
+
+{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}
+
+## ์ฌ์ฉ์ ์ ์ `PNGStreamingResponse` { #a-custom-pngstreamingresponse }
+
+์ ์์์์๋ ๋ฐ์ดํธ ๋ฐ์ดํฐ๋ฅผ ์คํธ๋ฆฌ๋ฐํ์ง๋ง, ์๋ต์ `Content-Type` ํค๋๊ฐ ์์ด ํด๋ผ์ด์ธํธ๋ ์ด๋ค ์ ํ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋์ง ์ ์ ์์ต๋๋ค.
+
+์คํธ๋ฆฌ๋ฐํ๋ ๋ฐ์ดํฐ ์ ํ์ ๋ง์ถฐ `Content-Type` ํค๋๋ฅผ ์ค์ ํ๋ `StreamingResponse`์ ํ์ ํด๋์ค๋ฅผ ์ง์ ๋ง๋ค ์ ์์ต๋๋ค.
+
+์๋ฅผ ๋ค์ด `media_type` ์์ฑ์ ์ฌ์ฉํด `Content-Type` ํค๋๋ฅผ `image/png`๋ก ์ค์ ํ๋ `PNGStreamingResponse`๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค:
+
+{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}
+
+๊ทธ๋ฐ ๋ค์ ๊ฒฝ๋ก ์ฒ๋ฆฌ ํจ์์์ `response_class=PNGStreamingResponse`๋ก ์ด ์ ํด๋์ค๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค:
+
+{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}
+
+### ํ์ผ ์๋ฎฌ๋ ์ด์
{ #simulate-a-file }
+
+์ด ์์์์๋ `io.BytesIO`๋ก ํ์ผ์ ์๋ฎฌ๋ ์ด์
ํฉ๋๋ค. ์ด๋ ๋ฉ๋ชจ๋ฆฌ์์๋ง ์กด์ฌํ์ง๋ง ํ์ผ๊ณผ ๋์ผํ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ ํ์ผ ์ ์ฌ ๊ฐ์ฒด์
๋๋ค.
+
+์๋ฅผ ๋ค์ด ์ค์ ํ์ผ์ฒ๋ผ ๋ด์ฉ์ ์๋นํ๊ธฐ ์ํด ์ํ(iterate)ํ ์ ์์ต๋๋ค.
+
+{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}
+
+/// note | ๊ธฐ์ ์ธ๋ถ์ฌํญ
+
+๋ค๋ฅธ ๋ ๋ณ์ `image_base64`์ `binary_image`๋ ์ด๋ฏธ์ง๋ฅผ Base64๋ก ์ธ์ฝ๋ฉํ ๋ค ๋ฐ์ดํธ๋ก ๋ณํํ ๊ฒ์ด๋ฉฐ, ์ด๋ฅผ `io.BytesIO`์ ์ ๋ฌํฉ๋๋ค.
+
+์ด ์์์์ ํ๋์ ํ์ผ ์์ ๋ชจ๋ ๋ด์, ๊ทธ๋๋ก ๋ณต์ฌํด ์คํํ ์ ์๋๋ก ํ๊ธฐ ์ํ ๋ชฉ์ ์
๋๋ค. ๐ฅ
+
+///
+
+`with` ๋ธ๋ก์ ์ฌ์ฉํ๋ฉด ์ ๋๋ ์ดํฐ ํจ์(`yield`๊ฐ ์๋ ํจ์)๊ฐ ๋๋ ๋ค, ์ฆ ์๋ต ์ ์ก์ด ์๋ฃ๋ ํ ํ์ผ ์ ์ฌ ๊ฐ์ฒด๊ฐ ๋ซํ๋๋ก ๋ณด์ฅํฉ๋๋ค.
+
+์ด ์์์ฒ๋ผ ๋ฉ๋ชจ๋ฆฌ ์์ ๊ฐ์ง ํ์ผ(`io.BytesIO`)์ด๋ผ๋ฉด ํฌ๊ฒ ์ค์ํ์ง ์์ง๋ง, ์ค์ ํ์ผ์ ๊ฒฝ์ฐ ์์
์ด ๋๋ ๋ค ํ์ผ์ ๋ซ๋ ๊ฒ์ด ๋งค์ฐ ์ค์ํฉ๋๋ค.
+
+### ํ์ผ๊ณผ ๋น๋๊ธฐ { #files-and-async }
+
+๋๋ถ๋ถ์ ๊ฒฝ์ฐ ํ์ผ ์ ์ฌ ๊ฐ์ฒด๋ ๊ธฐ๋ณธ์ ์ผ๋ก async/await์ ํธํ๋์ง ์์ต๋๋ค.
+
+์๋ฅผ ๋ค์ด `await file.read()`๋ `async for chunk in file`๊ณผ ๊ฐ์ ํจํด์ ์ง์ํ์ง ์์ต๋๋ค.
+
+๋ํ ๋์คํฌ๋ ๋คํธ์ํฌ์์ ์ฝ๊ธฐ ๋๋ฌธ์, ๋ง์ ๊ฒฝ์ฐ ์ฝ๊ธฐ ์์
์ ์ด๋ฒคํธ ๋ฃจํ๋ฅผ ๋ง์ ์ ์๋ ๋ธ๋กํน ์ฐ์ฐ์
๋๋ค.
+
+/// info | ์ ๋ณด
+
+์์ ์์๋ ์์ธ์ ์ธ ๊ฒฝ์ฐ์
๋๋ค. `io.BytesIO` ๊ฐ์ฒด๋ ์ด๋ฏธ ๋ฉ๋ชจ๋ฆฌ์ ์์ผ๋ฏ๋ก ์ฝ๊ธฐ๊ฐ ์๋ฌด ๊ฒ๋ ์ฐจ๋จํ์ง ์์ต๋๋ค.
+
+ํ์ง๋ง ์ค์ ํ์ผ์ด๋ ํ์ผ ์ ์ฌ ๊ฐ์ฒด๋ฅผ ์ฝ์ ๋๋ ๋ธ๋กํน๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
+
+///
+
+์ด๋ฒคํธ ๋ฃจํ๊ฐ ๋ธ๋กํน๋๋ ๊ฒ์ ํผํ๋ ค๋ฉด ๊ฒฝ๋ก ์ฒ๋ฆฌ ํจ์๋ฅผ `async def` ๋์ ์ผ๋ฐ `def`๋ก ์ ์ธํ์ธ์. ๊ทธ๋ฌ๋ฉด FastAPI๊ฐ ์ค๋ ๋ํ ์์ปค์์ ์คํํ์ฌ ๋ฉ์ธ ๋ฃจํ๊ฐ ๋งํ์ง ์๋๋ก ํฉ๋๋ค.
+
+{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}
+
+/// tip | ํ
+
+๋น๋๊ธฐ ํจ์ ์์์ ๋ธ๋กํน ์ฝ๋๋ฅผ ํธ์ถํด์ผ ํ๊ฑฐ๋, ๋ฐ๋๋ก ๋ธ๋กํน ํจ์ ์์์ ๋น๋๊ธฐ ํจ์๋ฅผ ํธ์ถํด์ผ ํ๋ค๋ฉด FastAPI์ ํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ [Asyncer](https://asyncer.tiangolo.com)๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
+
+///
+
+### `yield from` { #yield-from }
+
+ํ์ผ ์ ์ฌ ๊ฐ์ฒด์ฒ๋ผ ์ด๋ค ๊ฒ์ ์ํํ๋ฉด์ ๊ฐ ํญ๋ชฉ๋ง๋ค `yield`๋ฅผ ํ๋ ๋์ , `yield from`์ ์ฌ์ฉํด ๊ฐ ํญ๋ชฉ์ ์ง์ ์ ๋ฌํ๊ณ `for` ๋ฃจํ๋ฅผ ์๋ตํ ์ ์์ต๋๋ค.
+
+์ด๋ FastAPI์ ํนํ๋ ๊ธฐ๋ฅ์ด ์๋๋ผ ์์ํ ํ์ด์ฌ ๊ธฐ๋ฅ์ด์ง๋ง, ์์๋๋ฉด ์ ์ฉํ ํธ๋ฆญ์
๋๋ค. ๐
+
+{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}
--- /dev/null
+# ์๊ฒฉํ Content-Type ํ์ธ { #strict-content-type-checking }
+
+๊ธฐ๋ณธ์ ์ผ๋ก **FastAPI**๋ JSON ์์ฒญ ๋ณธ๋ฌธ์ ๋ํด ์๊ฒฉํ `Content-Type` ํค๋ ๊ฒ์ฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด๋ JSON ์์ฒญ์ ๋ณธ๋ฌธ์ JSON์ผ๋ก ํ์ฑํ๋ ค๋ฉด ์ ํจํ `Content-Type` ํค๋(์: `application/json`)๋ฅผ ๋ฐ๋์ ํฌํจํด์ผ ํจ์ ์๋ฏธํฉ๋๋ค.
+
+## CSRF ์ํ { #csrf-risk }
+
+์ด ๊ธฐ๋ณธ ๋์์ ๋งค์ฐ ํน์ ํ ์๋๋ฆฌ์ค์์ **Cross-Site Request Forgery (CSRF)** ๊ณต๊ฒฉ์ ํ ์ ํ์ ๋ํ ๋ณดํธ๋ฅผ ์ ๊ณตํฉ๋๋ค.
+
+์ด๋ฌํ ๊ณต๊ฒฉ์ ๋ธ๋ผ์ฐ์ ๊ฐ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ CORS ์ฌ์ ์์ฒญ(preflight) ๊ฒ์ฌ๋ฅผ ์ํํ์ง ์๊ณ ์คํฌ๋ฆฝํธ๊ฐ ์์ฒญ์ ๋ณด๋ด๋๋ก ํ์ฉํ๋ค๋ ์ ์ ์
์ฉํฉ๋๋ค:
+
+- `Content-Type` ํค๋๊ฐ ์์(์: `Blob` ๋ณธ๋ฌธ๊ณผ ํจ๊ป `fetch()` ์ฌ์ฉ)
+- ๊ทธ๋ฆฌ๊ณ ์ด๋ ํ ์ธ์ฆ ์๊ฒฉ ์ฆ๋ช
๋ ๋ณด๋ด์ง ์์
+
+์ด ์ ํ์ ๊ณต๊ฒฉ์ ์ฃผ๋ก ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ ๊ด๋ จ์ด ์์ต๋๋ค:
+
+- ์ ํ๋ฆฌ์ผ์ด์
์ด ๋ก์ปฌ(์: `localhost`) ๋๋ ๋ด๋ถ ๋คํธ์ํฌ์์ ์คํ ์ค์ด๊ณ
+- ์ ํ๋ฆฌ์ผ์ด์
์ ์ธ์ฆ์ด ์์ด ๊ฐ์ ๋คํธ์ํฌ์์ ์ค๋ ๋ชจ๋ ์์ฒญ์ ์ ๋ขฐํ๋ค๊ณ ๊ฐ์ ํ๋ ๊ฒฝ์ฐ
+
+## ๊ณต๊ฒฉ ์์ { #example-attack }
+
+๋ก์ปฌ AI ์์ด์ ํธ๋ฅผ ์คํํ๋ ๋ฐฉ๋ฒ์ ๋ง๋ค์๋ค๊ณ ๊ฐ์ ํด ๋ด
์๋ค.
+
+์ด ์์ด์ ํธ๋ ๋ค์ ์์น์ API๋ฅผ ์ ๊ณตํฉ๋๋ค:
+
+```
+http://localhost:8000/v1/agents/multivac
+```
+
+๋ํ ๋ค์ ์์น์ ํ๋ก ํธ์๋๊ฐ ์์ต๋๋ค:
+
+```
+http://localhost:8000
+```
+
+/// tip | ํ
+
+๋ ์ฃผ์ ๋ชจ๋ ๊ฐ์ ํธ์คํธ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
+
+///
+
+๊ทธ๋ฐ ๋ค์ ํ๋ก ํธ์๋๋ฅผ ํตํด AI ์์ด์ ํธ๊ฐ ์ฌ๋ฌ๋ถ์ ๋์ ํด ์์
์ ์ํํ๋๋ก ํ ์ ์์ต๋๋ค.
+
+์ด๋ ๊ณต๊ฐ ์ธํฐ๋ท์ด ์๋๋ผ ๋ก์ปฌ์์ ์คํ๋๋ฏ๋ก, ์ฌ๋ฌ๋ถ์ ๋ก์ปฌ ๋คํธ์ํฌ ์ ๊ทผ๋ง์ ์ ๋ขฐํ๊ณ ๋ณ๋์ ์ธ์ฆ์ ์ค์ ํ์ง ์๊ธฐ๋ก ํฉ๋๋ค.
+
+๊ทธ ํ ์ฌ์ฉ์๋ ์ด๋ฅผ ์ค์นํด ๋ก์ปฌ์์ ์คํํ ์ ์์ต๋๋ค.
+
+๊ทธ๋ฆฌ๊ณ ๋ค์๊ณผ ๊ฐ์ ์
์ฑ ์น์ฌ์ดํธ๋ฅผ ์ด ์ ์์ต๋๋ค:
+
+```
+https://evilhackers.example.com
+```
+
+๊ทธ ์
์ฑ ์น์ฌ์ดํธ๊ฐ `Blob` ๋ณธ๋ฌธ์ผ๋ก `fetch()`๋ฅผ ์ฌ์ฉํด ๋ก์ปฌ API๋ก ์์ฒญ์ ๋ณด๋
๋๋ค:
+
+```
+http://localhost:8000/v1/agents/multivac
+```
+
+์
์ฑ ์น์ฌ์ดํธ์ ํธ์คํธ์ ๋ก์ปฌ ์ฑ์ ํธ์คํธ๊ฐ ๋ค๋ฅด๋๋ผ๋, ๋ธ๋ผ์ฐ์ ๋ ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก CORS ์ฌ์ ์์ฒญ(preflight)์ ํธ๋ฆฌ๊ฑฐํ์ง ์์ต๋๋ค:
+
+- ์ธ์ฆ ์์ด ๋์ํ๋ฏ๋ก ์๊ฒฉ ์ฆ๋ช
์ ๋ณด๋ผ ํ์๊ฐ ์์ต๋๋ค.
+- ๋ธ๋ผ์ฐ์ ๋ JSON์ ๋ณด๋ด์ง ์๋๋ค๊ณ ํ๋จํฉ๋๋ค(`Content-Type` ํค๋๊ฐ ์๊ธฐ ๋๋ฌธ).
+
+๊ทธ๋ฌ๋ฉด ์
์ฑ ์น์ฌ์ดํธ๊ฐ ๋ก์ปฌ AI ์์ด์ ํธ๋ก ํ์ฌ๊ธ ์ฌ์ฉ์์ ์ ์ง์ฅ ์์ฌ์๊ฒ ํ๋ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๊ฒ ํ๊ฑฐ๋... ๋ ๋์ ์ผ์ ์ํฌ ์๋ ์์ต๋๋ค. ๐
+
+## ๊ณต๊ฐ ์ธํฐ๋ท { #open-internet }
+
+์ฌ๋ฌ๋ถ์ ์ฑ์ด ๊ณต๊ฐ ์ธํฐ๋ท์ ์๋ค๋ฉด, '๋คํธ์ํฌ๋ฅผ ์ ๋ขฐ'ํ์ฌ ๋๊ตฌ๋ ์ธ์ฆ ์์ด ๊ถํ ์๋ ์์ฒญ์ ๋ณด๋ด๋๋ก ๋์ง๋ ์์ ๊ฒ์
๋๋ค.
+
+๊ณต๊ฒฉ์๋ ๋ธ๋ผ์ฐ์ ์ํธ์์ฉ ์์ด๋ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํด ์ฌ๋ฌ๋ถ์ API๋ก ์์ฒญ์ ๋ณด๋ผ ์ ์์ผ๋ฏ๋ก, ์๋ง ์ด๋ฏธ ๊ถํ์ด ํ์ํ ์๋ํฌ์ธํธ๋ ๋ณดํธํ๊ณ ์์ ๊ฒ์
๋๋ค.
+
+๊ทธ๋ฐ ๊ฒฝ์ฐ์๋ ์ด ๊ณต๊ฒฉ/์ํ์ ํด๋นํ์ง ์์ต๋๋ค.
+
+์ด ์ํ๊ณผ ๊ณต๊ฒฉ์ ์ฃผ๋ก ์ฑ์ด **๋ก์ปฌ ๋คํธ์ํฌ**์์ ์คํ๋๊ณ ๊ทธ๊ฒ์ด **์ ์ผํ ๋ณดํธ์๋จ**์ด๋ผ๊ณ ๊ฐ์ ํ ๋ ๊ด๋ จ์ด ์์ต๋๋ค.
+
+## Content-Type ์์ด ์์ฒญ ํ์ฉํ๊ธฐ { #allowing-requests-without-content-type }
+
+๋ง์ฝ `Content-Type` ํค๋๋ฅผ ๋ณด๋ด์ง ์๋ ํด๋ผ์ด์ธํธ๋ฅผ ์ง์ํด์ผ ํ๋ค๋ฉด, `strict_content_type=False`๋ก ์ค์ ํด ์๊ฒฉํ ๊ฒ์ฌ๋ฅผ ๋นํ์ฑํํ ์ ์์ต๋๋ค:
+
+{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}
+
+์ด ์ค์ ์ ์ฌ์ฉํ๋ฉด `Content-Type` ํค๋๊ฐ ์๋ ์์ฒญ๋ ๋ณธ๋ฌธ์ด JSON์ผ๋ก ํ์ฑ๋ฉ๋๋ค. ์ด๋ ์ด์ ๋ฒ์ ์ FastAPI์ ๋์ผํ ๋์์
๋๋ค.
+
+/// info | ์ ๋ณด
+
+์ด ๋์๊ณผ ์ค์ ์ FastAPI 0.132.0์ ์ถ๊ฐ๋์์ต๋๋ค.
+
+///
--- /dev/null
+# ์๋ํฐ ์ง์ { #editor-support }
+
+๊ณต์ [FastAPI ํ์ฅ](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode)์ FastAPI ๊ฐ๋ฐ ์ํฌํ๋ก์ฐ๋ฅผ ๊ฐํํด ์ค๋๋ค. *๊ฒฝ๋ก ์ฒ๋ฆฌ* ํ์ ๋ฐ ์ด๋, FastAPI Cloud ๋ฐฐํฌ, ์ค์๊ฐ ๋ก๊ทธ ์คํธ๋ฆฌ๋ฐ์ ์ ๊ณตํฉ๋๋ค.
+
+ํ์ฅ์ ๋ํ ์์ธํ ๋ด์ฉ์ [GitHub ์ ์ฅ์](https://github.com/fastapi/fastapi-vscode)์ README๋ฅผ ์ฐธ๊ณ ํ์ธ์.
+
+## ์ค์น ๋ฐ ์ค์ { #setup-and-installation }
+
+**FastAPI ํ์ฅ**์ [VS Code](https://code.visualstudio.com/)์ [Cursor](https://www.cursor.com/)์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ฐ ์๋ํฐ์ ํ์ฅ(Extensions) ํจ๋์์ "FastAPI"๋ก ๊ฒ์ํ ๋ค **FastAPI Labs**๊ฐ ๋ฐฐํฌํ ํ์ฅ์ ์ ํํด ๋ฐ๋ก ์ค์นํ ์ ์์ต๋๋ค. ๋ํ [vscode.dev](https://vscode.dev), [github.dev](https://github.dev) ๊ฐ์ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ฐ ์๋ํฐ์์๋ ๋์ํฉ๋๋ค.
+
+### ์ ํ๋ฆฌ์ผ์ด์
์๋ ๊ฐ์ง { #application-discovery }
+
+๊ธฐ๋ณธ์ ์ผ๋ก ์ด ํ์ฅ์ ์์
๊ณต๊ฐ์์ `FastAPI()`๋ฅผ ์์ฑํ๋ ํ์ผ์ ์ค์บํ์ฌ FastAPI ์ ํ๋ฆฌ์ผ์ด์
์ ์๋์ผ๋ก ๊ฐ์งํฉ๋๋ค. ํ๋ก์ ํธ ๊ตฌ์กฐ์ ์๋ ๊ฐ์ง๊ฐ ์ด๋ ค์ด ๊ฒฝ์ฐ, `pyproject.toml`์ `[tool.fastapi]` ํญ๋ชฉ์ด๋ VS Code ์ค์ `fastapi.entryPoint`์ ๋ชจ๋ ํ๊ธฐ(์: `myapp.main:app`)๋ก ์ํธ๋ฆฌํฌ์ธํธ๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค.
+
+## ๊ธฐ๋ฅ { #features }
+
+- **๊ฒฝ๋ก ์ฒ๋ฆฌ ํ์๊ธฐ** - ์ ํ๋ฆฌ์ผ์ด์
์ ๋ชจ๋ <dfn title="๊ฒฝ๋ก, ์๋ํฌ์ธํธ">*๊ฒฝ๋ก ์ฒ๋ฆฌ*</dfn>๋ฅผ ์ฌ์ด๋๋ฐ ํธ๋ฆฌ ๋ทฐ๋ก ํ์ธํฉ๋๋ค. ํด๋ฆญํ๋ฉด ํด๋น ๊ฒฝ๋ก ๋๋ ๋ผ์ฐํฐ ์ ์๋ก ๋ฐ๋ก ์ด๋ํฉ๋๋ค.
+- **๊ฒฝ๋ก ๊ฒ์** - <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd> (macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>)๋ก ๊ฒฝ๋ก, ๋ฉ์๋, ์ด๋ฆ์ผ๋ก ๊ฒ์ํฉ๋๋ค.
+- **CodeLens ํ์** - ํ
์คํธ ํด๋ผ์ด์ธํธ ํธ์ถ(์: `client.get('/items')`) ์์ ํด๋ฆญ ๊ฐ๋ฅํ ๋งํฌ๋ฅผ ํตํด ํด๋น *๊ฒฝ๋ก ์ฒ๋ฆฌ*๋ก ์ฆ์ ์ด๋ํ์ฌ ํ
์คํธ์ ๊ตฌํ ๊ฐ์ ๋น ๋ฅด๊ฒ ์ค๊ฐ ์ ์์ต๋๋ค.
+- **FastAPI Cloud์ ๋ฐฐํฌ** - [FastAPI Cloud](https://fastapicloud.com/)๋ก ์ํด๋ฆญ ๋ฐฐํฌ๋ฅผ ์ง์ํฉ๋๋ค.
+- **์ ํ๋ฆฌ์ผ์ด์
๋ก๊ทธ ์คํธ๋ฆฌ๋ฐ** - FastAPI Cloud์ ๋ฐฐํฌ๋ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ก๊ทธ๋ฅผ ์ค์๊ฐ์ผ๋ก ์คํธ๋ฆฌ๋ฐํ๋ฉฐ, ๋ ๋ฒจ ํํฐ๋ง๊ณผ ํ
์คํธ ๊ฒ์์ ์ ๊ณตํฉ๋๋ค.
+
+ํ์ฅ์ ๊ธฐ๋ฅ์ ๋จผ์ ์ตํ๋ณด๊ณ ์ถ๋ค๋ฉด, ๋ช
๋ น ํ๋ ํธ(<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>, macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>)๋ฅผ ์ด๊ณ "Welcome: Open walkthrough..."๋ฅผ ์ ํํ ๋ค "Get started with FastAPI" walkthrough๋ฅผ ์ ํํด ๋ณด์ธ์.
--- /dev/null
+# ์๋ฒ ์ ์ก ์ด๋ฒคํธ(SSE) { #server-sent-events-sse }
+
+๋ธ๋ผ์ฐ์ ํด๋ผ์ด์ธํธ๋ก ๋ฐ์ดํฐ๋ฅผ ์คํธ๋ฆฌ๋ฐํ๋ ค๋ฉด **Server-Sent Events**(SSE)๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
+
+์ด๋ [JSON Lines ์คํธ๋ฆฌ๋ฐ](stream-json-lines.md)๊ณผ ๋น์ทํ์ง๋ง, ๋ธ๋ผ์ฐ์ ๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก [`EventSource` API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource)๋ฅผ ํตํด ์ง์ํ๋ `text/event-stream` ํ์์ ์ฌ์ฉํฉ๋๋ค.
+
+/// info | ์ ๋ณด
+
+FastAPI 0.135.0์ ์ถ๊ฐ๋์์ต๋๋ค.
+
+///
+
+## Server-Sent Events๋ { #what-are-server-sent-events }
+
+SSE๋ ์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก HTTP๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์คํธ๋ฆฌ๋ฐํ๊ธฐ ์ํ ํ์ค์
๋๋ค.
+
+๊ฐ ์ด๋ฒคํธ๋ `data`, `event`, `id`, `retry`์ ๊ฐ์ "ํ๋"๋ฅผ ๊ฐ์ง ์์ ํ
์คํธ ๋ธ๋ก์ด๋ฉฐ, ๋น ์ค๋ก ๊ตฌ๋ถ๋ฉ๋๋ค.
+
+๋ค์๊ณผ ๊ฐ์ต๋๋ค:
+
+```
+data: {"name": "Portal Gun", "price": 999.99}
+
+data: {"name": "Plumbus", "price": 32.99}
+
+```
+
+SSE๋ AI ์ฑํ
์คํธ๋ฆฌ๋ฐ, ์ค์๊ฐ ์๋ฆผ, ๋ก๊ทธ์ ๊ด์ธก์ฑ, ๊ทธ๋ฆฌ๊ณ ์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ๋ก ์
๋ฐ์ดํธ๋ฅผ ํธ์ํ๋ ์ฌ๋ฌ ๊ฒฝ์ฐ์ ํํ ์ฌ์ฉ๋ฉ๋๋ค.
+
+/// tip | ํ
+
+๋น๋์ค๋ ์ค๋์ค์ฒ๋ผ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์คํธ๋ฆฌ๋ฐํ๋ ค๋ฉด ๊ณ ๊ธ ๊ฐ์ด๋: [๋ฐ์ดํฐ ์คํธ๋ฆฌ๋ฐ](../advanced/stream-data.md)์ ํ์ธํ์ธ์.
+
+///
+
+## FastAPI๋ก SSE ์คํธ๋ฆฌ๋ฐ { #stream-sse-with-fastapi }
+
+FastAPI์์ SSE๋ฅผ ์คํธ๋ฆฌ๋ฐํ๋ ค๋ฉด, ๊ฒฝ๋ก ์ฒ๋ฆฌ ํจ์์์ `yield`๋ฅผ ์ฌ์ฉํ๊ณ `response_class=EventSourceResponse`๋ฅผ ์ค์ ํ์ธ์.
+
+`EventSourceResponse`๋ `fastapi.sse`์์ ์ํฌํธํฉ๋๋ค:
+
+{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[4,22] *}
+
+๊ฐ `yield`๋ ํญ๋ชฉ์ JSON์ผ๋ก ์ธ์ฝ๋ฉ๋์ด SSE ์ด๋ฒคํธ์ `data:` ํ๋๋ก ์ ์ก๋ฉ๋๋ค.
+
+๋ฐํ ํ์
์ `AsyncIterable[Item]`์ผ๋ก ์ ์ธํ๋ฉด FastAPI๊ฐ ์ด๋ฅผ ์ฌ์ฉํด ๋ฐ์ดํฐ๋ฅผ Pydantic์ผ๋ก **๊ฒ์ฆ**, **๋ฌธ์ํ**, **์ง๋ ฌํ**ํฉ๋๋ค.
+
+{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[10:12,23] *}
+
+/// tip | ํ
+
+Pydantic์ด **Rust** ์ชฝ์์ ์ง๋ ฌํํ๋ฏ๋ก, ๋ฐํ ํ์
์ ์ ์ธํ์ง ์์์ ๋๋ณด๋ค ํจ์ฌ ๋ ๋์ **์ฑ๋ฅ**์ ์ป์ ์ ์์ต๋๋ค.
+
+///
+
+### ๋น async *๊ฒฝ๋ก ์ฒ๋ฆฌ ํจ์* { #non-async-path-operation-functions }
+
+`async`๊ฐ ์๋ ์ผ๋ฐ `def` ํจ์๋ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ๋์ผํ๊ฒ `yield`๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
+
+FastAPI๊ฐ ์ด๋ฒคํธ ๋ฃจํ๋ฅผ ๋ง์ง ์๋๋ก ์ฌ๋ฐ๋ฅด๊ฒ ์คํ์ ๋ณด์ฅํฉ๋๋ค.
+
+์ด ๊ฒฝ์ฐ ํจ์๊ฐ async๊ฐ ์๋๋ฏ๋ก ์ ์ ํ ๋ฐํ ํ์
์ `Iterable[Item]`์
๋๋ค:
+
+{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[28:31] hl[29] *}
+
+### ๋ฐํ ํ์
์์ { #no-return-type }
+
+๋ฐํ ํ์
์ ์๋ตํ ์๋ ์์ต๋๋ค. FastAPI๋ [`jsonable_encoder`](./encoder.md)๋ฅผ ์ฌ์ฉํด ๋ฐ์ดํฐ๋ฅผ ๋ณํํ๊ณ ์ ์กํฉ๋๋ค.
+
+{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[34:37] hl[35] *}
+
+## `ServerSentEvent` { #serversentevent }
+
+`event`, `id`, `retry`, `comment` ๊ฐ์ SSE ํ๋๋ฅผ ์ค์ ํด์ผ ํ๋ค๋ฉด, ์ผ๋ฐ ๋ฐ์ดํฐ ๋์ `ServerSentEvent` ๊ฐ์ฒด๋ฅผ `yield`ํ ์ ์์ต๋๋ค.
+
+`ServerSentEvent`๋ `fastapi.sse`์์ ์ํฌํธํฉ๋๋ค:
+
+{* ../../docs_src/server_sent_events/tutorial002_py310.py hl[4,26] *}
+
+`data` ํ๋๋ ํญ์ JSON์ผ๋ก ์ธ์ฝ๋ฉ๋ฉ๋๋ค. Pydantic ๋ชจ๋ธ์ ํฌํจํด JSON์ผ๋ก ์ง๋ ฌํํ ์ ์๋ ๊ฐ์ ๋ชจ๋ ์ ๋ฌํ ์ ์์ต๋๋ค.
+
+## ์์ ๋ฐ์ดํฐ { #raw-data }
+
+JSON ์ธ์ฝ๋ฉ ์์ด ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด์ผ ํ๋ค๋ฉด, `data` ๋์ `raw_data`๋ฅผ ์ฌ์ฉํ์ธ์.
+
+๋ฏธ๋ฆฌ ํฌ๋งท๋ ํ
์คํธ, ๋ก๊ทธ ๋ผ์ธ, ๋๋ `[DONE]`๊ณผ ๊ฐ์ ํน์ํ <dfn title="ํน์ํ ์กฐ๊ฑด์ด๋ ์ํ๋ฅผ ๋ํ๋ด๋ ๋ฐ ์ฌ์ฉ๋๋ ๊ฐ">"์ผํฐ๋"</dfn> ๊ฐ์ ๋ณด๋ผ ๋ ์ ์ฉํฉ๋๋ค.
+
+{* ../../docs_src/server_sent_events/tutorial003_py310.py hl[17] *}
+
+/// note | ์ฐธ๊ณ
+
+`data`์ `raw_data`๋ ์ํธ ๋ฐฐํ์ ์
๋๋ค. ๊ฐ `ServerSentEvent`์๋ ์ด ๋ ์ค ํ๋๋ง ์ค์ ํ ์ ์์ต๋๋ค.
+
+///
+
+## `Last-Event-ID`๋ก ์ฌ๊ฐํ๊ธฐ { #resuming-with-last-event-id }
+
+๋ธ๋ผ์ฐ์ ๊ฐ ์ฐ๊ฒฐ์ด ๋๊ธด ํ ์ฌ์ฐ๊ฒฐํ ๋, ๋ง์ง๋ง์ผ๋ก ๋ฐ์ `id`๋ฅผ `Last-Event-ID` ํค๋์ ๋ด์ ๋ณด๋
๋๋ค.
+
+ํค๋ ํ๋ผ๋ฏธํฐ๋ก ์ด๋ฅผ ์ฝ์ด์ ํด๋ผ์ด์ธํธ๊ฐ ์ค๋จํ ์ง์ ๋ถํฐ ์คํธ๋ฆผ์ ์ฌ๊ฐํ ์ ์์ต๋๋ค:
+
+{* ../../docs_src/server_sent_events/tutorial004_py310.py hl[25,27,31] *}
+
+## POST๋ก SSE ์ฌ์ฉํ๊ธฐ { #sse-with-post }
+
+SSE๋ `GET`๋ฟ๋ง ์๋๋ผ **๋ชจ๋ HTTP ๋ฉ์๋**์ ํจ๊ป ๋์ํฉ๋๋ค.
+
+์ด๋ `POST`๋ก SSE๋ฅผ ์คํธ๋ฆฌ๋ฐํ๋ [MCP](https://modelcontextprotocol.io) ๊ฐ์ ํ๋กํ ์ฝ์ ์ ์ฉํฉ๋๋ค:
+
+{* ../../docs_src/server_sent_events/tutorial005_py310.py hl[14] *}
+
+## ๊ธฐ์ ์ธ๋ถ์ฌํญ { #technical-details }
+
+FastAPI๋ ์ผ๋ถ SSE ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ๊ตฌํํฉ๋๋ค.
+
+- ๋ฉ์์ง๊ฐ ์์ ๋๋ 15์ด๋ง๋ค **"keep alive" `ping` ์ฃผ์**์ ๋ณด๋ด ์ผ๋ถ ํ๋ก์๊ฐ ์ฐ๊ฒฐ์ ์ข
๋ฃํ์ง ์๋๋ก ํฉ๋๋ค. [HTML ์ฌ์: Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html#authoring-notes)์์ ๊ถ์ฅํฉ๋๋ค.
+- ์คํธ๋ฆผ์ด **์บ์๋์ง ์๋๋ก** `Cache-Control: no-cache` ํค๋๋ฅผ ์ค์ ํฉ๋๋ค.
+- Nginx ๊ฐ์ ์ผ๋ถ ํ๋ก์์์ **๋ฒํผ๋ง์ ๋ฐฉ์ง**ํ๊ธฐ ์ํด ํน์ ํค๋ `X-Accel-Buffering: no`๋ฅผ ์ค์ ํฉ๋๋ค.
+
+์ฌ๋ฌ๋ถ์ด ๋ฐ๋ก ํ ์ผ์ ์์ต๋๋ค. ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๋์ํฉ๋๋ค. ๐ค
--- /dev/null
+# JSON Lines ์คํธ๋ฆฌ๋ฐ { #stream-json-lines }
+
+์ฐ์๋ ๋ฐ์ดํฐ๋ฅผ "**์คํธ๋ฆผ**"์ผ๋ก ๋ณด๋ด๊ณ ์ถ๋ค๋ฉด **JSON Lines**๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
+
+/// info
+
+FastAPI 0.134.0์ ์ถ๊ฐ๋์์ต๋๋ค.
+
+///
+
+## ์คํธ๋ฆผ์ด๋ { #what-is-a-stream }
+
+๋ฐ์ดํฐ๋ฅผ "**์คํธ๋ฆฌ๋ฐ**"ํ๋ค๋ ๊ฒ์ ์ ํ๋ฆฌ์ผ์ด์
์ด ์ ์ฒด ํญ๋ชฉ ์ํ์ค๊ฐ ๋ชจ๋ ์ค๋น๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ํด๋ผ์ด์ธํธ๋ก ๋ฐ์ดํฐ ํญ๋ชฉ์ ๋ณด๋ด๊ธฐ ์์ํ๋ค๋ ๋ป์
๋๋ค.
+
+์ฆ, ์ฒซ ๋ฒ์งธ ํญ๋ชฉ์ ๋ณด๋ด๋ฉด ํด๋ผ์ด์ธํธ๋ ๊ทธ๊ฒ์ ๋ฐ์ ์ฒ๋ฆฌํ๊ธฐ ์์ํ๊ณ , ๊ทธ๋์ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ค์ ํญ๋ชฉ์ ๊ณ์ ์์ฑํ ์ ์์ต๋๋ค.
+
+```mermaid
+sequenceDiagram
+ participant App
+ participant Client
+
+ App->>App: Produce Item 1
+ App->>Client: Send Item 1
+ App->>App: Produce Item 2
+ Client->>Client: Process Item 1
+ App->>Client: Send Item 2
+ App->>App: Produce Item 3
+ Client->>Client: Process Item 2
+ App->>Client: Send Item 3
+ Client->>Client: Process Item 3
+ Note over App: Keeps producing...
+ Note over Client: Keeps consuming...
+```
+
+๋ฐ์ดํฐ๋ฅผ ๊ณ์ ๋ณด๋ด๋ ๋ฌดํ ์คํธ๋ฆผ์ผ ์๋ ์์ต๋๋ค.
+
+## JSON Lines { #json-lines }
+
+์ด๋ฐ ๊ฒฝ์ฐ์๋ ํ ์ค์ ํ๋์ JSON ๊ฐ์ฒด๋ฅผ ๋ณด๋ด๋ ํ์์ธ "**JSON Lines**"๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์
๋๋ค.
+
+์๋ต์ ์ฝํ
์ธ ํ์
์ `application/json` ๋์ `application/jsonl`์ด๊ณ , ๋ณธ๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
+
+```json
+{"name": "Plumbus", "description": "A multi-purpose household device."}
+{"name": "Portal Gun", "description": "A portal opening device."}
+{"name": "Meeseeks Box", "description": "A box that summons a Meeseeks."}
+```
+
+JSON ๋ฐฐ์ด(Python์ list์ ํด๋น)๊ณผ ๋งค์ฐ ๋น์ทํ์ง๋ง, ํญ๋ชฉ๋ค์ `[]`๋ก ๊ฐ์ธ๊ณ ํญ๋ชฉ ์ฌ์ด์ `,`๋ฅผ ๋ฃ๋ ๋์ , ์ค๋ง๋ค ํ๋์ JSON ๊ฐ์ฒด๊ฐ ์๊ณ , ์ ์ค ๋ฌธ์๋ก ๊ตฌ๋ถ๋ฉ๋๋ค.
+
+/// info
+
+ํต์ฌ์ ์ ํ๋ฆฌ์ผ์ด์
์ด ๊ฐ ์ค์ ์ฐจ๋ก๋ก ์์ฑํ๋ ๋์, ํด๋ผ์ด์ธํธ๋ ์ด์ ์ค์ ์๋นํ ์ ์๋ค๋ ์ ์
๋๋ค.
+
+///
+
+/// note | ๊ธฐ์ ์ธ๋ถ์ฌํญ
+
+๊ฐ JSON ๊ฐ์ฒด๋ ์ ์ค๋ก ๊ตฌ๋ถ๋๋ฏ๋ก, ๋ด์ฉ์ ์ค์ ์ค๋ฐ๊ฟ ๋ฌธ์๋ฅผ ํฌํจํ ์๋ ์์ต๋๋ค. ํ์ง๋ง JSON ํ์ค์ ์ผ๋ถ์ธ ์ด์ค์ผ์ดํ๋ ์ค๋ฐ๊ฟ(`\n`)์ ํฌํจํ ์ ์์ต๋๋ค.
+
+๋ณดํต์ ์ ๊ฒฝ ์ธ ํ์๊ฐ ์์ต๋๋ค. ์๋์ผ๋ก ์ฒ๋ฆฌ๋๋ ๊ณ์ ์ฝ์ด ์ฃผ์ธ์. ๐ค
+
+///
+
+## ์ฌ์ฉ ์ { #use-cases }
+
+์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํด **AI LLM** ์๋น์ค, **๋ก๊ทธ** ๋๋ **telemetry**์์ ์ค๋ ๋ฐ์ดํฐ, ํน์ **JSON** ํญ๋ชฉ์ผ๋ก ๊ตฌ์กฐํํ ์ ์๋ ๋ค๋ฅธ ์ ํ์ ๋ฐ์ดํฐ๋ฅผ ์คํธ๋ฆฌ๋ฐํ ์ ์์ต๋๋ค.
+
+/// tip
+
+๋น๋์ค๋ ์ค๋์ค์ฒ๋ผ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์คํธ๋ฆฌ๋ฐํ๋ ค๋ฉด ๊ณ ๊ธ ๊ฐ์ด๋๋ฅผ ํ์ธํ์ธ์: [์คํธ๋ฆผ ๋ฐ์ดํฐ](../advanced/stream-data.md).
+
+///
+
+## FastAPI๋ก JSON Lines ์คํธ๋ฆฌ๋ฐ { #stream-json-lines-with-fastapi }
+
+FastAPI์์ JSON Lines๋ฅผ ์คํธ๋ฆฌ๋ฐํ๋ ค๋ฉด, *๊ฒฝ๋ก ์ฒ๋ฆฌ ํจ์*์์ `return`์ ์ฌ์ฉํ๋ ๋์ `yield`๋ก ๊ฐ ํญ๋ชฉ์ ์ฐจ๋ก๋ก ์์ฑํ๋ฉด ๋ฉ๋๋ค.
+
+{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}
+
+๋ณด๋ด๋ ค๋ ๊ฐ JSON ํญ๋ชฉ์ ํ์
์ด `Item`(Pydantic ๋ชจ๋ธ)์ด๊ณ ํจ์๊ฐ async๋ผ๋ฉด, ๋ฐํ ํ์
์ `AsyncIterable[Item]`๋ก ์ ์ธํ ์ ์์ต๋๋ค:
+
+{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}
+
+๋ฐํ ํ์
์ ์ ์ธํ๋ฉด FastAPI๊ฐ ์ด๋ฅผ ์ฌ์ฉํด ๋ฐ์ดํฐ๋ฅผ **๊ฒ์ฆ**ํ๊ณ , OpenAPI์ **๋ฌธ์ํ**ํ๊ณ , **ํํฐ๋ง**ํ๊ณ , Pydantic์ผ๋ก **์ง๋ ฌํ**ํฉ๋๋ค.
+
+/// tip
+
+Pydantic์ด **Rust** ์ธก์์ ์ง๋ ฌํํ๋ฏ๋ก, ๋ฐํ ํ์
์ ์ ์ธํ์ง ์์์ ๋๋ณด๋ค ํจ์ฌ ๋์ **์ฑ๋ฅ**์ ์ป๊ฒ ๋ฉ๋๋ค.
+
+///
+
+### ๋น๋๊ธฐ ์๋ *๊ฒฝ๋ก ์ฒ๋ฆฌ ํจ์* { #non-async-path-operation-functions }
+
+์ผ๋ฐ `def` ํจ์(`async` ์์ด)๋ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ๋์ผํ๊ฒ `yield`๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
+
+FastAPI๊ฐ ์ด๋ฒคํธ ๋ฃจํ๋ฅผ ๋ง์ง ์๋๋ก ์ฌ๋ฐ๋ฅด๊ฒ ์คํ๋๊ฒ ๋ณด์ฅํฉ๋๋ค.
+
+์ด ๊ฒฝ์ฐ ํจ์๊ฐ async๊ฐ ์๋๋ฏ๋ก, ์ฌ๋ฐ๋ฅธ ๋ฐํ ํ์
์ `Iterable[Item]`์
๋๋ค:
+
+{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}
+
+### ๋ฐํ ํ์
์๋ต { #no-return-type }
+
+๋ฐํ ํ์
์ ์๋ตํ ์๋ ์์ต๋๋ค. ๊ทธ๋ฌ๋ฉด FastAPI๊ฐ [`jsonable_encoder`](./encoder.md)๋ฅผ ์ฌ์ฉํด ๋ฐ์ดํฐ๋ฅผ JSON์ผ๋ก ์ง๋ ฌํ ๊ฐ๋ฅํ ํํ๋ก ๋ณํํ ๋ค JSON Lines๋ก ์ ์กํฉ๋๋ค.
+
+{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}
+
+## ์๋ฒ ์ ์ก ์ด๋ฒคํธ(SSE) { #server-sent-events-sse }
+
+FastAPI๋ Server-Sent Events(SSE)๋ ์ผ๊ธ์ผ๋ก ์ง์ํฉ๋๋ค. ๋งค์ฐ ๋น์ทํ์ง๋ง ๋ช ๊ฐ์ง ์ถ๊ฐ ์ธ๋ถ์ฌํญ์ด ์์ต๋๋ค. ๋ค์ ์ฅ์์ ์์ธํ ์์๋ณด์ธ์: [Server-Sent Events (SSE)](server-sent-events.md). ๐ค