FastAPI 시작하기
Deep Learning Model 을 Back-end Server에 배포하기 위해 FastAPI를 알아보기 시작했다.
FastAPI란?
FastAPI는 공식 홈페이지에는 이렇게 적혀있다.
"현대적이고 빠르며 (고성능), Python 표준 타입에 기초한 Python 3.6+의 API를 Build 하기 위한 Web Framework"
즉, FastAPI 라는 것은 Python 3.6+ version 에서 API를 Bulid 하기 위한 web framework 라는 것이고 빠르다는 것이 주요 장점이라고 할 수 있다.
공식 홈페이지에 나온 주요 특징들을 보면 이렇다.
- 빠름 : Nodejs 및 Go 와 대등할 정도로 매우 높은 성능
- 빠른 코드 작성 : 개발 속도 증가
- 적은 버그
- 직관적
- 쉽고 짧은 코드
- 표준 기반 : OpenAPI 및 JSON schema
이러한 특징 때문에 Python 환경에서 API를 구현할 때 FastAPI를 활용하는 이유이다.
FastAPI 설치 및 간단한 Example
설치는 별로 어렵지 않으나 Python 3.6 버전 이상만 호환이 된다는 것을 유의하여야 한다.
pip install "fastapi[all]"
위 명령어를 사용하면 FastAPI 설치에 필요한 모든 라이브러리까지 함께 설치되는데, 만일 "pip install fastapi" 로 설치한다면 uvicorn과 같은 의존성이 걸리는 라이브러리를 따로 설치해주어야 한다.
Python Uvicorn 이란 무엇인가를 설명하기 전에, ASGI 라는 의미를 알아야 한다. 이것은 CGI -> WSGI -> ASGI를 차례대로 알아야 한다.
CGI
WAS (Web Application Server) 에 동적인 요청이 들어왔을 때 그 요청을 처리하고 응답해주어야 한다.
이 때, 서버마다 그리고 언어마다 이 형태가 다르게 된다면 곤란해지기 때문에 공통 규약 (Interface)을 만들어야 한다.
이러한 Interface 를 Common Gateway Interface (CGI) 라고 한다.
WSGI
Web Server Gateway Interface의 약자로, Python에서 사용되는 개념이다. CGI의 단점 (요청이 들어오면 새로운 프로세스를 생성하는 등)을 보완한 방법으로, callable object 등으로 요청을 처리한다. 역할마다 WSGI application, WSGI Middleware 등으로 세부적으로 나뉘어 있기도 하다.
ASGI
WSGI는 비동기 처리에 문제가 있다. ASGI는 이를 개선하기 위해 만들어진 비동기 서버 게이트웨이 인터페이스 (Asynchronous Server Gateway Interface) 로, Uvicorn은 바로 이 ASGI에서 활용된다.
즉, Uvicorn은 ASGI Web Application이며, 동기 또는 비동기적으로 들어오는 요청에 대해 빠르게 처리하는 능력을 가진다.
FastAPI 기본 예제 - FastAPI Get 구성 후 실행
먼저 파이썬 실행 파일을 하나 만들고 다음과 같이 코드를 작성한다.
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
# async def root():
def root():
return {"message" : "Hello World"}
@app.get("/home")
def home():
return {"message" : "home"}
이와 같이 구성하면 API server에 구성하는 path 경로에 따라 message가 return이 되는 것을 확인할 수 있음. 아래와 같이 fastAPI File을 실행한다.
uvicorn main:app --reload
이 파이썬 파일 이름이 main 이므로 main:app을 uvicorn 으로 실행하겠다는 의미를 지님. reload 는 update 등이 일어났을 때 reload 하겠다는 의미이다.
이렇게 실행하면 fastapi 서버가 실행되는 것이다. 해당 로그를 보면 "Uvicorn running on "http://127.0.0.1:8000 이라고 나와있는데, 해당 링크로 들어가보면 아래와 같은 화면이 나온다.
위 코드에서 경로를 두 개를 두었다.
- / 경로 : 127.0.0.0:8000
- /home 경로 : 127.0.0.0:8000/home
FastAPI async def & def란?
fastapi 에서 함수를 async (비동기) 로 두면 비동기로 동작이 된다. 그렇다면 def로 둬도 비동기가 안되지 않을까 했지만 그렇지 않다.
다만, await을 호출하도록 가이드를 두는 곳에서는 async 표시를 하라고 되어있다.
FastAPI 기본 예제 - FastAPI get에 값 넘겨주기
from fastapi import FastAPI
app = FastAPI()
@app.get("/home/{name}")
def read_name(name:str):
return {"name" : name}
@app.get("/home_err/{home}")
def read_name_err(name:int):
return {"name" : name}
/home 이라는 경로에 {name} 이라는 값을 두어서 /home/값의 형태를 받을 수 있도록 하였음.
int 형태로 받는 쪽의 함수는 나중에 error 처리를 할 수 있도록 해주는 함수임.
chan 이라는 값을 넘겨주면 return 형태로 값이 넘어오는 것을 알 수 있다.
FastAPI Swagger UI 확인
FastAPI 주요 특징 중 하나는 Swagger UI를 지원해주는 것이다. 이것은 표준 API를 지원해주기에 가능한 것이다. Swagger UI를 통해 API가 구성된 것을 한 눈에 확인할 수 있음
127.0.0.0.0:8000/docs
위 url로 들어가게 되면 docs를 확인할 수 있음.
각각의 API 값을 확장해서 자세한 정보를 확인할 수도 있으며, 테스트로 값을 넣어서 그 결과값을 확인해볼 수도 있음
FastAPI 기본 예제 응용
from enum import Enum
from fastapi import FastAPI
class ModelName(str, Enum):
alexnet = "alexnet"
lenet = "lenet"
resnet = "resnet"
app = FastAPI()
@app.get("/models/{model_name}")
async def get_model(model_name : ModelName):
if model_name is ModelName.alexnet:
return {"model_name" : model_name, "message" : "Deep Learning FTW!"}
if model_name.value == "lenet":
return {"model_name" : model_name, "message" : "LeCNN all the images"}
return {"model_name" : model_name, "message" : "Have some Residuals"}
get 으로 /models/{model_name} 을 받았을 때 model_name에 따라 return 값이 다르게 나오도록 하는 코드이다.
이 때 model_name은 ModelName 이라는 class로 지정된 값을 받도록 설정하였는데, 이것에 대한 활용 방법은 앞으로의 포스팅에서 차차 설명할 예정이다. 일단 FastAPI 에서 이렇게 input을 관리할 수 있다는 것을 보여주었다.
만약 model_name 이 alexnet 이라면 Deep Learning FTW 라는 메시지가 반환되고 나머지의 경우 또한 코드와 같다는 것을 보여준다.
위와 같이 확인 가능하다.
docs 에서도 아래와 같이 확인해볼 수 있다.