상세 컨텐츠

본문 제목

[FastAPI] CRUD 구현 (Create 하는 법, routers/ 부분 중점) #1

FastAPI

by grizzly 2025. 4. 9. 13:58

본문

데이터 사이언스 팀플 관련하여 백엔드를 FastAPI로 구현하게 되어 기본적인 CRUD과정부터 마지막 구현까지 블로그를 통하여 정리하려고 한다.

 

기본적으로 CRUD를 구현하기 위한 구조는 다음과 같다.

각 역할을 정리하면

  • main.py
    • 애플리케이션 진입점
    • FastAPI 인스턴스 생성 및 설정
    • 라우터 등록
    • CORS MIDDLEWARE 설정
    • 서버 실행 시 이 파일 실행
  • database.py
    • 데이터베이스 연결 설정
    • SQLAlchemy 엔진 생성
    • Session Factory 생성
    • 데이터베이스 세션 의존성 함수 (get_db) 정의
  • models.py
    • DB table 구조 정의
    • ORM 모델 클래스 선언
    • 테이블 간의 관계 설정 (이 부분 공부 필요 - 필수)
  • schemas.py
    • Pydantic 모델 정의
    • 데이터 검증 및 직렬화 / 역직렬화 담당
    • API 요청 / 응답 모델 정의
    • 각 엔드포인트의 입력 / 출력 형식 지정
  • routers/ (directory)
    • API 엔드포인트를 기능별로 분리
    • patients.py (환자 관련 CRUD)
    • examinations.py (검사 관련 CRUD)
    • treaments.py (치료 관련 CRUD)

이때의 데이터 흐름 구조는 다음과 같다.

  1. Client 요청 -> FastAPI (API 엔드포인트로 Http 요청 전송)
  2. 라우터에서 요청 처리
    1. routers/ 디렉토리의 파일들이 각 경로에 맞는 요청 처리
    2. /patients request => patients.py 에서 처리
  3. 데이터 베이스 접근
    1. database.py의 get_db 함수 통해 db session
    2. Dependency Injection 방식 => 라우터 함수에 세션 제공
  4. 데이터 조작
    1. models.py에 정의된 ORM 모델 -> DB 조작
    2. SQLAlchemy 처리를 사용해 CRUD 작업 수행
  5. 응답 반환
    1. DB작업 결과
    2. Pydantic 모델로 변환
    3. Json 형태로 client 응답

데이터의 전체적인 흐름은 위와 같다.

이제 코드를 살펴보며 확인해보자

 

환자 생성 코드 설명

# patients.py 

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List

from database import get_db
import models, schemas

router = APIRouter(
    prefix="/patients",
    tags=["patients"],
    responses={404: {"description": "Not found"}}
)

@router.post("/", response_model=schemas.Patient)
def create_patient(patient: schemas.PatientCreate, db: Session = Depends(get_db)):
    db_patient = models.Patient(**patient.dict())
    db.add(db_patient)
    db.commit()
    db.refresh(db_patient)
    return db_patient

위 코드 중

from fastapi import APIRouter

router = APIRouter(
    prefix="/patients",
    tags=["patients"],
    responses={404: {"description": "Not found"}}
)

이 부분에 대해서 먼저 설명을 하면, router라는 변수 명으로 APIRouter 인스턴스를 생성하게 된다.

인자를 설명하게 된다면,

  1. prefix="/patients"
    1. 라우터의 모든 경로에 /patients 접두사를 추가함
    2. @router.get("/")는 실제로 /patients/에 매핑된다.
    3. @router.get("/{patient_id}"}는 /patients/{patient_id}에 매핑된다
  2. tags=["patients"]
    1. Swagger UI 문서에서 이 라우터의 모든 엔드포인트를 "patients" 태그로 그룹화 함
    2. 문서화와 API 구조화에 도움
  3. responses={404: {"description": "Not found"}}
    1. 모든 엔드포인트에 대한 기본 응답을 정의
    2. 404 오류에 대한 기본 설명을 제공

그렇다면 patient파일이 아닌 다른 파일의 router는 다음과 같이 설정하게 될 것이다.

router = APIRouter(
	prefix="/examination",
    tags=["exmaination"],
    responses={404: {"description" : "Not found"}}
)

이렇게 라우터를 정의한 후에는 main.py에 이를 FastAPI 애플리케이션에 등록해야 함.

해당 부분을 간단하게 본다면

from fastapi import FastAPI
from routers import patients

app = FastAPI(...)

app.include_router(patients.router)

이렇게 할 경우 해당 라우터의 모든 엔드포인트가 활성화된다.

 

이제 다음 코드를 한 번 살펴보자

@router.post("/", response_model=schemas.Patient)
def create_patient(patient: schemas.PatientCreate, db: Session = Depends(get_db)):
    db_patient = models.Patient(**patient.dict())
    db.add(db_patient)
    db.commit()
    db.refresh(db_patient)
    return db_patient
  1. 라우터 데코레이터
    1. @router.post("/"): HTTP POST 메서드로 기본 경로(/patients)에 요청이 들어오면 함수 실행한다.
    2. response_model=schemas.Patient: 응답이 schemas.patient 모델 형식이 반환되도록 지정
  2. 함수 정의 및 매개변수
    1. patient: schemas.PatientCrate
      1. 요청 body를 PatientCreate 스키마로 검증
      2. client가 보낸 JSON 데이터가 자동으로 PatientCreate 객체로 변환
    2. db: Session = Depends(get_db)
      1. get_db 함수를 의존성으로 주입받아 데이터베이스 세션을 획득
      2. Depends 함수를 확인하게 되면, from fastapi임을 확인할 수 있다. 따라서 FastAPI의 의존성 주입 시스템을 사용함을 알 수 있다.
  3. 환자 객체 생성
    1. db_patient = models.Patient(**patient.dict())
      1. patient.dict(): PatientCreate 객체를 딕셔너리로 변환
      2. **patient.dict()
        1. 딕셔너리 키-값 쌍을 언패킹하여 models.Patient 클래스의 생성자에 전달
        2. name=patient.name, birth_date=patient.birth_date 등과 같음 (간단)
      3. models.Patient()
        1. SQLAlchemy ORM 모델 인스턴스를 생성 (아직 DB에 저장되지 않은 상태)
  4. 데이터베이스에 추가
    1. db.add(db_patient)
      1. db.add()
        1. 생성된 Patient 객체를 데이터베이스 세션에 추가
        2. 실제 데이터베이스에 변경 적용 x
        3. 세션의 대기열에만 추가
  5. 변경 사항 커밋
    1. db.commit()
      1. 세션에 대기 중인 모든 변경 사항을 데이터베이스 실제 적용
      2. 이 시점에 INSERT SQL 쿼리가 실행되고 환자 레코드가 DB에 저장
  6. 데이터 리프레시
    1. db.refresh(db_patient)
      1. 데이터베이스에서 객체를 다시 로드
      2. 자동 생성된 ID나 기본 값이 설정된 필드(create_at, update_at 등)를 객체에 반영하기 위해 필요
  7. 결과 반환
    1. return db_patient
      1. 생성되고 리프레시된 환자 객체를 반환
      2. FastAPI는 response_model=schemas.Patient에 따라 이 객체를 schemas.Patient형식으로 변환하여 JSON응답으로 client에게 반환

이제 여기 설명이 아직 없는 부분들이 있다. database.py는 어떻게 생성하였는지, schemas.py는 어떻게 생성되었는지

해당 부분은 다음 글로 이어서 설명

관련글 더보기