FastAPI 기초

홍찬우·2023년 7월 30일

FastAPI 기본 지식

Path Parameter & Query Parameter

  • 웹에서 GET Method를 사용해 데이터 전송 가능

  • ID가 402인 사용자 정보를 갖고오고 싶으면?

    • Path Parameter: /users/402

      • 서버에 402라는 값을 전달하고 변수로 사용
    • Query Parameter: /users?id=402

      • API 뒤에 입력 데이터를 함께 제공

      • key-value 쌍으로 이루어지며 &로 연결

    • 만약 402 유저가 없다면?

      • Path Parameter: 해당 경로에 존재하는 내용이 없으므로 404 Error
        → Resource를 식별해야 하는 경우 적합
      • Query Parameter: 데이터가 없는 경우 빈 리스트로 나옴
        → 정렬, 필터링을 해야하는 경우 적합

Path Parameter

  • 유저 정보에 접근하는 API 만들기

    from fastapi import FastAPI
    import uvicorn
    
    # FastAPI 객체 생성
    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)
  • @app.get("/users/{user_id}") 로 접근

  • GET Method의 인자로 있는 {user_id} 가 함수의 값으로 주입

  • localhost:8000/users/1로 접근하면, {”user_id”: 1} 리턴

  • 터미널에서 Request 로그가 남음


Query Parameter

from fastapi import FastAPI
import uvicorn

# FastAPI 객체 생성
app = FastAPI()

# 가짜 데이터베이스 생성
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]

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

if __name__ == '__main__':
		uvicorn.run(app, host='0.0.0.0', port=8000)
  • localhost:8080/itmes/ 로 접근 시, fake_items_db[0:10] 결과 출력

  • localhost:8080/itmes?start=0&limit=1 로 접근 시, fake_itmes_db[0:1] 결과 출력

    • 함수에 사용되는 인자를 url에 포함시켜 넘김
  • 만약 start=20, limit=10이면 아무것도 없으므로 출력되지 않음


Optional Parameter

  • 특정 파라미터는 선택적으로 하고 싶은 경우
from fastapi import FastAPI
import uvicorn
from typing import Optional

# FastAPI 객체 생성
app = FastAPI()

@app.get("/items/{item_id}")
def read_item(item_id: str, q: Optinal[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)
  • localhost:8000/items/1 로 접근하면 q가 없으므로 {item_id: 1} 반환

  • localhost:8000/items/1?q=boostcamp 로 접근하면 q가 존재하므로
    {”item_id”: 1, “q”: boostcamp} 반환


Request Body

  • 클라이언트에서 API에 데이터를 보낼 때, Request Body 사용

    • 클라이언트 → API : Request Body

    • API → 클라이언트 : Response Body

  • Request Body에 데이터가 항상 포함되어야 하는 것은 아님

  • Request Body에 데이터를 보내고 싶다면 POST Method 사용

    • GET Method는 URL, Request Header로 데이터 전달
  • POST Method는 Request Body에 데이터 넣어 보냄

  • Body의 데이터를 설명하는 Content-Type이란 Header 필드가 존재하고, 어떤 데이터 타입인지 명시해야 함


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의 BaseModel로 Request Body 정의
  • Item class가 request body

  • 웹 서버 실행 후 localhost:8000/docs로 이동
    • Swagger
  • Schemas의 Item 클릭

  • pydantic으로 정의한 내용 볼 수 있음
  • description, tax는 Optional로 설정해 *표시가 없음

  • POST 쪽을 클릭해도 해당 내용 확인 가능
  • Try it out 클릭
{
		"name": "string",
		"description": "string",
		"price": 0,
		"tax": 0
}
  • 기본 설정 상태이며, execute을 클릭하게 되면 curl 명령어와 Response를 볼 수 있음

  • -X는 GET, POST와 같은 Method

  • -H는 Header

  • -d는 data

  • Response body로 Response data 확인 가능

  • 만일 float type인 tax에 string을 넣어서 execute 하면?

    tax가 float이 아니라는 메세지 출력

    data validation check


Response Body

  • Request와 Response 데이터가 다를 수 있음
from typing import Optional
from fastapi import FastAPI
import uvicorn
from pydantic import BaseModel

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

# Response
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)
  • @app.post("/items/", response_model=ItemOut)

    • decorator 인자에 response_model 인자로 주입 가능

  • Response Body에 description 없어진 것 확인 가능

Form

  • Form(입력) 형태로 데이터를 받고 싶은 경우 사용

  • python-multipart 설치해야 함

    • pip install python-multipart
  • 간단한 프론트를 위해 Jinja2 이용

    • pip install Jinja2

from fastapi import FastAPI, Form, Request
import uvicorn

app = FastAPI()

@app.post("/login/")
def login(username: str = Form(...), password: str = Form(...)):
    return {"username": username}

if __name__ == '__main__':
    uvicorn.run(app, host="0.0.0.0", port=8000)
  • def login(username: str = Form(...), password: str = Form(...)):

    • username, password는 string인데 Form 형태임을 명시

    • 포맷에 입력된 값을 가져와서 실행

  • 해당 코드는 Method not allowed 에러 발생

    • app.post(”/login/”) 은 login url로 요청하는 것이므로 GET Method

    • 하지만 현재 POST Method이므로 에러 발생


from fastapi import FastAPI, Form, Request
from fastapi.templating import Jinja2Templates
import uvicorn

app = FastAPI()
templates = Jinja2Templates(directory='./')

@app.get("/login/")
def get_login_form(request: Request):
    return templates.TemplateResponse('login_form.html', context={'request': request})

@app.post("/login/")
def login(username: str = Form(...), password: str = Form(...)):
    return {"username": username}

if __name__ == '__main__':
    uvicorn.run(app, host="0.0.0.0", port=8000)
  • 정상적인 작동을 위해 app.get(”/login/”) 으로 메서드 생성

  • login url로 접속하면 저장된 html 템플릿을 읽고, post 요청까지 정상 작동

  • Form(...)

    • Python ellipsis

      • Fast API에서 필수 요소를 의미

      • 존재해야만 실행


File

  • 파일을 업로드하고 싶은 경우 사용

  • UploadFile 임포트

  • HTML에서 action으로 넘겨 사용







※ 모든 이미지 및 코드 출처는 네이버 커넥트재단 부스트캠프 AI Tech 5기입니다. ※

profile
AI-Kid

0개의 댓글