최근 가벼운 서버를 구축할 필요가 생겨 사용하는 김에 정리를 해봅니다.
배우기 쉽고 빠른 성능을 보인다고 하니 가볍게 사용할 수 있고, Python 기반이라 금방 익힐 수 있는 것 같아요.
Install Module
먼저, 필요한 모듈들을 설치해 줍니다.
$ pip install fastapi "uvicorn[standard]"
Implement Server
다음으로, server application을 구현합니다.
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
Root("/") 경로로 요청이 오면 "Hello World"를 반환해 줍니다.
Run Server
이제 명령창에 다음 명령을 입력하여 서버를 구동합니다.
$ uvicorn main:app --reload
다음과 같이 서버가 시작되면, 브라우저를 통해 접근해 봅니다.
명령창을 참고하여 "http://127.0.0.1:8000"에 접속해보면 JSON 메세지가 반환되는 것을 확인해 보실 수 있습니다.
Request Parameters
이제 사용자로부터 좀 더 다양한 요청을 받아서 처리해보도록 할게요.
@app.get("/params/{param_id}")
async def params(param_id):
return {"Param ID": param_id}
먼저, 경로를 입력받아 처리하는 함수를 추가했습니다.
브라우저에서 "http://127.0.0.1:8000/params/3"과 같은 형태로 요청을 보내면 설정한 대로 JSON 메세지가 반환됩니다.
이번엔 query를 처리해 보도록 하겠습니다.
@app.get("/queries")
async def queries(x: int = 0, y: str = ""):
return {"X": x, "Y": y}
x라는 정수와, y라는 문자열을 받아서 처리하는 함수를 추가했습니다.
브라우저에서 "http://127.0.0.1:8000/queries?x=7&y=hello"와 같은 형태로 요청을 보내면 설정한 대로 JSON 메세지가 반환됩니다.
Response with HTML
JSON만 반환하면 너무 밋밋하니 HTML 형태로 반환하도록 해봅시다.
from fastapi.responses import HTMLResponse
@app.get("/hello", response_class=HTMLResponse)
async def hello(name: str=""):
return f"""
<html>
<head>
<title>FastAPI Example</title>
</head>
<body>
<h1>Hello, {name}!</h1>
</body>
</html>
"""
사용자에게 이름을 입력받아 인사를 하는 함수를 추가했습니다.
따로 설명할 게 없을만큼 간단하죠?
브라우저에서 "http://127.0.0.1:8000/hello?name=HoYa"와 같은 형태로 요청을 보내면 결과를 보실 수 있어요.
Using with Jinja2
HTML 코드를 매번 직접 반환하려면 여간 귀찮고 힘든 게 아니죠.
이제 Jinja2를 사용해 봅니다.
먼저 모듈을 설치해 줍니다.
$ pip install jinja2
다음으로, 코드에 적용을 해줍니다.
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
templates = Jinja2Templates(directory="templates")
@app.get("/hello", response_class=HTMLResponse)
async def hello(request: Request, name: str=""):
return templates.TemplateResponse("index.html", {"request": request, "name": name})
코드도 깔끔해지고, 관리도 수월해 졌습니다.
이제, index.html 파일을 작성합니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css">
<title>FastAPI Example</title>
</head>
<body>
<main class="container">
<H1>Hello, {{name}}!</H1>
</main>
</body>
</html>
밋밋한 건 싫어서 picocss를 사용했고, 나머진 크게 다를 게 없습니다. ^^
테스트를 해보면 역시 잘 동작하는 것을 확인해 보실 수 있습니다.
Post using Form
이제 마지막으로 사용자로부터 입력을 받아봅시다.
@app.get("/hello", response_class=HTMLResponse)
async def hello(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
@app.get("/form", response_class=HTMLResponse)
async def form(request: Request, name: str="", age=0):
return templates.TemplateResponse("form.html", {"request": request, "name": name, "age": age})
/hello를 받으면 사용자에게 입력받을 form을 출력합니다.
/form은 사용자의 입력을 query로 받아 결과를 출력합니다.
<!-- index.html -->
<body>
<main class="container">
<h1>Hello, Let me know who you are!</h1>
<form class="container" action="/form?name={{name}}&age={{age}}">
<div class="grid">
<label for="name">
Name
<input type="text" id="name" name="name" placeholder="Name" required>
</label>
<label for="age">
Age
<input type="number" id="age" name="age" placeholder="Age" required>
</label>
</div>
<button type="submit">Submit</button>
</form>
</main>
</body>
<!-- form.html -->
<body>
<main class="container">
<h1>Hello, {{name}}!</h1>
<h2>You are {{age}} years old.</h2>
</main>
</body>
각각의 페이지는 요렇게 만들었습니다.
브라우저에서 "http://127.0.0.1:8000/hello"에 접속한 후, 정보를 입력하면 정상적으로 출력되는 것이 보일 거에요.
Documentation
FastAPI의 장점 중 하나는 API 문서를 자동으로 생성해 준다는 점입니다.
브라우저에서 "http://127.0.0.1:8000/docs"에 접속하시면 확인하실 수 있습니다.
Wrap Up
알고만 있고 직접 사용해본 것은 이번이 처음이었는 데, 정말 쉽긴 하더라고요.
공식 홈페이지만 참고해서 2시간도 안걸려서 원하는 걸 만들 수 있었어요.
간단히 기본적인 내용을 공유드리려고 포스팅을 했는데, 간결하게 중요한 부분만 설명 드리려고 노력했습니다.
그러다보니 코드도 살짝 생략한 부분들이 있긴 한데, 아마 기본적인 거라 잘 따라하셨을거라 믿습니다. ^^
Jinja2를 사용해 보셨다면 조금 더 편하게 이용하실 수 있을 거에요.
공통 부분을 묶어서 확장하거나, 조건에 따라 내용을 변경하는 등 기본적인 것은 FastAPI와도 다 동작합니다.
도움이 되셨길 바랍니다.
'Python' 카테고리의 다른 글
[Typer] Python으로 CLI App 만들기 (0) | 2024.03.30 |
---|---|
[Python] PyPI에 패키지 배포하기 (3) | 2024.03.16 |
[PyQt6] Save and Load Settings using QSettings (0) | 2023.04.06 |
[Python] Create and Draw Graph (0) | 2023.03.01 |
[Python] Abstract Base Classes (0) | 2023.02.23 |
댓글