Share
Sign In
Lighthouse Dev
FastAPI 특징 with Pydantic
D
donggyun_woo
👍👍🏻
3
😀
1
😘
1
🟩
1
💬
이번 글에서는 python FastAPI의 특징과 FastAPI내에서 Pydantic을 사용한 코드를 확인해 보겠습니다.
Fast API
Fast API란?
FastAPI는 Python 프레임워크 중 하나입니다. Python 프레임워크들 중 django, flask 와 같이 비교를 많이 하며, 빠른 속도로 인해 인기가 많아진 프레임워크입니다.
FastAPI에서 제공하는 기능들을 간략히 보면 아래와 같습니다.
👍
API 문서 자동 생성 (Swagger와 ReDoc 스타일 동일)
의존성 주입 위주의 설계를 통한 DB 등에 대한 관리 편리
비동기 동작으로 빠른 성능 보장 (Starlette)
Pydantic을 사용한 Validation 체크
뛰어난 공식문서 가이드
Python Framework 깃허브 스타
github star history 그래프를 보면 FastAPI(노란색)의 스타가 급격히 증가하는 것을 확인 할 수 있습니다.
그래프를 통해 FastAPI를 많이 사용한다는 의미는 될 수 없겠지만, 개발자들 사이에서 관심을 많이 갖고 있는것은 확인 할 수 있을것 같습니다.
FastAPI의 특징
특징들을 Fast API 공식문서를 통해 자세하게 확인해 보겠습니다.
💬
파이썬 3.8+ 버전의 Type hint를 사용하는 트랜디하고 높은 성능을 가진 파이썬 프레임워크
빠름: NodeJS 및 Go와 동등한 매우 높은 성능을 제공
실제 파이썬 기반의 프레임워크들을 비교한 내용을 확인해 보면 성능이 상위에 존재하는 것을 확인 할 수 있습니다.
빠른 코딩: 기능 개발 속도를 약 200%~300% 향상
버그 감소: 인간(개발자)이 유발한 오류의 약 40% 감소
직관적: 뛰어난 편집기 지원. 디버깅 시간이 줄어듭니다.
간단: 사용 및 학습이 용이하도록 설계되었습니다. 문서를 읽는 시간이 줄어듭니다.
짧게: 코드 중복을 최소화합니다. 버그 수를 줄입니다.
견고함: production-ready code를 얻을 수 있음.
🙋
To write production-ready code in Python,
it is important to understand the importance of code modularization, following PEP8 style guidelines, using meaningful variable, class, and function names, organizing your code, and writing thorough documentation.
표준 기반: API의 개방형 표준인 OpenAPI(이전의 Swagger)와 JSON Schema를 기반으로 합니다.
Starlette & Pydantic
Fast API는 빠른 속도와 코딩이 가능하고, 직관적이라고 합니다. 이런 특징을 갖게 된 이유는 StarlettePydantic 등을 사용한 결과이기도 합니다.
Starlette
Starlette에 대해 알기 전에 먼저 ASGI, WSGI에 대해 알아 보겠습니다.
WSGI(Web Server Gateway Interface)
WSGI는 파이썬 웹 응용 프로그램을 위한 것
웹서버와 파이썬으로 작성된 웹 응용 프로그램 간의 표준 인터페이스
gunicorn
기존의 동기(django, flask)로 작동되는 웹프레임워크들은 gunicorn을 많이 사용했습니다.
ASGI(Asynchronous Server Gateway Interface)
ASGI의 공식문서에서는 따르면, ASGI는 WSGI의 정신적 계승자로, 비동기 가능 Python 웹 서버, 프레임워크 및 애플리케이션 간의 표준 인터페이스를 제공하기 위한 것
WSGI가 동기 Python 앱에 대한 표준을 제공했다면 ASGI는 WSGI 이전 버전과의 호환성 구현과 여러 서버 및 애플리케이션 프레임워크를 통해 비동기 및 동기 앱 모두에 대한 표준을 제공합니다.
다시 Starlette으로 돌아가면, 공식 문서에서는 Python에서 비동기 웹 서비스를 구축하는 데 이상적인 경량 ASGI 프레임워크/툴킷으로 설명 합니다.
그리고 FastAPI는 이 Starlette을 기반으로 개발이 되었고, 그로 인해 비동기 동작이 가능한 서버를 구현합니다.
아래의 이미지 처럼 FastAPI앞에 ASGI의 하나인 uvicorn을 넣어서 비동기로 서버를 운영합니다.
Pydantic
Pydantic은 파이썬의 Type annotation(type hint)을 활용하여 data validataion(검증)과 세팅을 관리해 주는 파이썬 라이브러리입니다.
FastAPI에서 Pydantic이 하는 역할은 다음과 같습니다.
API 문서 자동화
입출력 항목의 갯수와 타입을 설정
입출력 항목의 필수값 체크
입출력 항목의 데이터 검증
Pydantic 장점
FastAPI에서 Pydantic을 사용하는 이점은 다음과 같습니다.
데이터 검증 및 직렬화 최적화 : Pydantic은 데이터 검증 및 직렬화(데이터 구조를 문자열 형태로 변환) 과정을 효율적으로 처리합니다. 이는 FastAPI가 요청을 빠르게 분석하고 응답 데이터를 신속하게 생성하는데 도움을 줍니다.
타입 힌트와 통합 : Pydantic은 Python의 타입 힌트와 밀접하게 통합되어 있어 명확한 타입 정의를 사용할 수 있게 합니다. 이를 통해 런타임 오류를 줄이고 성능을 개선합니다.
오류 처리 : Pydantic은 유효성 검증을 통해 발생할 수 있는 오류를 잡아내고, 에러 메시지로 반환하여 안정적인 성능을 유지하는데 기여합니다.
코드의 간결성과 유지보수성 : Pydantic을 사용하면 데이터 모델을 쉽게 유지보수 할 수 있습니다.
Pydantic - 적용 예제 코드
from typing import Union from fastapi import FastAPI from pydantic import BaseModel, EmailStr class BaseUser(BaseModel): user_id: int username: str email: EmailStr full_name: Union[str, None] = None # Type hint를 통해 스키마를 설정할 수 있다. class UserIn(BaseUser): # 상속을 받을 수 있어 코드를 줄일 수 있다. password: str @app.put("/items/{item_id}") async def update_item(item_id: int, item: Item, user: BaseUser): results = {"item_id": item_id, "item": item, "user": user} return results @app.post("/user/") async def create_user(user: UserIn) -> BaseUser: # 결과값에 대한 정의 이다. # user: UserIn => 사용자를 생성할 때 받아야하는 request body 값을 정의한다. return user
Pydantic - 데이터 검증 예제 코드
from typing import Union from pydantic import BaseModel ... class Item(BaseModel): name: str description: Union[str, None] = None price: float tax: Union[float, None] = None ... @app.put("/items/{item_id}") async def update_item( item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)], q: Union[str, None] = None, item: Union[Item, None] = None, ): results = {"item_id": item_id} if q: results.update({"q": q}) if item: results.update({"item": item}) return results
update를 하는 API가 있을 때, request body 값에 들어가야하는 내용을 Pydantic을 사용하여 데이터 스키마를 정의합니다.
Type hint를 활용해서 데이터 속성의 타입을 정의 할 수 있습니다.
FastAPI에서 제공하는 OpenAPI(swagger)로 확인을 해보면 path parameter, query parameter, request body를 확인 할 수 있고, 테스트가 가능합니다.
request body 값으로 미리 설정한 Pydantic에 맞게 실행을 하게 된다면 정상적으로 200 을 반환합니다.
// request body { "name": "string", "description": "string", "price": 1, "tax": 0 } // response body **{ "item_id": 1, "q": "test", "item": { "name": "string", "description": "string", "price": 1, "tax": 0 } } // log** >>> INFO: 127.0.0.1:8630 - "PUT /items/1?q=test HTTP/1.1" 200 OK
하지만 검증에 틀리는 경우에는 다음과 같습니다.
// request body { "name": "string", "description": "string", "price": "ff1", # float 값이 아닌 string 값인 경우 "tax": 0 } // response body { "detail": [ { "type": "float_parsing", "loc": [ "body", "price" ], "msg": "Input should be a valid number, unable to parse string as a number", "input": "ff1", "url": "https://errors.pydantic.dev/2.5/v/float_parsing" } ] } // log >>> INFO: 127.0.0.1:8693 - "PUT /items/1?q=test HTTP/1.1" 422 Unprocessable Entity
마무리
이번 세션을 준비하면서 Fast API에 대해 공부를 했습니다.
공식 가이드 문서가 잘 되어 있고, 관련된 기술 블로그들도 생각보다 많아서 참고하기에 좋았습니다.
참고 사이트 및 문서
Kp
Subscribe to 'kpmg-lighthouse'
Welcome to 'kpmg-lighthouse'!
By subscribing to my site, you'll be the first to receive notifications and emails about the latest updates, including new posts.
Join SlashPage and subscribe to 'kpmg-lighthouse'!
Subscribe
👍👍🏻
3
😀
1
😘
1
🟩
1
김원준
파이썬의 동시성 관리 : GIL 과 멀티 스레딩
0. 들어가며 저번 시간에는 동시성. 즉, 제어권에 대한 Blocking/NonBolocking. 또 작업의 순서를 논하는 Sync/Async에 대해 간단하게 살펴보았다. 그렇다면 이번 시간에는 다음 순서로 파이썬의 GIL 및 스레드 환경에 대해 살펴보자. 0-1. 들어가기 앞서 ! 오늘 발표를 조금 더 잘 이해할 수 있도록 하기 위해, 몇가지 용어에 대한 설명을 준비하였다. 메모리란 ? 메모리는 컴퓨터가 프로그램과 데이터를 저장하고 처리하는 데 사용되는 저장 공간이다. 프로그램의 실행 중에 생성되는 데이터는 물리적인 메모리에 저장 되며(주로 RAM), 이 데이터는 스레드가 실행되면서 읽고 쓰게 된다. 프로세스란 ? 실행 중에 있는 프로그램을 의미한다. 작업(Task)과 같은 의미로 쓰인다. 프로세스는 최소 하나의 스레드를 가지는데, 실제로 작업(Task)이 스레드 단위로 동작한다. 스레드란 ? 스레드는 프로그램 내에서 실행되는 흐름의 단위. 일반적으로 한 프로그램은 하나의 스레드를 가지고 있지만, 프로그램의 환경에 따라 둘 이상의 스레드를 동시에 실행할 수 있다. 이것이 바로 멀티스레딩이다. 프로세스 구조 프로세스의 데이터와 명령어가 있는 영역은 Code(Text), Data, Stack, Heap이다. 💡각 프로세스는 별도의 공간(독립된 메모리)에서 실행되고 프로세스끼리는 자원의 공유를 하지 않는다. 그렇다보니, 프로세스 간의 자원을 공유하기 위해서는 별도의 통신이 필요하다. 스레드 구조 스레드는 Stack만 따로 할당받고, Code(Text), Data, Heap 영역은 프로세스의 자원을 공유한다. 💡자원을 공유하다보니, 시스템의 자원과 처리 비용이 멀티 프로세싱에 비해 적다. (통신의 부담X) 하지만 자원을 공유하고 있다 보니, 멀티 스레딩 환경에서 동기화의 문제가 발생할 수 있다.
❤️
2
Lighthouse
TDD(Test-Driven Development)
안녕하세요, 오늘은 TDD(Test-Driven Development)에 대해 이야기하려 합니다. TDD 소프트웨어 개발 방법론 중 하나로, 개발 과정에서 테스트를 우선하여 작성하고 이를 통과시키는 것에 초점을 두는 방법론입니다. 코드를 작성하기 이전에 테스트 케이스를 작성하고, 이를 통과하기 위한 그에 맞는 기능을 작성하는 작업을 반복하여 개발합니다. TDD의 장점과 한계 TDD의 장점: 품질 향상: 개발자는 코드의 동작을 확실히 이해하고 테스트 케이스를 통해 코드의 정확성을 검증할 수 있어, 더 견고하고 안정적인 코드를 작성할 수 있습니다. 리팩토링 지원: 코드를 작은 단위로 분리하고 테스트 가능한 형태로 작성하여 코드의 구조와 설계를 개선하기 쉽게 합니다. 빠른 피드백: 작은 단위의 테스트를 빠르게 실행하고 결과를 확인하여 버그를 빠르게 발견하고 수정할 수 있으며, 코드 변경에 대한 피드백을 신속하게 받을 수 있습니다. 협업 강화: 테스트 코드가 개발 프로세스의 일부로 문서화되어 있어 다른 개발자들과의 협업을 용이하게 하며, 코드의 동작을 이해하고 검증하는 데 도움이 됩니다. TDD의 한계: 시간과 노력: 테스트 코드를 작성하기 위해 추가적인 시간과 노력이 필요하며, 개발 시간이 늘어날 수 있습니다. 설계에 대한 이해: 테스트 케이스를 작성하기 위해 개발자는 코드의 설계에 대한 깊은 이해가 필요하며, 이를 갖추지 않으면 테스트 케이스가 미흡해질 수 있습니다. 복잡한 시나리오의 테스트: 복잡한 시나리오나 UI, 성능 테스트 등은 TDD로 테스트하기 어려울 수 있습니다. 변동이 많은 요구사항: 요구사항이 자주 변경되는 경우, 테스트 케이스를 계속 수정해야 하는 상황이 발생할 수 있습니다. 출처: https://semaphoreci.com/wp-content/uploads/2022/02/tdd-vs-waterfall.webp 이러한 장점과 한계로 인해 TDD는 초기에는 추가 비용이 들 수 있지만, 시간이 지남에 따라 비용을 절감할 수 있는 특징을 지녔습니다. TDD의 사이클 Lifecycle of the Test-Driven Development method 출처: https://ko.wikipedia.org/wiki/테스트_주도_개발 Write Test: 기능을 검증할 테스트 케이스를 작성
Lighthouse
파이썬의 동시성 관리 : 코루틴(Corutine) 上
0. 들어가기 앞서 지난 시간에는 파이썬의 GIL 제약과 그 제약으로 인해 “찐”효율을 내지 못하는 멀티 스레드 프로그래밍에 대해서 알아보았다. 이번 시간에는 파이썬 비동기의 핵심 키워드 네이티브 코루틴인 Asyncio, async, await를 이해하기 전 이것들의 근간이라 불리는 코루틴(Corutine)에 대해서 알아보자. 들어가기 앞서, 복습 차원에서 지난 시간 내용을 간략하게 정리하자 1. 제네레이터 1.1. 제네레이터 제네레이터는 쉽게 말해서, 여러개의 데이터를 미리 만들어 놓지 않고 필요한 때마다 즉석에서 하나씩 만들어낼 수 있는 객체를 의미한다. 일반적인 함수와 달리 상태를 유지할 수 있다. 즉, 제네레이터는 yield 표현식을 사용하여 값을 반환하고, 다음 호출 시 마지막으로 실행된 yield 표현식 이후부터 실행을 재개한다. 일반함수는 return을 만나면 실행이 끝나버린다. 하지만 제네레이터는 yield 구문에서 “일시정지”의 상태로 값을 외부로 내보낸다. 그 이후에 필요할 때 다시 실행 흐름을 이어나갈 수 있다. 함수 내부에서 사용된 지역 변수등이 메모리에 그대로 유지되어 있기 때문이다. 아래 코드를 살펴보자. 함수 return_abc()는, 알파벳을 1초마다 하나하나 리스트에 적재하는 코드이다. print를 찍어본다면 어떻게 될까? 너무 당연한 결과이다. 그렇다면 해당 함수를 for loop에 돌려보면 어떻게 될까? 이 결과 역시 너무나도 쉽게 예상할 수 있다. 여기서 3초라는 시간을 잘 기억해주길 바란다. 위에서 제네레이터는 데이터를 미리 만들어두지 않고, 필요할 때마다 하나씩 만들어내는 객체를 뜻한다 했다. 이것도 코드를 통해 알아보자. 뭔가 위의 코드랑 별로 달라진게 없어보인다. print를 찍어보자. !! 예상했던 것과는 달리 제네레이터가 출력 되었다 !! 위에서 언급했던 것처럼 제네레이터는 “필요할 때마다” “하나씩” 만들어 낸다고 했으니, 한번 for문을 통해서 “하나씩” 값을 받아와 보자.
😍
1