앞 단계 참조 링크:
- 상태 코드: 2024.03.26 - [Web 개발/FAST API (인프런 강의 내용)] - 1 FastAPI 알아보기
- 프로젝트 소개 및 환경 구축: 2024.04.05 - [Web 개발/FAST API (인프런 강의 내용)] - 1 실습1 GET API 전체조회
- 1 실습1 GET API ToDo 전체 조회: 2024.04.05 - [Web 개발/FAST API (인프런 강의 내용)] - 1 실습1 GET API 전체조회
- 1 실습2 GET API ToDo 단일 조회: 2024.04.09 - [Web 개발/FAST API (인프런 강의 내용)] - 1 실습2 GET API 단일조회
- 1 실습3 POST API ToDo 생성: 2024.04.15 - [Web 개발/FAST API (인프런 강의 내용)] - 1 실습3 POST API todo 생성
- 1 실습4 PATCH API ToDo 수정: 2024.04.16 - [Web 개발/FAST API (인프런 강의 내용)] - 1 실습4 PATCH API todo 수정
- 1 실습5 DELETE API ToDo 삭제: 2024.04.17 - [Web 개발/FAST API (인프런 강의 내용)] - 1 실습5 DELETE API todo 삭제
현재 파일 내용:
# .../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 {}
# DELETE Method 사용하여 todo 아이템 삭제 API
@app.delete("/todos/{todo_id}")
def delete_todo_handler(todo_id: int):
todo_data.pop(todo_id, None)
return todo_data
06 상태 코드 (Status Code) 적용하기
- 목표: ToDo API에 상태 코드 적용하기
- 사용방법: 데코레이터에 status_code=n을 명시적으로 작성 (기본값 = 200)
- Method (GET, POST, PUT, PATCH, DELETE 등)를 mapping해준 decorator에 'status_code=n'을 반점 (,) 뒤에 적어주면 됨 (default = 200)
- 자주 사용되는 상태 코드들:
큰 분류 | 상태 코드 | 설명 |
200번대 (요청 성공) |
200 OK | 요청 성공, 범용적, GET / POST / PUT / PATCH |
201 Created | 요청 성공, 새로운 자원 생성, POST | |
204 No Content | 요청 성공, 응답할 자원 없음, DELETE | |
400번대 (요청 실패) (의도적으로 서버에서 발생시키는 에러) |
400 Bad Request | 요청 실패, 요청이 잘못된 경우 (query param, request body) |
401 Unauthorized | 인증 실패 | |
403 Forbidden | 권한 문제 또는 잘못된 method | |
404 Not Found | 존재하지 않은 자원 요청 또는 잘못된 endpoint 요청 | |
500번대 (다른 에러) (예상치 못한 상황에서 발생하는 에러) |
500 Internal Server Error | 범용적인 서버 에러 (원인 불명확) |
502 Bad Gateway | Reverse Proxy (e.g., Nginx)에서 서버(upstream 서버)의 응답을 처리할 수 없는 경우 | |
503 Service Unavailable | 서버가 요청을 처리할 수 없는 경우 (e.g., 서버의 일시적 부하, 서버 다운) |
1. GET 전체 조회 항상 status_code=200 설정
1) 데코레이터에 status_code=n 명시적으로 작성
# ../todos/src/main.py
...
@app.get("/todos", status_code=200) # 추가됨
def get_todos_handler(order:str | None = None):
ret = list(todo_data.values())
if order and order == "DESC":
return ret[::-1]
return ret
...
2) FastAPI 웹 서버 자동 재시작 (--reload 옵션 사용)
- 웹 서버 실행 후 코드 변경 시 변경사항을 SwaggerUI에 반영하기 위해선 웹 서버 재시작 (uvicorn 종료 후 다시 실행) 필수
- reload 옵션 사용 시 변화가 감지되면 자동으로 서버를 FastAPI가 재시작 됨
- 방금 수정한 main.py를 저장 (ctrl + S) 하면 자동으로 재시작되어 변경사항이 반영됨
- 우선 시작 안했으면 시작하기
$ 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 [352] using StatReload
INFO: Started server process [8700]
INFO: Waiting for application startup.
INFO: Application startup complete.
- 시작 후 문서를 변경했으면 저장하기 (Ctrl + S)
3) Swagger UI 문서 확인
- 브라우저에 http://127.0.0.1:8000/docs 입력 또는 새로고침
- GET /todos Get Todos Handler (전체 조회) 클릭 > Try it out > Execute 클릭 시
- Server Response를 보면 Code 아래 상태 코드 200이 잘 반환되는 것 확인
2. GET 단일 조회 예외처리 설정 - 없는 자원 요청 (Resource Not Found)
1) 필요한 패키지 참조: fastapi의 HTTPException
# .../todos/src/main.py 내용
from fastapi import FastAPI, Body, HTTPException # 추가됨
from pydantic import BaseModel
...
2) 데코레이터에 status_code=n 작성 및 raise로 Exception 발생
# .../todos/src/main.py
...
@app.get("/todos/{todo_id}", status_code=200) # 추가됨
def get_todo_handler(todo_id: int):
todo = todo_data.get(todo_id) # 추가됨
if todo: # 추가됨
return todo # 추가됨
raise HTTPException(status_code=404, detail="ToDo Not Found") # 추가됨
...
- @app.get("todos/{todo_id}, status_code=200)
- 정상적으로 처리될 시 상태 코드 200을 반환
- todo = todo_data.get(todo_id)
- 사용자로부터 받은 todo_id를 todo_data에서 조회하여 해당 todo_id의 todo 값을 todo 변수에 할당
- todo 값이 없을 경우 (즉, 사용자로부터 받은 todo_id 값이 todo_data에 없을 경우) 기본값=None을 할당
- if todo: return todo
- todo 값이 있을 경우 해당 todo_id의 todo 값을 반환
- raise HTTPException(status_code=404, detail="ToDo Not Found")
- todo 값이 없을 경우 raise를 통해 exception 발생시켜줌
- 상태 코드는 404
- detail 인자를 통해 원하는 error message 표현
3) FastAPI 웹 서버 자동 재시작 (--reload 옵션 사용)
- 웹 서버 실행 후 코드 변경 시 변경사항을 SwaggerUI에 반영하기 위해선 웹 서버 재시작 (uvicorn 종료 후 다시 실행) 필수
- reload 옵션 사용 시 변화가 감지되면 자동으로 서버를 FastAPI가 재시작 됨
- 방금 수정한 main.py를 저장 (ctrl + S) 하면 자동으로 재시작되어 변경사항이 반영됨
- 우선 시작 안했으면 시작하기
- 시작 후 문서를 변경했으면 저장하기 (Ctrl + S)
# main.py에서 Ctrl + S 시 터미널에 다음이 출력됨
WARNING: StatReload detected changes in 'main.py'. Reloading...
INFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Application shutdown complete.
INFO: Finished server process [8700]
Process SpawnProcess-1:
Traceback (most recent call last):
File "C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\asyncio\runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\asyncio\base_events.py", line 684, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
asyncio.exceptions.CancelledError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\multiprocessing\process.py", line 314, in _bootstrap
self.run()
File "C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\multiprocessing\process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\site-packages\uvicorn\_subprocess.py", line 78, in subprocess_started
target(sockets=sockets)
File "C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\site-packages\uvicorn\server.py", line 65, in run
return asyncio.run(self.serve(sockets=sockets))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\asyncio\runners.py", line 194, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\asyncio\runners.py", line 123, in run
raise KeyboardInterrupt()
KeyboardInterrupt
INFO: Started server process [14232]
INFO: Waiting for application startup.
INFO: Application startup complete.
4) Swagger 문서 확인
- 브라우저에 http://127.0.0.1:8000/docs 입력 또는 새로고침
- GET /todos/{todo_id} Get Todo Handler (단일 조회) 클릭 > Try it out 클릭
- todo_id 에 1 적기 (존재하는 값) > Execute 클릭 시
- 상태 코드 200이 잘 반환되는 것 확인
- todo_id 에 10 적기 (존재하지 않는 값) > Execute 클릭 시
- 상태 코드 404가 반환됨 + 'detail'에 'ToDo Not Found'라고 출력되는 것 확인
3. POST 항상 status_code=201 설정 - 새로운 자원 생성
1) 데코레이터에 status_code=n 명시적으로 작성
# ../todos/src/main.py
...
@app.post("/todos", status_code=201) # 추가됨
def create_todo_handler(request: CreateToDoRequest):
todo_data[request.id] = request.dict()
return todo_data[request.id]
...
2) FastAPI 웹 서버 자동 재시작 (--reload 옵션 사용)
- 웹 서버 실행 후 코드 변경 시 변경사항을 SwaggerUI에 반영하기 위해선 웹 서버 재시작 (uvicorn 종료 후 다시 실행) 필수
- reload 옵션 사용 시 변화가 감지되면 자동으로 서버를 FastAPI가 재시작 됨
- 방금 수정한 main.py를 저장 (ctrl + S) 하면 자동으로 재시작되어 변경사항이 반영됨
- 우선 시작 안했으면 시작하기
- 시작 후 문서를 변경했으면 저장하기 (Ctrl + S)
3) Swagger 문서 확인
- 브라우저에 http://127.0.0.1:8000/docs 입력 또는 새로고침
- POST / todos CreateTodos Handler (todo 생성) 클릭 > Try it out 클릭
- Request body에 다음과 같이 입력
{
"id": 4,
"contents": "test",
"is_done": true
}
- Execute 클릭 시
- 상태 코드 201이 반환됨 + 'id'값을 4로 갖고 있는 todo가 response에 반환되는 것 확인
4. PATCH 예외처리 설정 - 없는 자원 요청 (Resource Not Found)
1) 필요한 패키지 참조: fastapi의 HTTPException
# .../todos/src/main.py 내용
from fastapi import FastAPI, Body, HTTPException # 추가됨
from pydantic import BaseModel
...
2) 데코레이터에 status_code=n 명시적으로 작성
# ../todos/src/main.py
...
@app.patch("/todos/{todo_id}", status_code=200) # 추가됨
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
raise HTTPException(status_code=404, detail="ToDo Not Found") # 변경됨
...
- @app.patch("todos/{todo_id}, status_code=200)
- 정상적으로 처리될 시 상태 코드 200을 반환
- raise HTTPException(status_code=404, detail="ToDo Not Found")
- todo 값이 없을 경우 raise를 통해 exception 발생시켜줌
- 상태 코드는 404
- detail 인자를 통해 원하는 error message 표현
3) FastAPI 웹 서버 자동 재시작 (--reload 옵션 사용)
- 웹 서버 실행 후 코드 변경 시 변경사항을 SwaggerUI에 반영하기 위해선 웹 서버 재시작 (uvicorn 종료 후 다시 실행) 필수
- reload 옵션 사용 시 변화가 감지되면 자동으로 서버를 FastAPI가 재시작 됨
- 방금 수정한 main.py를 저장 (ctrl + S) 하면 자동으로 재시작되어 변경사항이 반영됨
- 우선 시작 안했으면 시작하기
- 시작 후 문서를 변경했으면 저장하기 (Ctrl + S)
3) Swagger 문서 확인
- 브라우저에 http://127.0.0.1:8000/docs 입력 또는 새로고침
- PATCH /todos/{todo_id} Update Todo Handler (todo 수정) 클릭 > Try it out 클릭
- Parameters의 todo_id에 3 (존재하는 값) 입력; Request body에 '{"is_done": true}' 입력
- Execute 클릭 시
- 상태 코드 200이 반환됨 + 'id'가 3인 todo의 'is_done' 상태가 true로 수정/업데이트된 것 확인
- Parameters의 todo_id에 7 (존재하지 않는 값) 입력; Request body에 '{"is_done": true}' 입력 Execute 클릭 시
- 상태 코드 404가 반환됨 + 'detail'에 'ToDo Not Found'라고 출력되는 것 확인
5. DELETE 예외처리 설정 - 응답할 자원 없음 및 없는 자원 요청 (Resource Not Found)
1) 데코레이터에 status_code=n 명시적으로 작성
# ../todos/src/main.py
...
@app.delete("/todos/{todo_id}", status_code=204) # 추가됨
def delete_todo_handler(todo_id: int):
todo = todo_data.pop(todo_id, None) # 변경됨
if todo: # 추가됨
return # 추가됨
raise HTTPException(status_code=404, detail="ToDo Not Found") # 추가됨
...
- @app.delete("todos/{todo_id}, status_code=204)
- 204는 삭제 처리 시 사용 → 응답할 자원이 없을 때 사용
- todo = todo_data.pop(todo_id, None)
- todo_data에서 사용자로부터 받은 todo_id (key 값)에 해당하는 value 값을 삭제한 todo_data를 todo변수에 담음
- 사용자로부터 받은 todo_id 값 (key 값)이 todo_data에 없을 경우 None을 todo 변수에 담음
- if todo: return
- 사용자로부터 받은 todo_id (key 값)이 기존 todo_data에 있다면 아무것도 반환되지 않고 상태 코드 204가 출력됨
- 기존의 todo를 삭제한 것이기에 반환값이 없어서 return을 아예 안 주거나 return을 비워서 줘도 됨
- 사용자로부터 받은 todo_id (key 값)이 기존 todo_data에 있다면 아무것도 반환되지 않고 상태 코드 204가 출력됨
- raise HTTPException(status_code=404, detail="ToDo Not Found")
- todo 값이 없을 경우 raise를 통해 exception 발생시켜줌
- 상태 코드는 404
- detail 인자를 통해 원하는 error message 표현
2) FastAPI 웹 서버 자동 재시작 (--reload 옵션 사용)
- 웹 서버 실행 후 코드 변경 시 변경사항을 SwaggerUI에 반영하기 위해선 웹 서버 재시작 (uvicorn 종료 후 다시 실행) 필수
- reload 옵션 사용 시 변화가 감지되면 자동으로 서버를 FastAPI가 재시작 됨
- 방금 수정한 main.py를 저장 (ctrl + S) 하면 자동으로 재시작되어 변경사항이 반영됨
- 우선 시작 안했으면 시작하기
- 시작 후 문서를 변경했으면 저장하기 (Ctrl + S)
3) Swagger 문서 확인
- 브라우저에 http://127.0.0.1:8000/docs 입력 또는 새로고침
- DELETE /todos/{todo_id} Delete Todo Handler (todo 삭제) 클릭 > Try it out 클릭
- Parameters의 todo_id에 3 입력 (존재하는 값) > Execute 클릭 시
- Server response를 보면
- 상태 코드 204이 반환되는 것 확인
- Response headers만 있는 것 확인
- Response body가 없다는 것은 반환값이 없다는 것을 의미 (다른 API Server Response와 비교해보기)
- Parameters의 todo_id에 7 (존재하지 않는 값) 입력 > Execute 클릭 시
- Server response를 보면
- 상태 코드 404가 되는 것 확인
- Response body에서 'detail'로 'ToDo Not Found'가 출력되는 것 확인
이때까지의 코드들:
# .../todos/src/main.py 내용
from fastapi import FastAPI, Body, HTTPException
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", status_code=200)
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}", status_code=200)
def get_todo_handler(todo_id: int):
todo = todo_data.get(todo_id)
if todo:
return todo
raise HTTPException(status_code=404, detail="ToD Not Found")
# POST Medthod 사용하여 todo 생성 API
@app.post("/todos", status_code=201)
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}", status_code=200)
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
raise HTTPException(status_code=404, detail="ToDo Not Found")
# DELETE Method 사용하여 todo 아이템 삭제 API
@app.delete("/todos/{todo_id}", status_code=204)
def delete_todo_handler(todo_id: int):
todo = todo_data.pop(todo_id, None)
if todo:
return
raise HTTPException(status_code=404, detail="ToDo Not Found")
'Web 개발 > FAST API (인프런 강의 내용)' 카테고리의 다른 글
2 실습1 MySQL 컨테이너 실행 (docker) (1) | 2024.04.24 |
---|---|
2 데이터베이스 (0) | 2024.04.24 |
1 실습5 DELETE API todo 삭제 (0) | 2024.04.17 |
1 실습4 PATCH API todo 수정 (0) | 2024.04.16 |
1 실습3 POST API todo 생성 (0) | 2024.04.15 |