본문 바로가기
Web 개발/FAST API (인프런 강의 내용)

1 실습4 PATCH API todo 수정

by yororing 2024. 4. 16.

앞 단계 참조 링크:

현재 파일 내용:

# /todos/src/main.py 내용

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

# 첫 화면 API
@app.get("/")
def health_check_handler():
    return {"ping": "pong"}

# POST 생성을 위해 사용자로부터 전달받을 request 클래스 생성
class CreateToDoRequest(BaseModel):
    id: int
    contents: str
    is_done: bool

# 데이터베이스 역할하는 딕셔너리 생성
todo_data = {
    1: {
        "id": 1,
        "content": "실전! FastAPI 섹션 0 수강",
        "is_done": True,
    },
    2: {
        "id": 2,
        "content": "실전! FastAPI 섹션 1 수강",
        "is_done": False,
    },
    3: {
        "id": 3,
        "content": "실전! FastAPI 섹션 2 수강",
        "is_done": False,
    },
}

# GET Medthod 사용하여 전체 조회 API
@app.get("/todos")
def get_todos_handler(order: str | None = None):
    rt = list(todo_data.values())
    if order and order == "DESC":
       return rt[::-1]
    return rt

# GET Medthod 사용하여 단일 조회 API
@app.get("/todos/{todo_id}")
def get_todo_handler(todo_id: int):
    return todo_data.get(todo_id, {})

# POST Medthod 사용하여 todo 생성 API
@app.post("/todos")
def create_todos_handler(request: CreateToDoRequest):
    todo_data[request.id] = request.dict()
    return todo_data[request.id]

 

 

04 기존 ToDo 수정하기 (PATCH Method 사용)

  • PATCH Method를 이용해 기존에 있는 ToDo를 업데이트/수정하는 API 만들기

1. main.py에 쓰기

1) fastapi의 Body 참조하기

# todos > src > main.py
from fastapi import FastAPI, Body	# 추가됨
from pydantic import BaseModel
...

2) PATCH Method Mapping해당 path에 PATCH 요청을 보내는 API 생성

# todos > src > main.py
from fastapi import FastAPI, Body	# 추가됨
from pydantic import BaseModel
...
@app.patch("/todos/{todos_id}")
def update_todo_handler(
	todo_id: int,
	is_done: bool = Body(..., embed=True)
	):
	todo = todo_data.get(todo_id)
	if todo:
		todo["is_done"] = is_done
		return todo
	return {}
  • @app.patch("/todos/{todos_id}")
    • appPATCH Method를 매핑
    • todos{todo_id}를 path로 받음
  • def update_todo_handler(
    • update_todo_handler 라는 함수(핸들러) 생성
  • todo_id: int,
    • todo_id 값을 int 형태로 받음
  •  is_done: bool = Body(..., embed=True) 
    • is_done 값을 bool 형태로 받음
    • = Body(..., embed=True)
      • 사용자의 todo의 달성 여부를 수정/업데이트 해주기 위해선 사용자로부터 request body로 is_done 값을 받아야 됨
      • 앞서 (참조: 1 실습3 POST API ToDo 생성) 새로운 todo를 생성할 때처럼 3개의 컬럼 ('id', 'contents', 'is_done')을 업데이트할 것이 아니라 하나 (i.e., 'is_done')만 받을 것
      • = Body(..., embed=True)를 적어줄 시 class 생성할 필요 없이 FastAPI에서 하나의 컬럼 값 (여기선 is_done)을 request body로 사용 가능
    • 즉, is_done 값을 request body에 전달했을 때 이 is_done으로 들어오게 될 것(?)
  • todo = todo_data.get(todo_id)
    • 역할: todo_id로 todo 조회하기
    • 기존의 todo_data에서 get Method 사용하여 todo_id를 통해 가져온 걸 todo에 넣음
  • if todo: 
    • todo가 있을 경우
  • todo["is_done"] = is_done
    • 기존에 있는 todo의 is_done 값을 사용자의 요청으로 받은 is_done 값으로 수정
  • return todo
    • 수정된 데이터 반환
  • return { }
    • todo가 없을 경우 빈 딕셔너리 반환

2. FastAPI 웹 서버 자동 재시작 (--reload 옵션 사용)

  • 웹 서버 실행 후 코드 변경 시 변경사항을 SwaggerUI에 반영하기 위해선 웹 서버 재시작 (uvicorn 종료 후 다시 실행) 필수
  • reload 옵션 사용 시 변화가 감지되면 자동으로 서버를 FastAPI가 재시작 됨
  • 방금 수정한 main.py를 저장 (ctrl + S) 하면 자동으로 재시작되어 변경사항이 반영됨
  • 우선 시작 안했으면 시작하기
$ cd /c/Users/관리자/Desktop/projects/todos/src
$ uvicorn main:app --reload
INFO:     Will watch for changes in these directories: ['C:\\Users\\관리자\\Desktop\\projects\\todos\\src']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [11092] using StatReload
INFO:     Started server process [13676]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
  • 시작 후 문서를 변경했으면 저장하기 
# 변경된 main.py를 저장하면 다음이 터미널에 출력됨
WARNING:  StatReload detected changes in 'main.py'. Reloading...
INFO:     Started server process [17024]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

3. SwaggerUI 및 화면 확인

1) Swagger 문서 확인

  • 브라우저에 http://127.0.0.1:8000/docs 입력 또는 새로고침 시
  •  

  • PATCH API가 추가된 것 확인
  • PATCH 클릭 시 request body도 예시와 함께 문서 반영되어 있는 것 확인
  •  

  • 다만, Responses에 대해서는 typing을 적용 안 해줬기에 아직 정상적으로 적용되지 않음 (추후에 바꿔볼 것임)

2) Swagger 문서에서 PATCH API 실습

  • 전체 todo 목록 확인
    • GET /todos Get Todos Handler > Try it out > Execute 하여 전체 목록 확인
    •  

 

  • 'id'값 = 2인 todo의 'is_done' 값 수정하기
    • PATCH /todos/{todo_id} Update Todo Handler > Try it out 클릭
    • todo_id 값에 2 입력
    • Request body에 {"is_done": true} 입력
    • Execute 클릭 시
    •  
    • Curl을 보면 PATCH Method의 /todos/2로 요청이 들어간 것을 확인
    • Server Response를 보면 'id'=2인 todo의 'is_done' 값이 true로 수정된 것 확인
  • 존재하지 않는 todo의 'is_done' 값 수정해보기
    • PATCH /todos/{todo_id} Update Todo Handler > Try it out 클릭
    • todo_id 값에 4 입력
    • Request body에 {"is_done": true} 입력 
    • Execute 클릭 시
    • Server Response를 보면 빈 딕셔너리 반환된 것 확인

주의※ 

  • 상태코드
    • 일반적으로 잘못된 path 처리에 대한 요청 (예, 지금과 같이 없는 todo의 값을 수정 등) 시 404 처리를 하지만 강의에선 아직 상태 메시지/코드에 대해 배우지 않아 지금은 빈 딕셔너리로 반환하는 것으로 처리
  • 데이터베이스
    • 앞서 <실습3 POST API ToDo 생성>에서 "id":4인 todo를 생성했는데 PATCH 했을 때에는 없다고 나오는 이유:
      • todo를 database에 저장하지 않고 todo_data라는 딕셔너리를 이용해서 메모리에서 사용하고 있음
      • 즉, 서버를 내렸다 올리면 그 때마다 메모리에 새로 쓰여진 값들이 refresh가 됨
      • 즉, 코드로 적은 "id": 1, 2, 3번의 todo들만 남게 되고 서버가 내렸다 올라가면 우리가 동적으로 추가한 "id": 4의 todo는 남아있지 않음
      • 그러므로 일반적인 경우 이런 작업을 database로 처리하여 새로 추가된 데이터나 변경된 데이터를 영속적으로 관리함
      • 하지만 강의에선 아직 database에 대해 배우지 않아 지금은 서버를 내리고 올렸을 경우 "id": 1, 2, 3만 남아있음
      • 추후 (section 2)에 database로 데이터 수정사항 영구적 저장 방법에 대해 배울것임

이때까지의 코드들:

# .../todos/src/main.py 내용

from fastapi import FastAPI, Body
from pydantic import BaseModel

app = FastAPI()

# 첫 화면 API
@app.get("/")
def health_check_handler():
    return {"ping": "pong"}

# POST 생성을 위해 사용자로부터 전달받을 request 클래스 생성
class CreateToDoRequest(BaseModel):
    id: int
    contents: str
    is_done: bool

# 데이터베이스 역할하는 딕셔너리 생성
todo_data = {
    1: {
        "id": 1,
        "content": "실전! FastAPI 섹션 0 수강",
        "is_done": True,
    },
    2: {
        "id": 2,
        "content": "실전! FastAPI 섹션 1 수강",
        "is_done": False,
    },
    3: {
        "id": 3,
        "content": "실전! FastAPI 섹션 2 수강",
        "is_done": False,
    },
}

# GET Method 사용하여 전체 조회 API
@app.get("/todos")
def get_todos_handler(order: str | None = None):
    rt = list(todo_data.values())
    if order and order == "DESC":
       return rt[::-1]
    return rt

# GET Method 사용하여 단일 조회 API
@app.get("/todos/{todo_id}")
def get_todo_handler(todo_id: int):
    return todo_data.get(todo_id, {})

# POST Medthod 사용하여 todo 생성 API
@app.post("/todos")
def create_todos_handler(request: CreateToDoRequest):
    todo_data[request.id] = request.dict()
    return todo_data[request.id]

# PATCH Method 사용하여 is_done 값 수정 API
@app.patch("/todos/{todo_id}")
def update_todo_handler(
    todo_id: int,
    is_done: bool = Body(..., embed=True)
    ):
    todo = todo_data.get(todo_id)
    if todo:
        todo["is_done"] = is_done
        return todo
    return {}

 

'Web 개발 > FAST API (인프런 강의 내용)' 카테고리의 다른 글

1 실습6 ERROR 처리  (0) 2024.04.18
1 실습5 DELETE API todo 삭제  (0) 2024.04.17
1 실습3 POST API todo 생성  (0) 2024.04.15
1 실습2 GET API 단일조회  (0) 2024.04.09
1 실습1 GET API 전체조회  (0) 2024.04.05