Skip to content

Commit f8f4e5b

Browse files
🌐 Update translations for ko (add-missing)
1 parent 8712af9 commit f8f4e5b

6 files changed

Lines changed: 522 additions & 0 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# 바이트를 Base64로 포함하는 JSON { #json-with-bytes-as-base64 }
2+
3+
애플리케이션에서 JSON 데이터를 주고받아야 하지만 그 안에 바이너리 데이터를 포함해야 한다면, base64로 인코딩해서 포함할 수 있습니다.
4+
5+
## Base64와 파일 { #base64-vs-files }
6+
7+
바이너리 데이터 업로드에는 [요청 파일](../tutorial/request-files.md)을, 바이너리 데이터 전송에는 [커스텀 응답 - FileResponse](./custom-response.md#fileresponse--fileresponse-)를 사용할 수 있는지 먼저 고려하세요. JSON으로 인코딩하는 대신 말입니다.
8+
9+
JSON은 UTF-8로 인코딩된 문자열만 포함할 수 있으므로, 원시 바이트를 그대로 담을 수 없습니다.
10+
11+
Base64는 바이너리 데이터를 문자열로 인코딩할 수 있지만, 이를 위해 원래의 바이너리 데이터보다 더 많은 문자 수를 사용해야 하므로 일반적인 파일 전송보다 비효율적일 수 있습니다.
12+
13+
반드시 JSON 안에 바이너리 데이터를 포함해야 하고, 파일을 사용할 수 없을 때만 base64를 사용하세요.
14+
15+
## Pydantic `bytes` { #pydantic-bytes }
16+
17+
`bytes` 필드를 가진 Pydantic 모델을 선언하고, 모델 설정에서 `val_json_bytes`를 사용하도록 지정하면 입력 JSON 데이터를 base64로 “검증”하도록 할 수 있습니다. 이 검증 과정의 일부로 base64 문자열을 바이트로 디코딩합니다.
18+
19+
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}
20+
21+
`/docs`를 확인하면 `data` 필드가 base64로 인코딩된 bytes를 기대한다고 표시됩니다:
22+
23+
<div class="screenshot">
24+
<img src="/img/tutorial/json-base64-bytes/image01.png">
25+
</div>
26+
27+
아래와 같은 요청을 보낼 수 있습니다:
28+
29+
```json
30+
{
31+
"description": "Some data",
32+
"data": "aGVsbG8="
33+
}
34+
```
35+
36+
/// tip | 팁
37+
38+
`aGVsbG8=``hello`의 base64 인코딩입니다.
39+
40+
///
41+
42+
그러면 Pydantic이 base64 문자열을 디코딩하여 모델의 `data` 필드에 원래 바이트를 제공합니다.
43+
44+
다음과 같은 응답을 받게 됩니다:
45+
46+
```json
47+
{
48+
"description": "Some data",
49+
"content": "hello"
50+
}
51+
```
52+
53+
## 출력 데이터용 Pydantic `bytes` { #pydantic-bytes-for-output-data }
54+
55+
출력 데이터에도 모델 설정에서 `ser_json_bytes`와 함께 `bytes` 필드를 사용할 수 있습니다. 그러면 Pydantic이 JSON 응답을 생성할 때 바이트를 base64로 “직렬화”합니다.
56+
57+
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}
58+
59+
## 입력과 출력 데이터용 Pydantic `bytes` { #pydantic-bytes-for-input-and-output-data }
60+
61+
물론, 동일한 모델을 사용해 JSON 데이터를 받을 때는 `val_json_bytes`로 입력을 “검증”하고, JSON 데이터를 보낼 때는 `ser_json_bytes`로 출력을 “직렬화”하도록 base64를 모두 처리하게 구성할 수 있습니다.
62+
63+
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# 데이터 스트리밍 { #stream-data }
2+
3+
JSON으로 구조화할 수 있는 데이터를 스트리밍하려면 [JSON Lines 스트리밍](../tutorial/stream-json-lines.md)을 사용하세요.
4+
5+
하지만 순수 바이너리 데이터나 문자열을 스트리밍하려면 다음과 같이 하면 됩니다.
6+
7+
/// info | 정보
8+
9+
FastAPI 0.134.0에 추가되었습니다.
10+
11+
///
12+
13+
## 사용 예시 { #use-cases }
14+
15+
예를 들어 AI LLM 서비스의 출력에서 바로 순수 문자열을 스트리밍하고 싶다면 이를 사용할 수 있습니다.
16+
17+
또한 큰 바이너리 파일을 스트리밍하는 데 사용할 수 있습니다. 한 번에 모두 메모리로 읽지 않고, 읽는 즉시 데이터 청크를 순차적으로 스트리밍합니다.
18+
19+
이 방식으로 비디오나 오디오를 스트리밍할 수도 있으며, 처리하면서 생성된 데이터를 곧바로 전송할 수도 있습니다.
20+
21+
## `yield`와 함께 `StreamingResponse` 사용하기 { #a-streamingresponse-with-yield }
22+
23+
경로 처리 함수에서 `response_class=StreamingResponse`를 선언하면 `yield`를 사용해 데이터 청크를 순차적으로 보낼 수 있습니다.
24+
25+
{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}
26+
27+
FastAPI는 각 데이터 청크를 있는 그대로 `StreamingResponse`에 전달하며, JSON 등으로 변환하려고 하지 않습니다.
28+
29+
### async가 아닌 경로 처리 함수 { #non-async-path-operation-functions }
30+
31+
`async`가 없는 일반 `def` 함수에서도 동일하게 `yield`를 사용할 수 있습니다.
32+
33+
{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}
34+
35+
### 타입 애너테이션 생략하기 { #no-annotation }
36+
37+
바이너리 데이터를 스트리밍할 때는 반환 타입 애너테이션을 굳이 선언할 필요가 없습니다.
38+
39+
FastAPI는 데이터를 Pydantic으로 JSON으로 변환하거나 어떤 방식으로든 직렬화하지 않으므로, 이 경우 타입 애너테이션은 편집기나 도구를 위한 용도일 뿐이며 FastAPI에서는 사용되지 않습니다.
40+
41+
{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}
42+
43+
이는 곧 `StreamingResponse`를 사용할 때 타입 애너테이션과 무관하게, 전송 기준에 맞춰 바이트 데이터를 생성하고 인코딩할 자유와 책임이 여러분에게 있음을 의미합니다. 🤓
44+
45+
### 바이트 스트리밍 { #stream-bytes }
46+
47+
주요 사용 사례 중 하나는 문자열 대신 `bytes`를 스트리밍하는 것입니다. 물론 그렇게 할 수 있습니다.
48+
49+
{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}
50+
51+
## 사용자 정의 `PNGStreamingResponse` { #a-custom-pngstreamingresponse }
52+
53+
위 예시에서는 바이트 데이터를 스트리밍했지만, 응답에 `Content-Type` 헤더가 없어 클라이언트는 어떤 유형의 데이터를 받는지 알 수 없습니다.
54+
55+
스트리밍하는 데이터 유형에 맞춰 `Content-Type` 헤더를 설정하는 `StreamingResponse`의 하위 클래스를 직접 만들 수 있습니다.
56+
57+
예를 들어 `media_type` 속성을 사용해 `Content-Type` 헤더를 `image/png`로 설정하는 `PNGStreamingResponse`를 만들 수 있습니다:
58+
59+
{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}
60+
61+
그런 다음 경로 처리 함수에서 `response_class=PNGStreamingResponse`로 이 새 클래스를 사용할 수 있습니다:
62+
63+
{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}
64+
65+
### 파일 시뮬레이션 { #simulate-a-file }
66+
67+
이 예시에서는 `io.BytesIO`로 파일을 시뮬레이션합니다. 이는 메모리에서만 존재하지만 파일과 동일한 인터페이스를 제공하는 파일 유사 객체입니다.
68+
69+
예를 들어 실제 파일처럼 내용을 소비하기 위해 순회(iterate)할 수 있습니다.
70+
71+
{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}
72+
73+
/// note | 기술 세부사항
74+
75+
다른 두 변수 `image_base64``binary_image`는 이미지를 Base64로 인코딩한 뒤 바이트로 변환한 것이며, 이를 `io.BytesIO`에 전달합니다.
76+
77+
이 예시에서 하나의 파일 안에 모두 담아, 그대로 복사해 실행할 수 있도록 하기 위한 목적입니다. 🥚
78+
79+
///
80+
81+
`with` 블록을 사용하면 제너레이터 함수(`yield`가 있는 함수)가 끝난 뒤, 즉 응답 전송이 완료된 후 파일 유사 객체가 닫히도록 보장합니다.
82+
83+
이 예시처럼 메모리 상의 가짜 파일(`io.BytesIO`)이라면 크게 중요하지 않지만, 실제 파일의 경우 작업이 끝난 뒤 파일을 닫는 것이 매우 중요합니다.
84+
85+
### 파일과 비동기 { #files-and-async }
86+
87+
대부분의 경우 파일 유사 객체는 기본적으로 async/await와 호환되지 않습니다.
88+
89+
예를 들어 `await file.read()``async for chunk in file`과 같은 패턴을 지원하지 않습니다.
90+
91+
또한 디스크나 네트워크에서 읽기 때문에, 많은 경우 읽기 작업은 이벤트 루프를 막을 수 있는 블로킹 연산입니다.
92+
93+
/// info | 정보
94+
95+
위의 예시는 예외적인 경우입니다. `io.BytesIO` 객체는 이미 메모리에 있으므로 읽기가 아무 것도 차단하지 않습니다.
96+
97+
하지만 실제 파일이나 파일 유사 객체를 읽을 때는 블로킹되는 경우가 많습니다.
98+
99+
///
100+
101+
이벤트 루프가 블로킹되는 것을 피하려면 경로 처리 함수를 `async def` 대신 일반 `def`로 선언하세요. 그러면 FastAPI가 스레드풀 워커에서 실행하여 메인 루프가 막히지 않도록 합니다.
102+
103+
{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}
104+
105+
/// tip | 팁
106+
107+
비동기 함수 안에서 블로킹 코드를 호출해야 하거나, 반대로 블로킹 함수 안에서 비동기 함수를 호출해야 한다면 FastAPI의 형제 라이브러리인 [Asyncer](https://asyncer.tiangolo.com)를 사용할 수 있습니다.
108+
109+
///
110+
111+
### `yield from` { #yield-from }
112+
113+
파일 유사 객체처럼 어떤 것을 순회하면서 각 항목마다 `yield`를 하는 대신, `yield from`을 사용해 각 항목을 직접 전달하고 `for` 루프를 생략할 수 있습니다.
114+
115+
이는 FastAPI에 특화된 기능이 아니라 순수한 파이썬 기능이지만, 알아두면 유용한 트릭입니다. 😎
116+
117+
{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# 엄격한 Content-Type 확인 { #strict-content-type-checking }
2+
3+
기본적으로 **FastAPI**는 JSON 요청 본문에 대해 엄격한 `Content-Type` 헤더 검사를 사용합니다. 이는 JSON 요청의 본문을 JSON으로 파싱하려면 유효한 `Content-Type` 헤더(예: `application/json`)를 반드시 포함해야 함을 의미합니다.
4+
5+
## CSRF 위험 { #csrf-risk }
6+
7+
이 기본 동작은 매우 특정한 시나리오에서 **Cross-Site Request Forgery (CSRF)** 공격의 한 유형에 대한 보호를 제공합니다.
8+
9+
이러한 공격은 브라우저가 다음과 같은 경우 CORS 사전 요청(preflight) 검사를 수행하지 않고 스크립트가 요청을 보내도록 허용한다는 점을 악용합니다:
10+
11+
- `Content-Type` 헤더가 없음(예: `Blob` 본문과 함께 `fetch()` 사용)
12+
- 그리고 어떠한 인증 자격 증명도 보내지 않음
13+
14+
이 유형의 공격은 주로 다음과 같은 경우에 관련이 있습니다:
15+
16+
- 애플리케이션이 로컬(예: `localhost`) 또는 내부 네트워크에서 실행 중이고
17+
- 애플리케이션에 인증이 없어 같은 네트워크에서 오는 모든 요청을 신뢰한다고 가정하는 경우
18+
19+
## 공격 예시 { #example-attack }
20+
21+
로컬 AI 에이전트를 실행하는 방법을 만들었다고 가정해 봅시다.
22+
23+
이 에이전트는 다음 위치에 API를 제공합니다:
24+
25+
```
26+
http://localhost:8000/v1/agents/multivac
27+
```
28+
29+
또한 다음 위치에 프론트엔드가 있습니다:
30+
31+
```
32+
http://localhost:8000
33+
```
34+
35+
/// tip | 팁
36+
37+
두 주소 모두 같은 호스트를 사용합니다.
38+
39+
///
40+
41+
그런 다음 프론트엔드를 통해 AI 에이전트가 여러분을 대신해 작업을 수행하도록 할 수 있습니다.
42+
43+
이는 공개 인터넷이 아니라 로컬에서 실행되므로, 여러분은 로컬 네트워크 접근만을 신뢰하고 별도의 인증을 설정하지 않기로 합니다.
44+
45+
그 후 사용자는 이를 설치해 로컬에서 실행할 수 있습니다.
46+
47+
그리고 다음과 같은 악성 웹사이트를 열 수 있습니다:
48+
49+
```
50+
https://evilhackers.example.com
51+
```
52+
53+
그 악성 웹사이트가 `Blob` 본문으로 `fetch()`를 사용해 로컬 API로 요청을 보냅니다:
54+
55+
```
56+
http://localhost:8000/v1/agents/multivac
57+
```
58+
59+
악성 웹사이트의 호스트와 로컬 앱의 호스트가 다르더라도, 브라우저는 다음과 같은 이유로 CORS 사전 요청(preflight)을 트리거하지 않습니다:
60+
61+
- 인증 없이 동작하므로 자격 증명을 보낼 필요가 없습니다.
62+
- 브라우저는 JSON을 보내지 않는다고 판단합니다(`Content-Type` 헤더가 없기 때문).
63+
64+
그러면 악성 웹사이트가 로컬 AI 에이전트로 하여금 사용자의 전 직장 상사에게 화난 메시지를 보내게 하거나... 더 나쁜 일을 시킬 수도 있습니다. 😅
65+
66+
## 공개 인터넷 { #open-internet }
67+
68+
여러분의 앱이 공개 인터넷에 있다면, '네트워크를 신뢰'하여 누구나 인증 없이 권한 있는 요청을 보내도록 두지는 않을 것입니다.
69+
70+
공격자는 브라우저 상호작용 없이도 스크립트를 실행해 여러분의 API로 요청을 보낼 수 있으므로, 아마 이미 권한이 필요한 엔드포인트는 보호하고 있을 것입니다.
71+
72+
그런 경우에는 이 공격/위험은 해당하지 않습니다.
73+
74+
이 위험과 공격은 주로 앱이 **로컬 네트워크**에서 실행되고 그것이 **유일한 보호수단**이라고 가정할 때 관련이 있습니다.
75+
76+
## Content-Type 없이 요청 허용하기 { #allowing-requests-without-content-type }
77+
78+
만약 `Content-Type` 헤더를 보내지 않는 클라이언트를 지원해야 한다면, `strict_content_type=False`로 설정해 엄격한 검사를 비활성화할 수 있습니다:
79+
80+
{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}
81+
82+
이 설정을 사용하면 `Content-Type` 헤더가 없는 요청도 본문이 JSON으로 파싱됩니다. 이는 이전 버전의 FastAPI와 동일한 동작입니다.
83+
84+
/// info | 정보
85+
86+
이 동작과 설정은 FastAPI 0.132.0에 추가되었습니다.
87+
88+
///

docs/ko/docs/editor-support.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# 에디터 지원 { #editor-support }
2+
3+
공식 [FastAPI 확장](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode)은 FastAPI 개발 워크플로우를 강화해 줍니다. *경로 처리* 탐색 및 이동, FastAPI Cloud 배포, 실시간 로그 스트리밍을 제공합니다.
4+
5+
확장에 대한 자세한 내용은 [GitHub 저장소](https://github.com/fastapi/fastapi-vscode)의 README를 참고하세요.
6+
7+
## 설치 및 설정 { #setup-and-installation }
8+
9+
**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) 같은 브라우저 기반 에디터에서도 동작합니다.
10+
11+
### 애플리케이션 자동 감지 { #application-discovery }
12+
13+
기본적으로 이 확장은 작업 공간에서 `FastAPI()`를 생성하는 파일을 스캔하여 FastAPI 애플리케이션을 자동으로 감지합니다. 프로젝트 구조상 자동 감지가 어려운 경우, `pyproject.toml``[tool.fastapi]` 항목이나 VS Code 설정 `fastapi.entryPoint`에 모듈 표기(예: `myapp.main:app`)로 엔트리포인트를 지정할 수 있습니다.
14+
15+
## 기능 { #features }
16+
17+
- **경로 처리 탐색기** - 애플리케이션의 모든 <dfn title="경로, 엔드포인트">*경로 처리*</dfn>를 사이드바 트리 뷰로 확인합니다. 클릭하면 해당 경로 또는 라우터 정의로 바로 이동합니다.
18+
- **경로 검색** - <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd> (macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>)로 경로, 메서드, 이름으로 검색합니다.
19+
- **CodeLens 탐색** - 테스트 클라이언트 호출(예: `client.get('/items')`) 위의 클릭 가능한 링크를 통해 해당 *경로 처리*로 즉시 이동하여 테스트와 구현 간을 빠르게 오갈 수 있습니다.
20+
- **FastAPI Cloud에 배포** - [FastAPI Cloud](https://fastapicloud.com/)로 원클릭 배포를 지원합니다.
21+
- **애플리케이션 로그 스트리밍** - FastAPI Cloud에 배포된 애플리케이션의 로그를 실시간으로 스트리밍하며, 레벨 필터링과 텍스트 검색을 제공합니다.
22+
23+
확장의 기능을 먼저 익혀보고 싶다면, 명령 팔레트(<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를 선택해 보세요.

0 commit comments

Comments
 (0)