Product Serving(5): FastAPI

SeongGyun Hong·2024년 12월 12일

NaverBoostCamp

목록 보기
44/64

1. FastAPI란?

대표적인 Python Web Framework
Django, FastAPI, Flask 등...

  • High Performance
  • Easy
  • Productivity

추천 학습방법
1. 웹서버를 직접 띄워서 점진적으로 기능 추가하기
2. 처음엔 FastAPI의 기본 기능에 익숙해지기
3. 자신이 만들어 두었던 모델들을 FastAPI 서버에 띄우기
4. 특정 기능을 구현하기 위해 어떻게 설계해야하는지 생각하고 구현하기


  • v1 프로젝트 구조
    • 프로젝트 코드가 들어갈 모듈 설정(app, 또는 프로젝트 이름, src 등)
      • __main__.py는 간단하게 애플리케이션을 실행할 수 있는 entrypoint 역할
      • entrypoint란 프로그래밍 언어에서 최상위 코드가 실행되는 시작점 또는 프로그램 진입점을 의미
    • main.py(또는 app.py): FastAPI의 애플리케이션과 Router 설정
    • model.py ML model에 대한 클래스와 함수 정의

poetry

pip 을 대체하는 패키지 매니저, 의존성 해결에 유용하다.

  • 프로젝트 init

    • poertry init 명령 후, 메타 정보들 입력

    대화 형식으로 패키지 설치 가능

    • 패키지 이름 검색 및 선택
    • 패키지 버전 명시
    • Dependency(프로덕션용)
    • Development Dependency(Dev용)
    • 개발 환경마다 필요한 패키지 분리
  • Poetry shell 활성화
    가상환경에 진입하는 것

  • Poetry Install
    pyproject.toml에 저장된 내용에 기반하여 명시된 의존성 라이브러리 설치

  • Poetry Add
    필요한 패키지를 추가하고 싶은 경우 사용
    ex) poetry add pandas

    poetry.lock?
    Writing lock file에서 생성되는 파일
    이 파일이 존재하면 작성하고 있는 프로젝트 의존성과 동일한 의존성을 가질 수 있음
    Github Repository에 꼭 커밋해라


Swagger

  • 만든 API를 클라이언트에서 호울하는 경우,,, 이거 어떻게 Request하는지 매번 따로 알려줄건가..?
    FastAPI에서 Swagger로 자동으로 문서를 만들어줘서
    협업할 때 매우 좋다!
    • API 디자인, 빌드, 문서화, 테스팅에 유용하다!

2. FastAPI 기본 사용법

2.1 URL Parameters

  • Path Parameter 방식
    /users/id/400 이런식
  • Query Parameter 방식
    /users?id=400 이런 식

전자는 식별에 후자는 정렬/필터링에 유용

2.2 Request Body

  • 클라이언트에서 API에 데이터를 보낼 때, Request Body(=Payload)를 사용함
  • 클라이언트 => API: Request Body
  • API의 Response => 클라이언트: Response Body

POST Method의 경우 Request Body에 데이터를 넣어서 보내는데, Body 데이터를 설명하는 Content-Type이란 Header 필드가 존재하고, 어떤 데이터 타입인지 명시해야 한다.

  • 대표적인 컨텐츠 타입
    • application/json: Body가 JSON 형태 (FastAPI는 기본적으로 이걸 사용)
    • application/x-www-form-urlencoded: BODY에 Key, Value 사용 & 구분자 사용
    • text/plain: 단순 txt 파일
    • multipart/form-data: 데이터를 바이너리 데이터로 전송

2.3 Response Body

  • API의 Response => 클라이언트: Response Body
  • Decorator의 response_model 인자로 주입 가능

역할

  • Output Data를 해당 정의에 맞게 변형
  • 데이터 Validation
  • Response에 대한 JSON schema 추가
  • 자동 문서화

2.4 Form

로그인창 같은것들 그런 것들이 다 Form 형태다

  • Form(입력) 형태로 데이터를 받고 싶은 경우
  • Form을 사용하려면 python-multipart를 설치해야 함
    • pip install python-multipart
  • 프론트엔드도 간단히 만들기 위해 jinja2 설치
    • pip install jinja2

2.5 File

  • File 업로드를 하고 싶은 경우
  • File을 사용할 때도 python-multipart 설치해야함.

3. Pydantic 사용법

FastAPI에서 Class 사용할 때 보이던 Pydantic...

Type Hint를 런타임에서 강제해 안전하게 데이터를 핸들링 한다.

기존 validaition 라이브러리보다는 빠르다.

  • 머신러닝 Feature Data Validation으로도 활용 가능.
    ex) Featrue A는 Int 타입이고, 0 ~ 100 사이

파이썬 Class로 검증하기에는... 의미없는 코드가 많이 길어진다... init 부분도 그러하고, return 부분도 길어지고...

그래서 다음에 생각할 수 있는 것이
Dataclass이다.

Dataclass 에서는
from dataclasses import dataclass를 통해서
모듈을 받아오므로
@dataclass를 통해 따로 init method를 작성할 필요가 없고, __post_init__ 매직메서드를 사용하여 해당 파트에서 self.validate를 통해 데이터 검증 가능,

  • 그러나 여전히 self.validate를 구현하긴 해야함.
  • 인스턴스 생성 시점에서 validation을 수행하기 쉬우나, 여전히 validation 로직을 직접 작성해야한다는 문제가 있고,
  • Runtime에서의 type checking을 별도로 지원하지 않는 이슈가 있음

그래서 등장...! Pydantic

Pydantic


사진과 같은 방식으로 매우 간편하게 검증 가능

  • Custom Type에 대한 Validation 또한 쉽게 사용할 수 있다!

Config

  • 앱을 가동하기 위해 사용자가 설정해야 하는 일련의 정보: Config
    • ex) DB 정보
  • 보통 이런 Config들은 하나의 모듈이나 클래스로 관리해서, 사용자가 보기 쉽게 저장

아래는 Config를 관리하는 여러 방식들이다.

  1. Config 관리: 코드 내 상수로 관리
  • 가장 간단하지만, 보안이 박살남
  • 배포 환경에 따라 값을 다르게 줄 수 없음
    • 환경에 따라 DB 주소가 다른데, 배포할 때 코드는 변경이 불가한 바, 정보 변경이 어렵다.
    • 보안 정보가 아닌 값들을 다루는 경우나, 테스트 같은 임시 환경에서나 적합하다.
  1. Config 관리: yaml 등과 같은 파일로 관리
    별도의 파일에서 관리 후, 실행할 때 파일을 지정하여 Config 클래스에 주입하는 방법
  • 배포 환경 별로 파일을 생성 (dev_config.aml, prod_config.yaml)
  • 보안 정보가 여전히 파일에 노출되므로, 배포 환경 별로 파일이 노출되지 않게 관리하는 것이 필요
  1. Config 관리: 환경변수(+Pydantic.BaseSettings)로 관리
    환경변수에 설정 값을 저장한 후에, 코드에서는 환경 변수를 읽어오는 방법
  • Validation 처럼 Pydantic은 BaseSettings를 상속한 클래스에서 Type Hint로 주입된 설정 데이터에 대한 검증을 할 수 있음
  • Field 클래스의 env 인자: 환경 변수를 해당 필드로 오버라이딩
  • yaml, ini 파일들을 추가적으로 만들지 않고, .env 파일들을 환경별로 만들어 두거나, 실행 환경에서 유연하게 오버라이딩
    • 보통 환경 변수는 배포할 때 주입
    • 코드나 파일에 보안 정보가 노출되지 않음

4. FastAPI 확장 기능

Lifespan function

FastAPI 앱을 실행할 때와 종료할 때, 로직을 넣고 싶은 경우
ex) FastAPI 앱이 처음 실행될 때, 머신러닝 모델을 Load하고 앱을 종료할 때 연결해두었던 Database Connection을 정리

  • async def lifespan(add: FastAPI) 정의

    • yield를 기점으로
    • yield 이전 라인은 앱 시작 전
    • yield 이후 라인은 앱 종료 전
  • FastAPI 인스턴스 생성 시 lifespan 파라미터에 위 함수를 전달하면 됨.

    • FastAPI(lifespan=lifespan)

API Router

API 엔드포인트가 점점 많아져서, @app.get @app.post와 같은 코드를 하나의 모듈에서 관리하기가 어려워질 수 있다.

점점 많아지는 API 엔드포인트를 좀 더 효율적으로 관리할 수는 없을까?

  • API Router는 큰 애플리케이션들에서 많이 사용되는 기능으로
  • API Endpoint를 정의한다.
  • APIRouter는 Mini FastAPI로 여러 API를 연결해서 활용한다.
  • 기존에 사용하던 @app.get @app.post를 사용하지 않고, router 파일을 따로 설정하고 app에 import 해서 사용한다.

    위와 같이 다르게 나올 수 있도록 기능들을 만들고 Router로 연결하는 것

Project structure

처음에 봤던 v1버전과 달리 좀 많아졌다.

Error Handler

  • 웹 서버를 안정적으로 운영하기 위해 반드시 필요한 주제
  • 서버의 에러가 어떤 에러이고, 요청한 클라이언트에 해당 정보를 전달하여 대응할 수 있어야 한다.
  • 서버 개발자는 모니터링 도구를 사용하여 Error Log를 수집해야하고
  • 발생하고 있는 오류를 빠르게 수정할 수 있도록 예외 처리를 잘 만들 필요가 있다.

Background Tasks

일부 오래걸리는 API 엔드포인트는 클라이언트에게 비동기(asynchronous)로 처리하도록 하고 싶은 경우

오래 걸리는 작업들을 Background에서 실행할 수 있도록 하는 기능임

  • Online Serving에서 CPU 사용이 많은 작업들을 Background Task로 사용하면, 클라이언트는 작업 완료를 기다리지 않고 즉시 Response를 받아볼 수 있음

    • ex) 특정 작업 이후 이메일 전송하는 TAsk

    • Background Task를 사용하지 않는 작업들은 작업 시간만큼 응답을 기다린다.

    • 그러나 Background Task를 사용하여 구현하면 바로 응답을 주기에 0초가 소요되며 실제 작업은 Background에서 실행된다.

    • 작업 결과물을 조회할 때는 Task를 어딘가에 저장해두고, GET 요청을 통해 Task가 완료됐는지를 확인한다.


5. FastAPI가 어렵다?

  • 빽엔드 원래 어렵다 ㅎㅎ
    • 프로젝트 구조는 어떻게 잡아야 하는가?
    • 객체 지향이 낯설기도 하다..
    • 백엔드 프로그래밍 자체가 처음일 수도 있고
    • 목표가 부재되면 어렵다..!
  • 이럴때 사용하면 좋은게 Cookiecutter 이다.
    • 많은 사람들이 프로젝트 구조에 대해 고민이 많고 그건 당신만의 고민이 아니다.
    • 그래서 프로젝트 구조를 공유하는 템플릿이 바로 Cookie cutter
      • CLI 형태로 프로젝트 생성 과정을 도와주고
      • 회사에서 공통의 프로젝트 구조가 필요할 때 쿠키 커터로 설정할 때도 있다.
      • 개인용 쿠키 커터 템플릿을 만드는 것도 좋은 방법이다!
      • 특히 DS 할거면
        Cookiecutter Data Science 이거 참고해라
      • cooki-cutter-fastapi FastAPI 관련 쿠키커터는 이런것도 있다.

만약 FastaPI 프로젝트가 처음이라면
일단 하나의 파일에 모두 코드를 작성하여 FastAPI에 익숙해지고
그 이후에 다른 프로젝트 구조를 참고해서 코드를 개선해라!
클린 아키텍쳐 류의 책을 보면서 계속 구조를 고민해보자!

  • 절차형 프로그래밍 vs 객체 지향형 프로그래밍의 차이를 이해해보라

  • 객체 지향 프로그래밍은 결국 코드 중복을 최소화하여 재사용성을 증가시키는 이점이 있고

  • 복잡한 로직이 들어갈 수록 빛을 발휘한다.

  • 현재 가지고 있는 코드를 Class로 변경해보고

  • Pydantic Use Case를 탐색해봐라


그리고 빽엔드가 낯선건 당연하고 계속 시도하고 실패하고 고쳐내라
이게 사실 제일 중요하다.

profile
헤매는 만큼 자기 땅이다.

0개의 댓글