본문 바로가기
개발관련/FastAPI(BE)

FastAPI - (2) HTTP메소드, URL 매개변수

by yjoo_ 2023. 10. 7.
 

경로 매개변수 - FastAPI

FastAPI framework, high performance, easy to learn, fast to code, ready for production

fastapi.tiangolo.com


FastAPI 공식 문서의 튜토리얼을 따라가면서 정리해보도록 하겠다.

 

좀 더 정확한 내용이 보고싶다면 공식 docs를 읽어보는게 좋다.

 

먼저 지난번에 사용한 코드를 그대로 사용하여 시작한다

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def hello():
    return {"message": "Hello World!"}

# python으로 실행된 파일 명이 main일 때
if __name__ == "__main__":
    import uvicorn
    # main:app main.py의 app 오브젝트 즉 FastAPI
    # 0.0.0.0 아이피 자기 자신에 대한 모든 IP라는 뜻 따라서 자기자신
    # port는 8000번
    # reload=True 코드 변경시 자동으로 서버를 리로드함
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
python main.py

코드에 대한 자세한 설명은 매번 주석으로 작성하도록 하겠다.

 

터미널에 명령어를 사용해 서버를 실행한다.

그리고 다음 링크로 접속해보자. http://localhost:8000/docs

Swagger를 통한 자동 문서화

우리가 만든 API에 대한 문서가 자동으로 만들어진다.

 

실제로 이 페이지에서 API에 대한 요청도 날려볼 수 있다. Try it out 버튼을 눌러보자.

 

자동 문서는 이것 말고도 하나 더 있다.

http://localhost:8000/redoc 에도 접속해보자

 

그리고 다운로드 버튼을 누르고 받아진 파일을 열어보면...

이렇게 깔끔하게 정리된 API 명세서를 볼 수 있다.

 

이것만 보고도 어떤 경로에 무슨 데이터를 보내면 어떤 답이 오는지 쉽게 유추해낼 수 있다.

 

이것을 프론트엔드 개발자에게 넘겨주면 API를 호출하는 코드를 작성하는데 큰 도움이 될 수 있다.

 

이제 코드를 작성해보자.

 

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def hello():
    return {"message": "Hello World!"}

@app.get("/items/{item_id}")
async def read_item(item_id):
    return {"item_id": item_id}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

read_item이라는 함수를 새롭게 추가했다.

이 함수로 접근하는 방법은 localhost:8000/items/{item_id}인데

 

먼저 엔드포인트의 개념부터 잡고가도록 하자

 

엔드포인트란 URL 경로를 의미한다. 라우트라고도 불리는데, "localhost:8000/"의 뒷 부분을 의미한다.

 

첫번째 "/"의 뒷 부분인 "items/{item_id}"가 바로 해당 함수의 엔드포인트다.

 

해당 URL에 접근하게 되면 해당 함수가 실행되는데, 이것을 요청(request)라고 한다.

HTTP 메서드

프론트엔드에서 백엔드로 요청(request)를 보낼 때 HTTP 메서드를 통해 요청을 구분하여 보낼 수도 있다.

 

즉 동일한 URL에도 HTTP 메서드만 다르게 보낸다면, 다른 동작이 가능한 것이다.

 

HTTP 메서드의 종류에는 대표적으로 4가지가 있다.

 

  1. GET - 데이터를 표시할 때 사용, 일반적인 URL 접근시 GET이 사용된다.
  2. POST - 데이터를 생성할 때 사용, 이 때 데이터가 담긴 그릇이 숨겨져서 보내진다 Body라고 부른다.
    Form태그로 보내는게 일반적이다.
  3. PUT - 데이터를 수정할 때 사용, 마찬가지로 Body를 가지고 있다.
    이 역시 Form태그를 사용하여 보낸다.
  4. DELETE - 데이터를 삭제할 때 사용

우리의 코드 중 @(데코레이터) 부분을 살펴보자

# items/{item_id}로 GET 요청이 들어올 경우
@app.get("/items/{item_id}")
async def read_item(item_id):
    return {"item_id": item_id}

 

일반적인 URL 접근은 기본적으로 GET 요청을 갖는다.

 

따라서 해당페이지에 접근하면  "item_id": `URL에 입력한 값`을 갖게된다.

 

1을 입력했으니 return되어 돌아온다.
주영민은 천재다!

이런식으로 엔드포인트를 중괄호에 변수 명을 적어주면, 매개변수로 받을 수 있게 된다.

 

이것을 URL Parameter라고 부른다.

 

경로 매개변수

우리는 URL에 우리가 직접 입력한 값을 사용해 return하는 함수를 만들었다.

 

하지만 Parameter값을 어떻게 넣든간에 무조건 return이 되어 돌아온다는 건 조금 이상하다.

 

item_id값이 string일지, int일지 float일지 어떤 데이터든 받아서 DB에 요청을 하게 된다면

 

당연히 프로그램에 문제가 생길 가능성이 높다. 막으려면 어떻게 해야할까?

 

item_id 값을 int형으로 제한할 수 있다.

간단하다 매개변수의 타입을 원하는 형태로 제한하면 된다.

 

이렇게 한다면 int외의 값이 들어올 경우 함수로 접근을 막아버린다.

주영민은 더 이상 천재가 아니다...

프론트에서도 API에 접근을 실패하니 당연히 예외처리가 쉽게 가능해질 것이다!

 

이런식으로 확실하게 정해주는 것은 버그를 막기 위해 중요하다.

 

쿼리 매개변수

우리가 URL에 매개 변수를 입력하는 것은 쿼리 매개변수라는 것도 있다.

 

흔히 URL에서 ?이후 매개변수마다 &로 구분되어지는 것이 바로 그것이다.

 

네이버 웹툰의 URL에서도 쉽게 볼 수 있다.

https://comic.naver.com/webtoon?tab=tue 


webtoon URL의 쿼리 매개변수는 tab이라는 뜻이다.

 

tab에 어떤 값이 들어가냐에 따라 돌아오는 요일 웹툰 리스트가 다르다.

from fastapi import FastAPI

app = FastAPI()

@app.get("/webtoon")
# tab과 item_id가 따로 입력되지 않으면 기본 값은 mon과 1이다.
async def read_item(tab: str="mon", item_id: int=1):
    return {tab : item_id}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

간단하게 구현해보았다.

 

먼저 http://localhost:8000/webtoon에 접속해보자.

tab과 item_id를 URL 파라미터로 넘겨주지 않았지만, 함수 선언문에 초기 값이 들어가있다.

 

그래서 에러가 나오지 않고, mon과 1이 출력되었다.

 

이번엔 URL로 파라미터를 넘겨서 값이 변하는 걸 확인해보자.

http://localhost:8000/webtoon?tab=tue&item_id=1

URL이 변경되자 return되는 데이터도 변경됐다.

 

이런 식으로 리턴되는 URL도 변경되었다.

 

하지만 여전히 이상한 점이 하나 남아있다. tab이 string형태로 지정되었기에 완전히 다른 문자가 들어갈 수도 있다는 거다.

김현준 바보

그렇다면 이 문제는 어떻게 해결해야할까??

 

여러가지 해결 방안이 있지만 공식문서에 소개되는 Enum 클래스를 사용하는 방식을 소개해보겠다.

from enum import Enum
from fastapi import FastAPI

app = FastAPI()

# tabName Enum을 선언한다.
class tabName(str, Enum):
	mon = "mon"
	tue = "tue"
	wed = "wed"
	thu = "thu"
	fri = "fri"
	sat = "sat"
	sun = "sun"

@app.get("/webtoon")
# tab을 tabName 클래스로 지정한다.
async def read_item(tab: tabName, item_id: int=1):
    return {tab : item_id}

    

if __name__ == "__main__":
    import uvicorn
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

이런식으로 열거형 클래스를 매개변수의 형식으로 지정해주면

 

해당 클래스의 값만 입력해야 정상작동 한다. 한번 테스트해보자

좀 기네...

이상한 값을 집어넣으면 뱉어낸다.

 

그렇다면 정상적인 값을 집어넣었을 때 잘 작동할까?

잘 작동한다. 추가적으로 이러한 내용은 docs에서도 잘 적용이 된다.

아예 이렇게 드롭박스로 제공해준다.

 

Reference

쿼리 매개변수
https://fastapi.tiangolo.com/ko/tutorial/path-params/
경로 매개변수
https://fastapi.tiangolo.com/ko/tutorial/path-params/

HTTP 요청 메서드
https://developer.mozilla.org/ko/docs/Web/HTTP/Methods

'개발관련 > FastAPI(BE)' 카테고리의 다른 글

FastAPI - (5) Model  (0) 2023.10.19
FastAPI - (4) DB 연결하기  (0) 2023.10.16
FastAPI - (3) Request Body  (0) 2023.10.10
FastAPI - (1) 개념 및 설치  (2) 2023.10.06