FastAPI - 좋은, 나쁜, 못생긴 것.
좋다
1. FastAPI 확인
FastAPI
을 다른 주요 Python 프레임워크(예를 들어 Flask
과 Django
)와 비교했을 때 그 속도는 상당히 빠르다.다음 Techempower의 분수도는 두 프레임 간의 성능 차이가 얼마나 큰지 보여 준다.
나도 어떤 프레임워크가 가장 빠른지 작은 테스트를 했는데 결과는 실제로 매우 재미있었다.이 테스트에 대해 저는 모든 3개 프레임워크에 기본적인'Hello world'API를 설정했습니다.API 호출을 통해 응답 시간을 테스트하고 평균 응답 시간을 계산했습니다.결과는 두 가지 상황으로 나눌 수 있다.
a, 서버 시작 후 첫 번째 호출의 평균 시간
b. 첫 통화 후 연속 통화의 평균 시간Django
및 FastAPI
은 첫 번째 API 호출에서 평소보다 응답 속도가 느립니다.Flask
은 항상 일치하지만 모든 API 호출 기간은 다른 두 개보다 훨씬 느리다.
세 API 모두에 사용되는 평균 시간은 다음과 같습니다.
프레임
사례
사례
FastAPI
17ms
6.2ms
회사 명
517.2ms
5.834ms
병.
507.2ms
508.9ms
여기서 주목할 만한 것은 Django가 처음 호출된 후의 실행 속도가 실제로는 FastAPI보다 조금 빠르다는 것이다.그러나 일부 장면에서 서버 환경이 없으면 Django의 첫 호출과 시작 시간이 높을 수 있습니다.주의해야 할 것은 측정은 특정 환경에서 이루어지고 데이터가 매우 적으며 저는 Flask와 Django에 대한 경험이 매우 제한되어 있기 때문에 결과는 당신에 따라 다를 수 있습니다.
2. 비동기식 코드 지원
FastAPI의 가장 흥미로운 특징은 async/await
Python 키워드를 사용하는 실시간 비동기 코드를 지원한다는 것이다.다음은 Reddit에서 비동기적으로 데이터를 가져오는 API 예입니다.(예: Python async/await Tutorial by Scott Robinson 참조)
app = FastAPI()
async def get_json(client: ClientSession, url: str) -> bytes:
async with client.get(url) as response:
assert response.status == 200
return await response.read()
async def get_reddit_top(subreddit: str, client: ClientSession, data: dict):
data1 = await get_json(client, 'https://www.reddit.com/r/' + subreddit + '/top.json?sort=top&t=day&limit=5')
j = json.loads(data1.decode('utf-8'))
subreddit_data = []
for i in j['data']['children']:
score = i['data']['score']
title = i['data']['title']
link = i['data']['url']
print(str(score) + ': ' + title + ' (' + link + ')')
subreddit_data.append(str(score) + ': ' + title + ' (' + link + ')')
data[subreddit] = subreddit_data
print('DONE:', subreddit + '\n')
@app.get("/")
async def get_reddit_data_api() -> dict:
start_time: float = time.time()
client: ClientSession = aiohttp.ClientSession()
data: dict = {}
await asyncio.gather(
get_reddit_top('python', client, data),
get_reddit_top('programming', client, data),
get_reddit_top('compsci', client, data),
)
await client.close()
print("Got reddit data in ---" + str(time.time() - start_time) + "seconds ---")
return data
비동기 코드의 신기한 점은 협동 루트가 get_reddit_top
에서 동시에 운행하기 때문에 직렬 운행에 비해 API의 집행 시간이 현저히 줄어든다는 것이다.
3. 개발 시간이 매우 짧다
기본 "Hello world"API를 만들기 위해 이 프레임워크는 전체 항목을 고려하여 다음 코드 줄 수를 필요로 합니다.
프레임
코드 행
FastAPI
8행
병.
7개 노선
나는 Django를 고려하지 않았다. 왜냐하면 나는 그것의 구조가 다른 두 가지와 다르다고 생각하기 때문이다.
FastApi 응용 프로그램을 확장하고 싶다면, 이 작업도 Flask와 유사합니다.둘 다 Flask의 청사진과 FastAPI의 라우터를 통해 모듈식 개념을 가지고 있습니다.그래서 Flask와 FastAPI의 개발 시간은 매우 비슷하다고 말하고 싶습니다.
4, 테스트 용이성
FastAPI 노드 테스트는 FastAPI에서 제공하는 TestClient을 사용하여 간단합니다.이것은 테스트 구동 개발(TDD)을 매우 쉽게 한다.
app = FastAPI()
@app.get("/")
async def read_main():
return {"msg": "Hello World"}
client = TestClient(app)
def test_read_main():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"msg": "Hello World"}
API 정의 함수(예: read_main
)의 서비스 호출이나 코드를 쉽게 시뮬레이션하고 TestClient를 사용하여 테스트할 수 있습니다.
5. 틈새 없는 중앙 이상 처리
FastAPI에서 예외를 처리하려면 @app.exception_handler
주석 또는 app.add_exception_handler
함수를 사용하여 Exception
의 응답을 등록하면 FastAPI에서 처리됩니다.
app = FastAPI()
@app.exception_handler(SomeException)
async def http_exception_handler(request: Request, exc: SomeException) -> PlainTextResponse:
return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
async def request_exception_handler(request: Request, exc: SomeOtherException) -> PlainTextResponse:
return PlainTextResponse(str(exc.detail),status_code=exc.status_code)
app.add_exception_handler(exc_class_or_status_code=SomeOtherException,
handler=request_exception_handler)
6. 우수한 문서
FastAPI는 매우 광범위하고 예시가 풍부한 documentation을 가지고 있어 일을 더욱 쉽게 한다.FastAPI에 대한 컨텐트를 찾으려면 다른 컨텐트를 찾을 필요가 없습니다.
7, 구축 용이성
FastAPI에서 제공하는 docker image을 사용하면 Docker를 통해 FastAPI 응용 프로그램을 쉽게 배포할 수 있습니다.Mangum을 사용하여 AWS Lamdba에 배포할 수도 있습니다.
나쁘다
1. 마스터 파일 혼잡
FastAPI에서는 모든 내용이 FastAPI app
과 연결됩니다.따라서 main.py
파일은 매우 붐비기 쉽습니다.여기에 예가 하나 있다.
app = FastAPI()
app.include_router(users.router)
app.include_router(items.router)
app.include_router(shops.router)
app.include_router(other.router)
@app.exception_handler(SomeException)
async def http_exception_handler(request: Request, exc: SomeException) -> PlainTextResponse:
return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
@app.exception_handler(SomeOtherException)
async def http_exception_handler(request: Request, exc: SomeOtherException) -> PlainTextResponse:
return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
현재 10개의 공유기와 20개의 이상이 처리되어야 한다고 가정하면 main.py
파일은 유지하기 어려워질 수 있습니다.다행히도 이것은 쉽게 해결된다.
app = FastAPI()
include_routers(app);
add_exception_handlers(app);
include_routers
및 add_exception_handlers
은 별도의 파일에 저장할 수 있습니다.
2. 의존 주입 중 단례가 없다
Github thread에 따르면 FastAPI의 의존 주입은 singleton
인스턴스를 지원하지 않지만 HTTP 요청마다 단일 인스턴스를 지원합니다.단일 클래스를 직접 만들거나 다른 DI 라이브러리를 사용합니다.
못난이
검증 요청
FastAPI를 사용할 때 가장 나쁜 경험은 요청 검증을 처리하는 것입니다.이것은 Pydantic
의 검증을 사용하는데, 내가 알기로는 검증 메시지를 검증점에서 응답으로 전달하는 직접적인 방법이 없다.Pydantic
에서 RequestValidationError
으로 전달되는 모든 메시지를 처리하거나 사용자 정의 검증기를 작성할 수 있습니다.예:
app = FastAPI()
class SomeDto(BaseModel):
data: str = Field(min_length=1, description="Minimum length must be greater than 1",
title="Minimum length must be greater than 1")
@app.post(path="/")
async def get_response(request: SomeDto):
return "some response"
@app.exception_handler(RequestValidationError)
async def handle_error(request: Request, exc: RequestValidationError) -> PlainTextResponse:
return PlainTextResponse(str(exc.errors()), status_code=400)
exc.errors()
은 Pydantic
에서 온 하드 인코딩 메시지를 포함하는 검증 충돌 목록을 되돌려줍니다.나는 FastAPI
과 Pydantic
의 파일에서 그것을 바꿀 방법을 찾지 못했다.심지어 description
과 title
의 매개 변수 값도 잃어버릴 수 있다.
입문
FastAPI를 사용하기 시작하려면 여기에 아주 좋은 자원이 있습니다.다음은 탐색할 수 있는 몇 가지 내용입니다.
app = FastAPI()
async def get_json(client: ClientSession, url: str) -> bytes:
async with client.get(url) as response:
assert response.status == 200
return await response.read()
async def get_reddit_top(subreddit: str, client: ClientSession, data: dict):
data1 = await get_json(client, 'https://www.reddit.com/r/' + subreddit + '/top.json?sort=top&t=day&limit=5')
j = json.loads(data1.decode('utf-8'))
subreddit_data = []
for i in j['data']['children']:
score = i['data']['score']
title = i['data']['title']
link = i['data']['url']
print(str(score) + ': ' + title + ' (' + link + ')')
subreddit_data.append(str(score) + ': ' + title + ' (' + link + ')')
data[subreddit] = subreddit_data
print('DONE:', subreddit + '\n')
@app.get("/")
async def get_reddit_data_api() -> dict:
start_time: float = time.time()
client: ClientSession = aiohttp.ClientSession()
data: dict = {}
await asyncio.gather(
get_reddit_top('python', client, data),
get_reddit_top('programming', client, data),
get_reddit_top('compsci', client, data),
)
await client.close()
print("Got reddit data in ---" + str(time.time() - start_time) + "seconds ---")
return data
app = FastAPI()
@app.get("/")
async def read_main():
return {"msg": "Hello World"}
client = TestClient(app)
def test_read_main():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"msg": "Hello World"}
app = FastAPI()
@app.exception_handler(SomeException)
async def http_exception_handler(request: Request, exc: SomeException) -> PlainTextResponse:
return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
async def request_exception_handler(request: Request, exc: SomeOtherException) -> PlainTextResponse:
return PlainTextResponse(str(exc.detail),status_code=exc.status_code)
app.add_exception_handler(exc_class_or_status_code=SomeOtherException,
handler=request_exception_handler)
1. 마스터 파일 혼잡
FastAPI에서는 모든 내용이
FastAPI app
과 연결됩니다.따라서 main.py
파일은 매우 붐비기 쉽습니다.여기에 예가 하나 있다.app = FastAPI()
app.include_router(users.router)
app.include_router(items.router)
app.include_router(shops.router)
app.include_router(other.router)
@app.exception_handler(SomeException)
async def http_exception_handler(request: Request, exc: SomeException) -> PlainTextResponse:
return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
@app.exception_handler(SomeOtherException)
async def http_exception_handler(request: Request, exc: SomeOtherException) -> PlainTextResponse:
return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
현재 10개의 공유기와 20개의 이상이 처리되어야 한다고 가정하면 main.py
파일은 유지하기 어려워질 수 있습니다.다행히도 이것은 쉽게 해결된다.app = FastAPI()
include_routers(app);
add_exception_handlers(app);
include_routers
및 add_exception_handlers
은 별도의 파일에 저장할 수 있습니다.2. 의존 주입 중 단례가 없다
Github thread에 따르면 FastAPI의 의존 주입은
singleton
인스턴스를 지원하지 않지만 HTTP 요청마다 단일 인스턴스를 지원합니다.단일 클래스를 직접 만들거나 다른 DI 라이브러리를 사용합니다.못난이
검증 요청
FastAPI를 사용할 때 가장 나쁜 경험은 요청 검증을 처리하는 것입니다.이것은 Pydantic
의 검증을 사용하는데, 내가 알기로는 검증 메시지를 검증점에서 응답으로 전달하는 직접적인 방법이 없다.Pydantic
에서 RequestValidationError
으로 전달되는 모든 메시지를 처리하거나 사용자 정의 검증기를 작성할 수 있습니다.예:
app = FastAPI()
class SomeDto(BaseModel):
data: str = Field(min_length=1, description="Minimum length must be greater than 1",
title="Minimum length must be greater than 1")
@app.post(path="/")
async def get_response(request: SomeDto):
return "some response"
@app.exception_handler(RequestValidationError)
async def handle_error(request: Request, exc: RequestValidationError) -> PlainTextResponse:
return PlainTextResponse(str(exc.errors()), status_code=400)
exc.errors()
은 Pydantic
에서 온 하드 인코딩 메시지를 포함하는 검증 충돌 목록을 되돌려줍니다.나는 FastAPI
과 Pydantic
의 파일에서 그것을 바꿀 방법을 찾지 못했다.심지어 description
과 title
의 매개 변수 값도 잃어버릴 수 있다.
입문
FastAPI를 사용하기 시작하려면 여기에 아주 좋은 자원이 있습니다.다음은 탐색할 수 있는 몇 가지 내용입니다.
app = FastAPI()
class SomeDto(BaseModel):
data: str = Field(min_length=1, description="Minimum length must be greater than 1",
title="Minimum length must be greater than 1")
@app.post(path="/")
async def get_response(request: SomeDto):
return "some response"
@app.exception_handler(RequestValidationError)
async def handle_error(request: Request, exc: RequestValidationError) -> PlainTextResponse:
return PlainTextResponse(str(exc.errors()), status_code=400)
FastAPI를 사용하기 시작하려면 여기에 아주 좋은 자원이 있습니다.다음은 탐색할 수 있는 몇 가지 내용입니다.
Reference
이 문제에 관하여(FastAPI - 좋은, 나쁜, 못생긴 것.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/fuadrafid/fastapi-the-good-the-bad-and-the-ugly-20ob텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)