GET
REST API는 GET 부터 시작된다. GET 메소드는 서버로부터 정보를 가져올 때사용하는 READ API이다.
route 이용
route 메소드를 이용하면 string type의 데이터만 반환할 수 있다. 따라서 route를 이용한 GET 메소드는 서버가 제대로 동작하는지 확인하는 health check 용도로 적합하다.
from fastapi import FastAPI
app = FastAPI()
@app.get('/healthcheck')
async def health_check():
return 'OK'
(fastapi) PS D:\workspace> http :8000/healthcheck
HTTP/1.1 200 OK
content-length: 4
content-type: application/json
date: Sun, 14 Aug 2022 08:32:54 GMT
server: uvicorn
"OK"
get 이용
GET 메소드는 다양한 자료형을 반환할 수 있다. JSONResponse 객체를 이용해 dict 자료형을 JSON 으로 변환할 수 있다.
import uuid
from starlette.responses import JSONResponse
from fastapi import FastAPI
app = FastAPI()
@app.get('/{name}')
async def create_id(name: str):
result = JSONResponse({'id': str(uuid.uuid4()), 'name': name})
return result
(fastapi) PS D:\workspace> http :8000/syj
HTTP/1.1 200 OK
content-length: 58
content-type: application/json
date: Sun, 14 Aug 2022 08:39:02 GMT
server: uvicorn
{
"id": "912bf37d-aa6b-4b89-8189-b6265348b6da",
"name": "syj"
}
POST
POST 메소드는 CREATE에 해당된다. 서버에 데이터를 저장하고 싶을 때 사용한다. FastAPI에서 POST 메소드를 작성할 때는 pydanctic 이라는 스키마 디펜던시가 있다. 따라서 pydantic 에서 제공하는 BaseModel 상속없이는 POST 메소드를 작성할 수 없다.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
user_id: str
password: str
@app.post('/register')
async def register(user: User):
return user
(fastapi) PS D:\workspace> http :8000/register user_id=syj password=1234
HTTP/1.1 200 OK
content-length: 35
content-type: application/json
date: Sun, 14 Aug 2022 08:56:05 GMT
server: uvicorn
{
"password": "1234",
"user_id": "syj"
}
PUT, PATCH
PUT과 PATCH 메소드는 UPDATE에 해당한다. PUT은 전체 내용을 바꾸고, PATCH는 일부의 내용을 바꾼다.
PUT
from datetime import date
from typing import Optional
from pydantic import BaseModel, Field
from fastapi import FastAPI
user_db = {
'jack': {'username': 'jack', 'date_joined': '2021-12-01', 'location': 'New York', 'age': 28},
'jill': {'username': 'jill', 'date_joined': '2021-12-02', 'location': 'Los Angeles', 'age': 19},
'jane': {'username': 'jane', 'date_joined': '2021-12-03', 'location': 'Toronto', 'age': 52}
}
class User(BaseModel):
username: str
date_joined: Optional[date] = None
location: Optional[str] = None
age: int = Field(None, gt=5, lt=130)
class UserUpdate(User):
date_joined: Optional[date] = None
age : int = Field(None, gt=5, lt=130)
app = FastAPI()
@app.get('/users/{username}')
def get_users_path(username: str):
return user_db[username]
@app.put('/users')
async def update_user(user: User):
username = user.username
user_db[username] = user.dict()
return {'message': f'Successfully updated user {username}'}
PUT으로 바꾸면 안적은 date_joined과 location 값은 null로 초기화 된다.
(fastapi) PS D:\workspace>http :8000/users/jane
HTTP/1.1 200 OK
content-length: 76
content-type: application/json
server: uvicorn
{
"age": 52,
"date_joined": "2021-12-03",
"location": "Toronto",
"username": "jane"
}
(fastapi) PS D:\workspace> http PUT :8000/users username=jane age=99
HTTP/1.1 200 OK
content-type: application/json
date: Sun, 14 Aug 2022 09:36:10 GMT
server: uvicorn
{
"message": "Successfully updated user jane"
}
(fastapi) PS D:\workspace> http :8000/users/jane
HTTP/1.1 200 OK
content-length: 63
content-type: application/json
date: Sun, 14 Aug 2022 09:36:24 GMT
server: uvicorn
{
"age": 99,
"date_joined": null,
"location": null,
"username": "jane"
}
PATCH
from datetime import date
from typing import Optional
from pydantic import BaseModel, Field
from fastapi import FastAPI
user_db = {
'jack': {'username': 'jack', 'date_joined': '2021-12-01', 'location': 'New York', 'age': 28},
'jill': {'username': 'jill', 'date_joined': '2021-12-02', 'location': 'Los Angeles', 'age': 19},
'jane': {'username': 'jane', 'date_joined': '2021-12-03', 'location': 'Toronto', 'age': 52}
}
class User(BaseModel):
username: str
date_joined: Optional[date] = None
location: Optional[str] = None
age: int = Field(None, gt=5, lt=130)
class UserUpdate(User):
date_joined: Optional[date] = None
age : int = Field(None, gt=5, lt=130)
app = FastAPI()
@app.get('/users/{username}')
def get_users_path(username: str):
return user_db[username]
@app.put('/users')
async def update_user(user: User):
username = user.username
user_db[username] = user.dict()
return {'message': f'Successfully updated user {username}'}
@app.patch('/users')
async def update_user_partial(user: UserUpdate):
username = user.username
user_db[username].update(user.dict(exclude_unset=True))
return {'message': f'Successfully updated user {username}'}
PATCH는 기존 데이터는 그대로 두고 우리가 바꾸고자 하는 데이터만 바꿔주는 것을 확인할 수 있다.
(fastapi) PS D:\workspace> http PATCH :8000/users username=jane age=99
HTTP/1.1 200 OK
content-length: 44
content-type: application/json
date: Sun, 14 Aug 2022 09:39:52 GMT
server: uvicorn
{
"message": "Successfully updated user jane"
}
(fastapi) PS D:\workspace> http :8000/users/jane
HTTP/1.1 200 OK
content-length: 76
content-type: application/json
date: Sun, 14 Aug 2022 09:40:04 GMT
server: uvicorn
{
"age": 99,
"date_joined": "2021-12-03",
"location": "Toronto",
"username": "jane"
}
DELETE
DELETE 메소드는 삭제하는 메소드이다.
from datetime import date
from typing import Optional
from pydantic import BaseModel, Field
from fastapi import FastAPI
user_db = {
'jack': {'username': 'jack', 'date_joined': '2021-12-01', 'location': 'New York', 'age': 28},
'jill': {'username': 'jill', 'date_joined': '2021-12-02', 'location': 'Los Angeles', 'age': 19},
'jane': {'username': 'jane', 'date_joined': '2021-12-03', 'location': 'Toronto', 'age': 52}
}
class User(BaseModel):
username: str
date_joined: Optional[date] = None
location: Optional[str] = None
age: int = Field(None, gt=5, lt=130)
class UserUpdate(User):
date_joined: Optional[date] = None
age : int = Field(None, gt=5, lt=130)
app = FastAPI()
@app.get('/users')
def get_users_query(limit: int = 10):
user_list = list(user_db.values())
return user_list[:limit]
@app.delete('/users/{username}')
async def delete_user(username: str):
del user_db[username]
return {'message': f'Successfully deleted user {username}'}
다음과 같이 jane의 데이터를 삭제할 수 있다.
(fastapi) PS D:\workspace> http GET :8000/users
HTTP/1.1 200 OK
content-length: 237
content-type: application/json
date: Sun, 14 Aug 2022 09:45:12 GMT
server: uvicorn
[
{
"age": 28,
"date_joined": "2021-12-01",
"location": "New York",
"username": "jack"
},
{
"age": 19,
"date_joined": "2021-12-02",
"location": "Los Angeles",
},
{
"age": 52,
"date_joined": "2021-12-03",
"location": "Toronto",
"username": "jane"
}
]
(fastapi) PS D:\workspace> http DELETE :8000/users/jane
HTTP/1.1 200 OK
content-length: 44
content-type: application/json
date: Sun, 14 Aug 2022 09:45:38 GMT
server: uvicorn
{
"message": "Successfully deleted user jane"
}
(fastapi) PS D:\workspace> http GET :8000/users
HTTP/1.1 200 OK
content-length: 160
content-type: application/json
date: Sun, 14 Aug 2022 09:45:42 GMT
server: uvicorn
[
{
"age": 28,
"date_joined": "2021-12-01",
"location": "New York",
"username": "jack"
},
{
"age": 19,
"date_joined": "2021-12-02",
"location": "Los Angeles",
"username": "jill"
}
]
(참고) 에러 처리
from datetime import date
from typing import Optional
from pydantic import BaseModel, Field
from fastapi import FastAPI, HTTPException, status
user_db = {
'jack': {'username': 'jack', 'date_joined': '2021-12-01', 'location': 'New York', 'age': 28},
'jill': {'username': 'jill', 'date_joined': '2021-12-02', 'location': 'Los Angeles', 'age': 19},
'jane': {'username': 'jane', 'date_joined': '2021-12-03', 'location': 'Toronto', 'age': 52}
}
class User(BaseModel):
username: str
date_joined: Optional[date] = None
location: Optional[str] = None
age: int = Field(None, gt=5, lt=130)
app = FastAPI()
@app.post('/users')
def create_user(user: User):
username = user.username
if username in user_db:
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=f'Cannot create user. Username {username} already exists')
user_db[username] = user.dict()
return {'message': f'Successfully created user: {username}'}
(fastapi) PS D:\workspace> http POST :8000/users
username=jane age=100
HTTP/1.1 409 Conflict
content-length: 61
content-type: application/json
date: Sun, 14 Aug 2022 10:03:35 GMT
server: uvicorn
{
"detail": "Cannot create user. Username jane
already exists"
}
참고링크: https://github.com/liannewriting/YouTube-videos-public/blob/main/fastapi-python-tutorial-intro/fastapi-python-tutorial-2022-final.py