[FastAPI] 3. Main & Route

Judy·2023년 7월 12일
1

FastAPI

목록 보기
3/8

저의 오랜 로망은 번역기를 만드는 것입니다 💁🏻‍♀️
그래서 번역 모델에 대한 연구를 주로 해 왔는데
백엔드에 대해 조금 배우고 나니 개발 관점에서 번역 서비스를 만들어 보고 싶어졌어요.

우선 파이썬으로 백엔드를 개발하려니 Django, Flask, FastAPI 중에 고르면 되겠고...
가장 최근에 공개된 FastAPI 만 아주 간단히 해 보았는데 이번 기회에 제대로 복습하려고 합니다.
마침 8월에 간단한 백엔드 강의를 할 일이 생겼고, 갑작스레 백엔드 스터디를 하게 되었네요. 😉

요약하면... 이번 공부의 목표는 '구글 번역 클론코딩' 토이 프로젝트입니다!

FastAPI 에 대한 아주 간단한 요약은 예전에 제가 아주 작은 프로젝트를 할 때 작성한 포스팅을 참고해 주세요.
[FastAPI] 1. Summary
(이번 토이 프로젝트는 file tree 가 다릅니다!)

Why FastAPI?

FastAPI 는 아직 ver 1.0 도 나오지 않은(!) 아주 따끈따끈한 백엔드 프레임워크인데요,
공식문서에서는 FastAPI 의 장점을 이렇게 말하고 있어요.

Web framework for developing RESTful APIs in Python

  • Pydantic 및 유형 힌트를 기반으로 데이터를 검증, 직렬화 및 역직렬화하고 OpenAPI 문서를 자동으로 생성합니다.
    • 경험해 보니 pydantic 은 파이썬의 타입 어노테이션(type annotation) 을 사용해서 데이터를 검증하는 파이썬 라이브러리로, 미리 개발자가 정의한 데이터만 전송되도록 request body 를 검증할 수 있습니다. 이로써 요청 데이터가 적절한지 확인하고 악의적인 공격의 위험을 줄일 수 있지요.
      예를 들어 ID는 string 으로 받아야 하는데, int 와 같은 다른 자료형이라면 이를 미리 정의한 pydantic 모델을 이용해 자료형이 틀렸음을 검증할 수 있어요.

The key features are:

  • 빠름: (Starlette과 Pydantic 덕분에) NodeJS 및 Go와 대등할 정도로 매우 높은 성능.
    사용 가능한 가장 빠른 파이썬 프레임워크 중 하나.
    • 경험상 python 으로 작성한 코드는 javascript 로 작성한 코드에 비해 느리다는 것을 확연히 체감할 수 있었는데, FastAPI 는 속도의 차이를 느끼기 어려울 만큼 빨랐습니다!
  • 빠른 코드 작성: 약 200%에서 300%까지 기능 개발 속도 증가. *
  • 적은 버그: 사람(개발자)에 의한 에러 약 40% 감소. *
  • 직관적: 훌륭한 편집기 지원. 모든 곳에서 . 적은 디버깅 시간. 자동완성
  • 쉬움: 쉽게 사용하고 배우도록 설계. 적은 문서 읽기 시간.
  • 짧음: 코드 중복 최소화. 각 매개변수 선언의 여러 기능. 적은 버그.
  • 견고함: 준비된 프로덕션 용 코드를 얻으십시오. 자동 대화형 문서와 함께.
  • 표준 기반: API에 대한 (완전히 호환되는) 개방형 표준 기반: OpenAPI (이전에 Swagger로 알려졌던) 및 JSON 스키마.
    • 많은 API 를 개발하다 보면 하나하나 문서화하는 것도 일인데, FastAPI 는 자동으로 문서화를 해 줍니다!
      서버 url 맨 뒤에 docs 만 붙여 주면 자동으로 문서화된 API 를 조회할 수 있고, 쿼리를 보내고 응답값도 확인할 수 있어서 매우 편리했어요.

개발환경

저는 AI researcher 시절에는 conda 가상환경 + pip 를 이용했는데
이번에는 pip 와 가상환경 모두를 지원하고 디펜던시 관리에 용이한 poetry 를 이용하겠습니다.
poetry 참고 포스팅

main & routes

앞으로 약 열흘간 하루에 1개씩 기능을 구현하고 포스팅할 예정으로,
오늘은 entry point 역할을 하는 main 부터 시작하고, 웹 서버의 첫번째 관문인 route 까지 설명합니다.

1. FastAPI 인스턴스 생성

FastAPI 를 이용하기 위해 새 인스턴스를 생성합니다.

from fastapi import FastAPI

# Create FastAPI Instance
# default
app = FastAPI()
# title, description 을 추가할 수도 있어요 :)
app = FastAPI(title="NMT-API",
              description="Backend API for NMT")

2. Route 생성

라우팅?

클라이언트가 서버로 보내는 HTTP 요청을 처리하는 프로세스.
HTTP 요청이 지정한 라우트로 전송되면 미리 정의된 로직이 해당 요청을 처리해서 응답.

app 변수(라고 책에서 설명하지만 저는 인스턴스가 맞는 것 같아요) 에 FastAPI 를 초기화해서 Route를 생성합니다.
우선 파이썬 데코레이터(@)를 사용해 처리 유형을 정의하고, Route 가 호출됐을 때 실행될 함수를 작성합니다.

# <server_url>/ 로 접속했을 때. 즉 서버에 맨 처음 접속하면 '{"message": "Hello World"}' 를 보여준다
@app.get("/")
async def root():
    return {"message": "Hello World"}

여기까지만 작성해도 웹 서버가 완성됩니다!
실행은 uvicorn 서버를 이용하는데, 쉽게 말해 FastAPI 에서 제공하는 가벼운 웹 서버이고
배포에 별도의 준비가 필요 없어서 간단한 걸 개발해서 웹 서버를 띄워보기에 좋더라고요.

개발한 웹 서버를 시작해 볼까요?

uvicorn <파일명>:app --port <port number> --reload
uvicorn main:app --port 8000 --reload

--reload 옵션을 주면 파일이 변경될 때마다 자동으로 서버를 재시작해줘서 매우 편리했어요.

3. Routes

2번까지는 아주 간단한 웹 서버 예제였고,
이번에는 <server_url>/translate 형태로 접근할 수 있도록 다중 route 를 만들어 보겠습니다.

앞에서 root route 를 만들었는데, 사실 route 는 여러개를 사용할 수 있거든요?
다중 라우팅을 위한 경로 처리 클래스인 APIRouter 를 이용합니다.
이 클래스를 이용하면 애플리케이션 라우팅과 로직을 독립적으로 구성하고 모듈화할 수 있습니다.

저는 라우트가 여러 개 생길 것으로 예상하고 file tree 를 다음과 같이 만들었습니다.

nmt_backend
├── app
│   ├── routes
│   │   └── translate.py
└── main.py

라우트 파일인 translate.py 는 이렇게 작성했습니다.

  • APIRouter 를 이용해 라우팅 메서드 생성
  • 라우팅 메서드 호출 시 수행될 함수 작성
    • 저는 Google Translate 와 똑같이 query parameter 로 번역에 필요한 인자를 받겠습니다.
    • src : source, 입력 문장의 언어
    • tgt : target, 번역할 문장의 언어
    • text : 번역할 문장
# app/routes/translate.py
from fastapi import APIRouter
from app.service import translate

# Create routing method
router = APIRouter()

# Query parameter
# /?src=ko&tgt=en&st=테스트 문장

@router.post("/")
async def translate(src: str = "ko", tgt: str = "en", text: str = "삶은 다이아몬드처럼 빛나") -> dict:
    mt = await translate.translate(src, tgt, text)
    # return mt
    # 임시로 지정된 응답을 반환하도록 했습니다 (아직 번역 모델을 서빙하지 않아서요...)
    dic = {"translated": "good!"}
    return dic

그런데 uvicorn 은 APIRouter() 인스턴스를 사용해서 애플리케이션을 실행할 수가 없어요.
다시 말해, APIRouter() 클래스를 사용해 정의한 라우터를 FastAPI() 인스턴스에 추가해야 외부에서 접근할 수 있어요.
main.py 에서 include_router() 메서드를 사용해서 내가 만든 라우터를 FastAPI 인스턴스(=app) 에 추가합니다.

요약 : 외부에서 라우터에 접근하기 위해 include_router() 사용.
include_router() 메소드는 APIRouter 클래스로 정의한 라우트를 메인 애플리케이션의 인스턴스로 추가하여 전체 애플리케이션에서 라우트를 사용할 수 있도록 함.

from app.routes.translate import router as translate_router

# Add translate router to FastAPI instance using 'include_router' method
# To access from outside
app.include_router(translate_router, prefix="/translate")

4. CORS (Cross-Origin Resource Sharing)

현재의 웹 브라우저는 보안상의 이유로 서로 다른 출처의 http 통신을 막도록 기본적으로 세팅되어 있습니다. 동일한 출처의 주체끼리만 서로 통신할 수 있도록 하는 이 SOP(Same Origin Policy) 정책은 보안성 향상을 위한 기본이라 이해할 수 있습니다.

하지만 현실적으로 백엔드와 프론트 서버가 서로 다른 도메인에서 운용되는 현재의 3세대 웹 서비스 환경에서, 동일한 출처에서만 리소스를 주고 받을 수 없는 실정입니다. 따라서 이러한 SOP 정책을 올바르게 의도한 요청에 한해서 다소 완화시켜 서로간 통신을 가능케 해야 합니다.

이는 별도의 CORS 설정을 통해서 서로 다른 두개의 origin/domain 끼리의 데이터를 주고 받게 하기 위한 설정하여 이루어지며, 만일 해당 과정을 생략한다면 CORS 정책 위반을 이유로 웹 브라우저 차원에서 서버 통신을 막습니다

참고 블로그

FastAPI 에서는 보통 main 에 이 cors 설정을 추가합니다.
우선 CORS middleware 를 허용할 도메인을 추가합니다.

#app/main.py
# Allows CORS middleware
# example: "http://localhost"
# * : all
origins = ["*"]

와일드카드

  • 모든 출처를 허용하기 위해 목록을 "*" ("와일드카드")로 선언할 수 있음
  • 한계
    • 특정한 유형의 통신만을 허용하며, 쿠키 및 액세스 토큰과 사용되는 인증 헤더(Authoriztion header) 등이 포함된 경우와 같이 자격 증명(credentials)이 포함된 통신은 허용되지 않음
    • 따라서 모든 작업을 의도한대로 실행하기 위해 허용되는 출처를 명시적으로 지정하는 것 추천.

이어서 CORSMiddleware 를 추가합니다.

CORSMiddleware 사용

  • CORSMiddleware 임포트.
  • 허용되는 출처(문자열 형식)의 리스트 생성.
  • FastAPI 응용 프로그램에 "미들웨어(middleware)"로 추가.
# Setting Middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"]
)

Tip) https://hides.kr/1107 에서 설명하길,
깃헙 이슈에 따르면 해당 메소드의 경우 호출할 때 마다 미들웨어를 re-initialize하는 이슈가 있다고 합니다.
따라서 Middleware클래스를 활용하여 넣어주는 방식으로 변경하는 게 좋다고 하네요.

5. Run

uvicorn main:app --port 8000 --reload

6. Docs

저는 일단 라우트에서 이용하는 service 로직까지 완성한 상태라
앞서 설명한 FastAPI 의 자동 문서화를 간단히 소개하며 첫 스터디 글을 마무리하겠습니다.
url 맨 뒤에 docs 만 붙이면 자동으로 swagger foramt 에 맞게 문서화된 API 들을 볼 수 있어요!
API 들을 조회할 수도 있고, try it out 을 이용해 서버에 쿼리를 보내 테스트를 할 수도 있어요.

Reference

FastAPI 공식 문서
https://fastapi.tiangolo.com/ko/
FastAPI를 사용한 파이썬 웹 개발
https://www.yes24.com/Product/Goods/117817320

p.s) 내 스터디메이트 화이팅.... 나 자신도 화이팅... 🙌

profile
NLP Researcher

0개의 댓글