[FastAPI] 4일차 - 예외 처리와 CRUD API 완성

빛나김·2026년 1월 15일

Fast API

목록 보기
4/7

📢 4일차 학습 내용 한눈에 보기

오늘은 FastAPI의 핵심 기능인 CRUD API를 완성하고, 데이터베이스 연동을 위한 SQLAlchemy를 학습했습니다!

  • HTTPException으로 예외 처리 - 잘못된 요청에 대한 적절한 에러 반환
  • CRUD API 구현 - Create, Read, Update, Delete 전체 구현
  • PUT vs PATCH - 전체 교체와 부분 수정의 차이
  • SQLAlchemy 소개 - ORM으로 DB 다루기
  • Engine, Session, Base - DB 연결의 핵심 개념

1️⃣ HTTPException으로 예외 처리


왜 필요할까요?

API를 만들 때, 항상 정상적인 경우만 있는 건 아니에요. 예를 들어:

  • 사용자가 빈 문자열을 보낼 때
  • 존재하지 않는 아이디를 요청할 때

이럴 때 HTTPException을 사용하면 적절한 HTTP 상태 코드와 메시지를 반환할 수 있어요!

코드로 보기

from fastapi import FastAPI, HTTPException

app = FastAPI()

@app.post("/hello")
def hello(body: HelloRequest):
    # 빈 문자연이라면 400 Bad Request 발생
    if not body.name.strip():
        raise HTTPException(
            status_code=400,
            detail="이름을 입력해주세요."
        )
    
    return {"message": f"안녕하세요, {body.name}님!"}

핵심 포인트

  • return 대신 raise 사용: 예외를 발생시켜서 함수를 즉시 종료
  • status_code: 400(Bad Request), 404(Not Found) 등 적절한 코드 사용
  • detail: 구체적인 에러 메시지

2️⃣ CRUD API 구현

CRUD란?

  • Create (생성) - POST
  • Read (조회) - GET
  • Update (수정) - PUT / PATCH
  • Delete (삭제) - DELETE

기본적인 데이터 처리의 4가지 기능을 모두 구현해봅시다!

1. Create - 데이터 생성 (POST)

from typing import List
from pydantic import BaseModel

# 임시 DB (메모리에 저장)
items = [
    {"id": 1, "name": "Apple", "price": 100},
    {"id": 2, "name": "Banana", "price": 80},
]

class ItemCreateRequest(BaseModel):
    name: str
    price: int

class ItemResponse(BaseModel):
    id: int
    name: str
    price: int

@app.post("/items", response_model=ItemResponse, status_code=201)
def create_item(item_request: ItemCreateRequest):
    new_id = len(items) + 1
    new_item = {
        "id": new_id,
        "name": item_request.name,
        "price": item_request.price,
    }
    items.append(new_item)
    return new_item

포인트:

  • status_code=201: Create 성공시 201 Created 반환
  • len(items) + 1: 간단한 ID 자동 증가

2. Read All - 전체 조회 (GET)

@app.get("/items", response_model=List[ItemResponse])
def get_items():
    return items

포인트:

  • List[ItemResponse]: 여러 개의 Item을 반환할 때는 List 타입

3. Read One - 특정 데이터 조회 (GET)

@app.get("/items/{item_id}", response_model=ItemResponse)
def get_item(item_id: int):
    for item in items:
        if item["id"] == item_id:
            return item
    
    # 찾지 못하면 404 에러
    raise HTTPException(status_code=404, detail="Item not found")

포인트:

  • Path Parameter로 item_id 받기
  • 찾지 못하면 404 발생

4. Update - 데이터 수정 (PATCH)

from typing import Optional

class ItemUpdateRequest(BaseModel):
    name: Optional[str] = None
    price: Optional[int] = None

@app.patch("/items/{item_id}", response_model=ItemResponse)
def update_item(item_id: int, item_request: ItemUpdateRequest):
    for item in items:
        if item["id"] == item_id:
            # None이 아닌 값만 업데이트
            if item_request.name is not None:
                item["name"] = item_request.name
            if item_request.price is not None:
                item["price"] = item_request.price
            return item
    
    raise HTTPException(status_code=404, detail="Item not found")

PUT vs PATCH:

  • PUT: 전체를 교체 (모든 필드 필수)
  • PATCH: 부분만 수정 (Optional 사용)

5. Delete - 데이터 삭제 (DELETE)

from fastapi import status

@app.delete("/items/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_item(item_id: int):
    for item in items:
        if item["id"] == item_id:
            items.remove(item)
            return  # 204는 body가 없으므로 return만
    
    raise HTTPException(status_code=404, detail="Item not found")

포인트:

  • 204 No Content: 삭제 성공시 body 없이 반환
  • items.remove(item): 리스트에서 제거
  • return만 사용: 204는 별도의 데이터 반환 불필요

3️⃣ ORM과 SQLAlchemy 소개

메모리 DB의 문제점

지금까지는 items = [] 같은 리스트에 데이터를 저장했어요. 하지만 이 방식은:

  • 서버 재시작하면 모든 데이터가 사라짐
  • 대량의 데이터 처리가 어려움

데이터베이스(DB)를 사용해야 합니다!

ORM이란?

ORM (Object-Relational Mapping)은 Python 객체와 DB 테이블을 연결해주는 기술이에요.

  • SQL 없이 Python 코드로 DB 조작
  • 테이블 row → Python 객체
  • 테이블 column → 객체 속성

예시:

# SQL: SELECT * FROM items
# ORM:
db.query(Item).all()

SQLAlchemy는?

Python에서 가장 많이 사용되는 ORM 라이브러리에요!

pip install sqlalchemy

4️⃣ SQLAlchemy 핵심 3요소

1. Engine - DB 연결

Engine은 DB와의 연결을 관리하는 객체에요.

# connection.py
from sqlalchemy import create_engine

# SQLite DB 파일 경로
DATABASE_URL = "sqlite:///./test.db"

# Engine 생성
engine = create_engine(DATABASE_URL)

포인트:

  • SQLite: 파일 기반 DB (간단한 테스트용)
  • create_engine: DB 연결 설정

2. Session - DB 작업 세션

Session은 DB와 상호작용하는 공간이에요. 조회, 삽입, 수정, 삭제를 모두 Session을 통해 수행해요.

# connection.py
from sqlalchemy.orm import sessionmaker

# Session 클래스 생성
SessionLocal = sessionmaker(
    autocommit=False,
    autoflush=False,
    bind=engine
)

포인트:

  • sessionmaker: Session 생성 팩토리
  • bind=engine: 어떤 DB와 연결할지 지정

3. Base - ORM 모델 기반 클래스

Base는 모든 ORM 모델이 상속받을 기반 클래스예요.

# orm.py
from sqlalchemy.orm import declarative_base

Base = declarative_base()

# 이제 Item 모델을 만들 때
class Item(Base):
    __tablename__ = "items"
    # ...

포인트:

  • declarative_base(): ORM 모델의 기반 제공
  • Base를 상속받으면 SQLAlchemy가 테이블로 인식

📝 요약 정리

오늘 배운 내용

  1. HTTPException: API 예외 처리의 핵심

    • raise HTTPException(status_code=..., detail=...)
    • 400, 404 등 적절한 상태 코드 사용
  2. CRUD API 전체 구현

    • CREATE: POST + 201 Created
    • READ: GET (All + One)
    • UPDATE: PATCH + Optional 필드
    • DELETE: DELETE + 204 No Content
  3. PUT vs PATCH

    • PUT: 전체 교체
    • PATCH: 부분 수정
  4. ORM 개념

    • SQL 없이 Python으로 DB 조작
    • 객체 ↔️ 테이블 매핑
  5. SQLAlchemy 기초

    • Engine: DB 연결
    • Session: DB 작업 공간
    • Base: ORM 모델의 기반

다음 단계는?

다음 시간에는:

  • ✅ SQLAlchemy로 실제 DB 모델 만들기
  • ✅ CRUD API를 DB와 연동하기
  • ✅ 마이그레이션 (DB 스키마 관리)

를 학습할 거예요!


참고

🚀 CRUD API 마스터 완료! 이제 본격적인 백엔드 개발의 기초를 다졌어요!

profile
함께 성장

0개의 댓글