일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- map
- android
- 스피너
- FastAPI
- 유튜브
- kotlin collection
- ktor client
- DiffUtil.ItemCallback
- 시행착오
- android ktor
- android exoplayer
- Python
- AWS EC2
- kotlin list
- build with ai
- ListAdapter DiffUtil
- ChatGPT
- video caching
- doc2vec
- list map
- Zsh
- android custom view
- 안드로이드
- ExoPlayer
- 유튜브 요약
- llm
- ktor api call
- ListAdapter
- exoplayer cache
- getChangePayload
- Today
- Total
버튼 수집상
[책] FastAPI를 사용한 파이썬 웹 개발 본문
책 읽으면서 메모 업데이트.
fastapi: 애플리케이션을 구축하기 위해 필요한 프레임워크
uvicorn: 애플리케이션을 실행하기 위한 비동기 asynchronous 방식 서버 게이트웨이 인터페이스 (ASGI)
이에 대해 ChatGPT에게 물어봄.
>> FastAPI의 핵심 기능 중 하나는 비동기 코드를 지원하는 것이며, 이를 효과적으로 처리하기 위해 Uvicorn과 같은 ASGI 서버를 사용하는 것이 일반적입니다. Uvicorn은 FastAPI 애플리케이션의 비동기 라우트 및 이벤트 핸들러를 처리하고 실행하는 데 특히 효과적입니다.
>> FastAPI는 비동기 프레임워크이며, 라우트 함수가 async def로 정의될 수 있습니다. 이로써 비동기 코드를 사용하여 I/O 바운드 작업을 효율적으로 처리할 수 있습니다. Uvicorn은 이러한 비동기 코드를 ASGI 인터페이스를 통해 서버에 적절하게 처리할 수 있게 도와줍니다.
Q. 그럼 fastapi에서 라우트를 비동기로 처리하고 애플리케이션을 gunicorn (동기식 서버) 으로 돌리면 어떻게 돼?
>> (생략)
>> Gunicorn 설치:
pip install gunicorn
>> Gunicorn을 사용하여 FastAPI 애플리케이션 실행:
gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app
>> 위 명령에서 -w는 worker의 수를 나타내며, -k는 사용할 worker 클래스를 지정합니다. -k uvicorn.workers.UvicornWorker 부분은 Gunicorn이 UvicornWorker를 사용하여 FastAPI 애플리케이션을 실행하도록 지정합니다.
>> 이제 Gunicorn이 FastAPI 애플리케이션을 WSGI 서버로 실행하고, 비동기 코드를 처리할 때는 Gunicorn 내부에서 UvicornWorker를 사용하여 처리합니다.
uvicorn 외의 ASGI 웹서버 옵션들
https://fastapi.tiangolo.com/deployment/manually/
Run a Server Manually - Uvicorn - FastAPI
FastAPI framework, high performance, easy to learn, fast to code, ready for production
fastapi.tiangolo.com
- Uvicorn
- Hypercorn
- Daphne
FastAPI()인스턴스를 사용하는 경우, 애플리케이션은 한 번에 여러 라우트를 처리할 수 없다.
uvicorn이 하나의 엔트리포인트만 실행할 수 있기 때문이다.
그렇다면 여러 함수를 사용하는 연속적인 라우트 처리는 어떻게 할 수 있을까?
-> APIRouter 클래스 사용
메서드만 다르게 하면 api 패스를 동일하게 쓸 수도 있다!
@router.post("/todo")
async def add_todo(todo: dict) -> dict:
#...
@router.get("/todo")
async def retrieve_todos() -> dict:
# ...
경로 매개변수
@router.get("/todo/{todo_idx}")
async def get_single_todo(todo_idx: int) -> dict:
경로 매개변수 검증해주는 Path 클래스
from fastapi import Path
쿼리 매개변수 검증해주는 Query 클래스도 있다.
POST와 UPDATE 메서드에 데이터 전달하는 리퀘스트 바디
.. 를 검증해주는 Body 클래스도 있다.
pydantic BaseModel 클래스에 config 추가 가능
문서화할때 샘플 데이터 보여주기 용도.
from pydantic import BaseModel
class TodoItem(BaseModel) :
item: str
class Config:
schema_extra = {
"example" : {
"item": "Read the next chapter of the book"
}
}
그런데 위 샘플대로 적으면 swagger 문서에서 예시 데이터가 뜨지 않는다.
아래처럼 적용해야한다.
from pydantic import BaseModel
class TodoItem(BaseModel) :
item: str
#테스트시 기입
model_config={
"json_schema_extra":{
"examples":[
{
"item":"Read the next chapter of the book"
}
]
}
}
리턴 값을 검사해서 상태코드를 404 띄울 수도 있음
from fastapi import HTTPException, status
@router.get("/todo/{todo_idx}")
async def get_single_todo(todo_id: int) -> dict:
for todo in todo_list:
if todo.id == todo_id:
return {
"todo": todo
}
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Todo with given ID does not exist"
)
pydantic 모델의 Optional 필드
from typing import Optional, List
from pydantic import BaseModel, EmailStr
class User(BaseModel):
email: EmailStr
password: str
events: Optional[List[Event]]
이메일 값을 검증해주는 EmailStr 클래스는 email-validator 라는 패키지를 설치해야만 한다.
그리고 Optional 클래스는 pydantic 모델 안에서만 써야지, FastAPI 라우트의 쿼리 매개변수를 정의할 때 쓰는 게 아니었다ㅎ.
@router.get("/list", response_model=List[User])
async def get_list(search_keyword:Optional[str]) :
# ...
위처럼 쓰면 search_keyword 쿼리 파라미터가 없을 때 서버 에러 난다..
아마 이에 대한 처리는 위에서 언급된 Query 클래스가 해주지 않을까 싶다.
아니면 그냥 디폴트값을 넣어두거나..
@router.get("/list", response_model=List[User])
async def get_list(search_keyword:str="") :
# ...
로그인(signIn) 라우트 정의하기 (예시)
@router.post("/signIn")
async def sign_user_in(user: UserSignIn) -> dict:
if user.email not in users:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="User does not exist"
)
if users[user.email].password != user.password:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Wrong credentials passed"
)
return {
"message" : "User signed in successfully."
}
여기서는 설명을 위해 패스워드를 암호화하지 않고 일반 텍스트로 저장했지만 소프트웨어 개발 관점에서는 잘못된 방식이다. <CHAPTER6>에서 암호화를 사용한 패스워드 저장방식을 설명한다.
라우터 등록할 때 prefix 등록 가능
from route.users import user_router
app = FastAPI()
app.include_router(user_router, prefix="/user")
현재 절반 읽음.
'일상 - 책' 카테고리의 다른 글
[책] HTTP 완벽 가이드 - 9장 웹 로봇 (0) | 2025.02.17 |
---|---|
[책] 새빨간 거짓말, 통계 (0) | 2024.05.08 |
[책] 배드블러드 Bad Blood (0) | 2023.11.09 |
책 읽고 메모하는 법 업데이트 (0) | 2023.07.11 |
[책] 2023년 상반기 읽은 책 리스트 (0) | 2023.07.03 |