WeniVooks

검색

FastAPI 베이스캠프

기본 라우팅

1. 기본 라우팅 및 세팅

1.1 기본 라우팅

라우팅은 앞서 언급했었던 경로를 동작에 연결하는 것입니다. 이번 챕터에서는 여러 경로를 만들어보고, 각 경로에 대한 응답을 확인해보겠습니다.

경로 함수명 설명
/ read_root {"Hello": "World"}를 반환합니다.
/about about {"message": "about page"}를 반환합니다.
/contact contact {"message": "contact page"}를 반환합니다.
/notice notice 공지사항 목록을 반환합니다.

라우팅을 만들 때에는 이렇게 먼저 경로와 함수명을 정의하는 것이 좋습니다. 실제 프로젝트에서는 어떻게 테이블을 만드는지 아래 프로젝트를 참고해주세요. 샘플 프로젝트입니다.

샘플 프로젝트

여기에는 다양한 경로, 함수명, 메서드, 권한 등이 정의 되어 있습니다. 우리는 점차 위 테이블을 실무에 가깝게 만들어볼 예정입니다.

1.2 기본 세팅

매번 실습 하는 코드가 달라지고, 각각의 챕터로 바로 오신 분들을 위해 매 챕터마다 새로운 폴더를 만들어서 진행하겠습니다. 이번 실습 폴더는 02_1_route입니다. VSC 터미널에서 사용할 명령어 입니다. 가상환경은 벗어난 상태에서 실행해야 합니다. 만약 터미널 입력창 앞에 (venv)라고 되어 있다면 deactivate 명령어로 가상환경을 나간 상태에서 cd ..으로 상위 폴더로 나와 아래 명령어를 실행해주세요.

저는 Window로 실습을 하고 있기 때문에 .\venv\Scripts\activate로 가상환경을 활성화하고 있습니다. Mac이나 Linux를 사용하시는 분들은 source ./venv/bin/activate로 가상환경을 활성화하시면 됩니다.

mkdir 02_1_route
cd 02_1_route
python -m venv venv
.\venv\Scripts\activate
pip install fastapi
pip install uvicorn
mkdir 02_1_route
cd 02_1_route
python -m venv venv
.\venv\Scripts\activate
pip install fastapi
pip install uvicorn

main.py 파일을 생성하고 아래 코드를 입력합니다.

from fastapi import FastAPI
 
 
app = FastAPI()
 
@app.get("/")
def read_root():
    return {"Hello": "World"}
from fastapi import FastAPI
 
 
app = FastAPI()
 
@app.get("/")
def read_root():
    return {"Hello": "World"}

개발 서버를 실행하여 127.0.0.1:8000접속이 되는 것을 확인합니다.

uvicorn main:app --reload
uvicorn main:app --reload

2. 다양한 URL 요청 처리하기

이번에는 다양한 URL을 만들어보겠습니다. 위에서 정의한 테이블을 참고하여 코드를 작성합니다.

from fastapi import FastAPI
 
app = FastAPI()
 
 
@app.get("/")
def read_root():
    return {"Hello": "World"}
 
 
@app.get("/about")
def about():
    return {"message": "about page"}
 
 
@app.get("/contact")
def contact():
    return {"message": "contact page"}
 
 
@app.get("/notice")
def notice():
    return {
        "notice": [
            {"title": "공지사항1", "content": "내용1"},
            {"title": "공지사항2", "content": "내용2"},
            {"title": "공지사항3", "content": "내용3"},
        ]
    }
from fastapi import FastAPI
 
app = FastAPI()
 
 
@app.get("/")
def read_root():
    return {"Hello": "World"}
 
 
@app.get("/about")
def about():
    return {"message": "about page"}
 
 
@app.get("/contact")
def contact():
    return {"message": "contact page"}
 
 
@app.get("/notice")
def notice():
    return {
        "notice": [
            {"title": "공지사항1", "content": "내용1"},
            {"title": "공지사항2", "content": "내용2"},
            {"title": "공지사항3", "content": "내용3"},
        ]
    }

이 코드를 main.py 파일에 저장하고 다음 명령어로 서버를 실행합니다.

uvicorn main:app --reload
uvicorn main:app --reload

브라우저에서 위에서 정의한 URL을 차례대로 접속합니다. 여기서 직접 클릭해서 확인해보기 위해서는 Ctrl + 클릭을 사용하면 됩니다. Ctrl을 누르지 않고 클릭을 하면 위니북스를 벗어납니다.

  1. http://localhost:8000/
  2. http://localhost:8000/about
  3. http://localhost:8000/contact
  4. http://localhost:8000/notice

각 URL에 접속하면 각각의 응답을 받게 됩니다. 이러한 딕셔너리 형태의 응답을 JSON 응답이라고 합니다. 주로 웹 개발에서 데이터를 주고 받을 때 사용하며 프론트엔드 개발자가 이러한 데이터를 받아 화면을 구성할 수 있습니다.

다만 이렇게 만든 URL을 가지고 앞서 테스트한 about:blank에서 js코드로 테스트할 수는 없습니다. 이는 CORS(Cross-Origin Resource Sharing) 정책 때문입니다. 이 정책은 보안을 위해 브라우저가 다른 도메인으로부터 리소스를 요청할 때 제한을 두는 정책입니다. 이를 해결하기 위해서는 FastAPI에서 CORS를 허용하는 설정을 추가해야 합니다. 이 설정은 지금 필요하지 않으므로 나중에 추가할 예정입니다.

또한 http://localhost:8000/docs 에 접속하면 FastAPI가 자동으로 생성한 API 문서를 확인할 수 있습니다. 이 문서는 Swagger를 사용하여 생성되며, API의 엔드포인트, 요청/응답 형식, 파라미터 등을 확인할 수 있습니다. 좀 더 상세한 기능을 제공하는 ReDoc 문서는 http://localhost:8000/redoc 에서 확인할 수 있으며 http://localhost:8000/openapi.json 에서 JSON 형식으로 확인할 수도 있습니다.

이 문서를 더 상세하게 작성하고 싶다면 아래와 같은 형식의 코드를 추가하면 됩니다.

from fastapi import FastAPI
 
app = FastAPI()
 
@app.get("/", tags=["Root"], summary="Root API", description="Hello World를 반환합니다.")
def read_root():
    return {"Hello": "World"}
from fastapi import FastAPI
 
app = FastAPI()
 
@app.get("/", tags=["Root"], summary="Root API", description="Hello World를 반환합니다.")
def read_root():
    return {"Hello": "World"}

이제 http://localhost:8000/docs 에 접속하면 위에서 작성한 설명이 문서에 추가된 것을 확인할 수 있습니다.

3. 요청에 다양한 방식으로 응답

3.1 HTML 응답하기

FastAPI는 기본적으로 딕셔너리 형태의 JSON 응답을 반환하는 것이 일반적입니다. 다만, 아래와 같이 HTML 형태로 응답할 수도 있습니다. HTML은 웹 서비스를 만들 때 사용하는 언어입니다.

from fastapi import FastAPI
from fastapi.responses import HTMLResponse
 
app = FastAPI()
 
@app.get("/", response_class=HTMLResponse)
def index():
    return '<h1>hello world 1</h1>'
 
@app.get("/about", response_class=HTMLResponse)
def about():
    return '<h1>hello world 2</h1>'
 
@app.get("/contact", response_class=HTMLResponse)
def contact():
    return '<h1>hello world 3</h1>'
 
@app.get("/notice", response_class=HTMLResponse)
def notice():
    return '<h1>hello world 4</h1>'
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
 
app = FastAPI()
 
@app.get("/", response_class=HTMLResponse)
def index():
    return '<h1>hello world 1</h1>'
 
@app.get("/about", response_class=HTMLResponse)
def about():
    return '<h1>hello world 2</h1>'
 
@app.get("/contact", response_class=HTMLResponse)
def contact():
    return '<h1>hello world 3</h1>'
 
@app.get("/notice", response_class=HTMLResponse)
def notice():
    return '<h1>hello world 4</h1>'

이번에도 순서대로 URL에 접속하여 응답을 확인해보세요.

  1. http://localhost:8000/
  2. http://localhost:8000/about
  3. http://localhost:8000/contact
  4. http://localhost:8000/notice

각 URL에 접속하면 아래와 같이 HTML 형태의 응답을 받게 됩니다.

텍스트를 아래와 같이 수정하면 좀 더 다양한 형태의 HTML을 반환할 수 있습니다.

@app.get("/", response_class=HTMLResponse)
def index():
    return '''
    <h1>hello world 1</h1>
    <p>안녕</p>
    <ol>
        <li>첫 번째</li>
        <li>두 번째</li>
        <li>세 번째</li>
    </ol>
    '''
@app.get("/", response_class=HTMLResponse)
def index():
    return '''
    <h1>hello world 1</h1>
    <p>안녕</p>
    <ol>
        <li>첫 번째</li>
        <li>두 번째</li>
        <li>세 번째</li>
    </ol>
    '''

다시 한 번 URL에 접속하여 응답을 확인해보세요.

3.2 템플릿으로 응답하기

자주 사용되는 형태는 아니지만 .html 파일을 사용하여 응답할 수도 있습니다. 이렇게 만들어진 파일로 응답하는 것을 템플릿으로 응답한다고 합니다. 템플릿으로 응답을 보내기 위해서는 jinja2가 필요합니다. Ctrl+C로 서버를 중지하고 다음 명령어로 jinja2를 설치합니다.

pip install jinja2
pip install jinja2

main.py 파일을 다음과 같이 수정합니다.

from fastapi import FastAPI
from fastapi import Request
from fastapi.templating import Jinja2Templates
 
 
app = FastAPI(docs_url="/documentation", redoc_url=None)
 
templates = Jinja2Templates(directory="templates")
 
 
@app.get("/")
def index(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})
from fastapi import FastAPI
from fastapi import Request
from fastapi.templating import Jinja2Templates
 
 
app = FastAPI(docs_url="/documentation", redoc_url=None)
 
templates = Jinja2Templates(directory="templates")
 
 
@app.get("/")
def index(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

여기서 설정한 파일을 만듭니다. 파일은 01_3_basic > templates 폴더에 저장합니다.

<h1>hello world</h1>
<p>안녕</p>
<h1>hello world</h1>
<p>안녕</p>

다시 아래 명령어를 통해 서버를 실행합니다.

uvicorn main:app --reload
uvicorn main:app --reload

127.0.0.1:8000에 접속하면 html 파일이 렌더링된 화면을 확인할 수 있습니다. jinja2에 자세한 사용법은 이 강의의 범위를 벗어나므로 공식문서나 ChatGPT와 같은 LLM 참고하시기 바랍니다. FastAPI는 아키텍처가 단순하여 LLM을 사용하더라도 완성도 높은 코드를 작성할 수 있습니다.

설치한 jinja2는 템플릿을 사용하지 않을 경우 필요하지 않습니다. 앞으로 할 실습에서는 템플릿을 사용하지 않을 것이므로, templates 폴더와 jinja2를 삭제하셔도 됩니다. 남겨두셔도 문제는 되지 않습니다.

2장 FastAPI로 기본 API 만들기2.2 매개변수 라우팅