Fast API

이준수·2021년 12월 16일
1

Back-End Programming


Server의 형태

  • 모놀리식 아키텍처: 하나의 큰 서버로 구성되어 모든 기능(서비스, 머신러닝 등)을 하나의 서버에서 처리하는 방식
    버전이 변경될 때마다 서버가 통째로 Build되어야 해서 배포 속도가 느리다.
  • 마이크로서비스 아키텍처: 여러개의 개별 서버로 구성하여 기능을 담당하는 서버로 생성하고 서로 통신하도록 하는 구조

REST API

REST(Representational State Transfer)의 약자로 자원을 이름으로 구분하여 해당 자원의 상태를 주고받는 모든 것을 의미한다.

1) HTTP URI를 통해 자원을 명시하고, 2) HTTP Method를 통해 해당 자원에 대한 CRUD Operation을 적용하는 것을 의미한다.

웹에서의 통신은 주로 정보를 주고 받을 때 지켜야 하는 통신 프로토콜인 HTTP(Hyper Text Transfer Protocol)를 사용하며 기본적으로 80번 포트를 사용하여 서버와 클라이언트가 통신하게 된다.

URI란?

Uniform Resource Identifier로 인터넷 상의 자원을 식별하기 위한 문자열의 구성
URI는 인터넷 상에서 자원의 위치를 의미하는 URL을 포함하게 되며, URI가 더 포괄적인 범위이다.

CRUD Operation이란?

CRUD는 대부분의 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능인 Create, Read, Update, Delete를 묶어서 일컫는 말이다.

REST에서의 CRUD Operation 동작은 HTTP Method의 형식으로 표현되는데 Create는 POST, Read는 GET, Update는 PUT, PATCH, Delete은 DELETE이다.

  • GET vs POST

Status Code

클라이언트 요청에 따라 서버가 어떻게 반응하는지를 알려주는 숫자 Code이다.
ex) 404 Not Found, 502 Bad Gate와 같은 에러

Synchronize vs Asynchronize

  • Sync: 서버에 요청을 보냈을 때, 실시간으로 응답이 돌아와야 다음 동작을 수행할 수 있는 Task로, 클라이언트-서버 통신을 예로 들 수 있다.
    클라이언트가 정보를 요청하면 서버로부터 응답이 돌아오기 전 까진 클라이언트는 대기상태에 들어가게 된다.
  • Async: 요청을 보낼 때, 응답 상태와 상관없이 다음 동작을 수행할 수 있는 Task로, 메일 시스템을 생각하면 쉽다.
    두 유저 사이에 메일이 오고 가는 경우, 다른 유저가 응답할 때까지 대기할 필요 없이 다른 작업을 수행할 수 있다.

Fast API


Fast API의 특징

FastAPI의 장점

  • Flask보다 간결한 Router 문법 (FastAPI는 Flask로부터 발전을 시켰다)
  • Asynchronous(비동기) 지원
  • Built-in API Documentation(Swagger)
  • Pydantic을 이용한 Serialization 및 Validation

FastAPI의 단점

  • 아직까지는 Flask의 유저가 더 많음
  • ORM 등 Database와 관련된 라이브러리가 적음
    ⇒ FastAPI 공식사이트에 DB관련 사용법이 나와있음

FastAPI 환경설정


FastAPI 구조 (기초적인 구조)

  • main.py: 어플리케이션을 실행할 수 있는 Entrypoint 역할을 하는 모듈
    ⇒ 최상위 코드가 실행되는 시작점 또는 프로그램 진입점을 뜻함
  • main.py 또는 app.py: Flask API의 어플리케이션과 Router 설정
  • model.py: ML model에 대한 클래스와 함수 정의

Poetry를 사용한 Virtual env 관리

자세한 내용은 PDF 참고

FastAPI 기초지식


Path Parameter vs Query Parameter

Web에서 Get Method를 사용해 데이터를 전송하는 방식은 2가지로 나뉜다.
ex) ID가 402인 사용자 정보를 가져오고 싶은 경우에

  • Path Parameter: /users/402, 서버에 402라는 값을 전달하고 변수로 사용
  • Query Parameter: /users?id=402, API 뒤에 입력 데이터를 Query 형식으로 전달하는 방법
    Query String은 Key, Value 쌍으로 이루어지며 '&'를 사용하여 여러 쌍의 Query를 전달할 수 있다.
    ex) https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=0&ie=utf8&query=광진구
  • Resource를 식별해야 하는 경우에는 Path Parameter가 더 적합하고 정렬, 필터링을 해야 하는 경우에는 Query Parameter 더 적합하다.

Path Paramter in FastAPI

FastAPI는 데코레이터로 Get과 Post를 구분하여 받을 수가 있다.
GET Method의 인자로 있는 {user_id}가 함수의 값으로 주입된다.

from fastapi import FastAPI
import uvicorn

app = FastAPI()

@app.get("users/{user_id}")
def get_user(user_id):
    return {"user_id": user_id}

if __name__ == '__main__':
    uvicorn.run(app, host='0.0.0.0', port=8000)

Query Parameter in FastAPI

Path Parameter 방식과는 달리 get URL에 Paramter를 넘겨주지 않아도 된다.
하지만, 원하는 Query를 URL뒤에 '?'와 '&'로 연결하여 요청할 수 있다.

또한, 없는 데이터의 경우는 자동적으로 Empty List를 반환해주기 때문에, 추가적인 Error Handling이 필요한 경우도 있다.

from fastapi import FastAPI
import uvicorn

app = FastAPI()

fake_db = [{'item_name': 'Foo'}, {'item_name': 'Bar'}, {'item_name': 'Baz'}]

@app.get("/items/")
def read_item(skip: int=0, limit: int=10):
    return fake_db[skip: skip + limit]

if __name__ == '__main__':
    uvicorn.run(app, host='0.0.0.0', port=8000)

Optional Parameter

특정 파라미터는 Optional로 선언하고 싶은 경우에는 Typing 모듈의 Optional을 사용하여 지정해준다.

from typing import Optional
from fastapi import FastAPI
import uvicorn

@app.get('/items/{item_id}')
def read_item(item_id: str, q: Optional[str] = None):
    if q:
        return {'item_id': item_id, 'q': q}
    return {'item_id': item_id}

if __name__ == '__main__':
    uvicorn.run(app, host='0.0.0.0', port=8000)

Request Body

클라이언트가 API에 데이터를 보낼 때는 Request Body를 사용하며, 이 때는 POST Method를 사용한다.
GET Method는 Request Header(URL)로 데이터를 전송하고 POST Method는 Request Body로 데이터를 전송하게된다.

from typing import Optional
from fastapi import FastAPI
import uvicorn

from pydantic import BaseModel

class Item(BaseModel):
    name:str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None

app = FastAPI()

@app.post("/items/")
def create_item(item: Item):
    return item

if __name__ == '__main__':
    uvicorn.run(app, host='0.0.0.0', port=8000)
  • pydantic으로 Request Body의 데이터를 정의하는 Class 생성
  • POST Method로 정의된 함수의 인자에 Type Hinting을 선언해줄 경우, Request Body 데이터의 타입이 Type Hinting과 일치하는지 Validation 진행

Response Body

POST Method에 response_model을 데코레이터에 인자로 Class를 넘겨주면 자동으로 Class에 맞게 Response를 실행하게 된다.
즉, API에서 Client로 전송되는 Output Data를 선언한 Class에 맞게 변형하고, 데이터에 대한 Validation을 진행한 후 Json Format으로 변형하여 Client로 보내주게된다.

아래 코드를 실행할 경우 Request Data는 name, description, price, tax 4가지를 Client에서 API로 요청을 하게되고, API에서 Client로 전송되는 Response Data는 name, price, tax가 응답으로 전송된다.

from typing import Optional
from fastapi import FastAPI
import uvicorn

from pydamic import BaseModel

class ItemIn(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None

class ItemOut(BaseModel):
    name: str
    price: float
    tax: Optional[float] = None

app = FastAPI()

@app.post('/items/', response_model=ItemOut)
def create_item(item: ItemIn):
    return item

if __name__ == '__main__':
    uvicorn.run(app, host='0.0.0.0', port=8000)

Pydantic


Pydantic Library

FastAPI에서 Class를 선언할 때 사용하는 라이브러리로, 요청/응답 시에 Data의 Type이 올바른지 Validation과 Settings을 관리해주는 라이브러리이다.

Type Hinting을 런타임에서 강제하여 안전하게 데이터 핸들링을 처리
파이썬 기본 타입(String, Int 등) + Typing 라이브러리의 List, Dict, Tuple에 대한 Validation 지원

  1. Pydantic Validation
    밑바닥부터 Python Class로 Validation을 진행할 경우 init을 통해 변수를 설정해주고, If문을 활용하여 예외처리를 설정해줘야하기 때문에 코드가 길어진다.
    @dataclass Decorater를 사용하여 설정하게 되면 init을 사용하지 않아도 되고, Validation을 if문을 사용하지 않고 내장 메소드를 사용할 수 있지만, 여전히 Validation을 위한 코드는 필요하다
    하지만 Pydantic Validation은 BaseModel을 상속하고 데이터만 명시해주면 자동으로 init과 Validation을 진행해준다.
  2. Pydantic Config
profile
Beginner_of_AI_Engineer

0개의 댓글