dict: client = boto3.client("secretsmanager", region_name=region) secret = client.get_secret_value(SecretId=secret_name) return json.loads(secret["SecretString"]) secret = get_secret("/secret/db") DB_URL = ( f"mysql+pymysql://{secret['DB_USERNAME']}:{secret['DB_PASSWORD']}" f"@{secret['DB_HOST']}:{secret['DB_PORT']}/{secret['DB_NAME']}" ) engine = create_engine(DB_URL, pool_pre_ping=True) SessionLocal = sessionmaker(bind=engine) class Base(DeclarativeBase): pass # ── 모델 ───────────────────────────────────────────────── "> dict: client = boto3.client("secretsmanager", region_name=region) secret = client.get_secret_value(SecretId=secret_name) return json.loads(secret["SecretString"]) secret = get_secret("/secret/db") DB_URL = ( f"mysql+pymysql://{secret['DB_USERNAME']}:{secret['DB_PASSWORD']}" f"@{secret['DB_HOST']}:{secret['DB_PORT']}/{secret['DB_NAME']}" ) engine = create_engine(DB_URL, pool_pre_ping=True) SessionLocal = sessionmaker(bind=engine) class Base(DeclarativeBase): pass # ── 모델 ───────────────────────────────────────────────── "> dict: client = boto3.client("secretsmanager", region_name=region) secret = client.get_secret_value(SecretId=secret_name) return json.loads(secret["SecretString"]) secret = get_secret("/secret/db") DB_URL = ( f"mysql+pymysql://{secret['DB_USERNAME']}:{secret['DB_PASSWORD']}" f"@{secret['DB_HOST']}:{secret['DB_PORT']}/{secret['DB_NAME']}" ) engine = create_engine(DB_URL, pool_pre_ping=True) SessionLocal = sessionmaker(bind=engine) class Base(DeclarativeBase): pass # ── 모델 ───────────────────────────────────────────────── ">
from fastapi import FastAPI, HTTPException, Depends
from sqlalchemy import create_engine, Column, Integer, String, Boolean, text
from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker
from pydantic import BaseModel, EmailStr
from passlib.context import CryptContext
from typing import Optional
import os, json, boto3

# ── AWS Secrets Manager에서 DB 정보 로드 ─────────────────
def get_secret(secret_name: str, region: str = "ap-northeast-2") -> dict:
    client = boto3.client("secretsmanager", region_name=region)
    secret = client.get_secret_value(SecretId=secret_name)
    return json.loads(secret["SecretString"])

secret = get_secret("/secret/db")

DB_URL = (
    f"mysql+pymysql://{secret['DB_USERNAME']}:{secret['DB_PASSWORD']}"
    f"@{secret['DB_HOST']}:{secret['DB_PORT']}/{secret['DB_NAME']}"
)
engine = create_engine(DB_URL, pool_pre_ping=True)
SessionLocal = sessionmaker(bind=engine)

class Base(DeclarativeBase): pass

# ── 모델 ─────────────────────────────────────────────────
class User(Base):
    __tablename__ = "users"
    id       = Column(Integer, primary_key=True, autoincrement=True)
    email    = Column(String(255), unique=True, nullable=False)
    name     = Column(String(100), nullable=False)
    password = Column(String(255), nullable=False)
    active   = Column(Boolean, default=True)

Base.metadata.create_all(engine)

# ── 스키마 ────────────────────────────────────────────────
class UserCreate(BaseModel):
    email:    EmailStr
    name:     str
    password: str

class UserResponse(BaseModel):
    id:     int
    email:  str
    name:   str
    active: bool
    model_config = {"from_attributes": True}

# ── 앱 & 유틸 ─────────────────────────────────────────────
app = FastAPI(title="WorldPay User API")
pwd = CryptContext(schemes=["bcrypt"])

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# ── 엔드포인트 ────────────────────────────────────────────
@app.get("/health")
def health():
    return {"status": "ok"}

@app.get("/health/db")
def health_db(db: Session = Depends(get_db)):
    try:
        db.execute(text("SELECT 1"))
        return {"status": "ok", "db": "connected"}
    except Exception as e:
        return {"status": "error", "db": str(e)}

@app.post("/users", response_model=UserResponse, status_code=201)
def create_user(body: UserCreate, db: Session = Depends(get_db)):
    if db.query(User).filter(User.email == body.email).first():
        raise HTTPException(400, "이미 존재하는 이메일입니다.")
    user = User(email=body.email, name=body.name, password=pwd.hash(body.password))
    db.add(user); db.commit(); db.refresh(user)
    return user

@app.get("/users", response_model=list[UserResponse])
def list_users(db: Session = Depends(get_db)):
    return db.query(User).all()

@app.get("/users/{user_id}", response_model=UserResponse)
def get_user(user_id: int, db: Session = Depends(get_db)):
    user = db.get(User, user_id)
    if not user: raise HTTPException(404, "유저를 찾을 수 없습니다.")
    return user

@app.patch("/users/{user_id}", response_model=UserResponse)
def update_user(user_id: int, name: Optional[str] = None, active: Optional[bool] = None, db: Session = Depends(get_db)):
    user = db.get(User, user_id)
    if not user: raise HTTPException(404, "유저를 찾을 수 없습니다.")
    if name   is not None: user.name   = name
    if active is not None: user.active = active
    db.commit(); db.refresh(user)
    return user

@app.delete("/users/{user_id}")
def delete_user(user_id: int, db: Session = Depends(get_db)):
    user = db.get(User, user_id)
    if not user: raise HTTPException(404, "유저를 찾을 수 없습니다.")
    db.delete(user); db.commit()
    return {"message": f"유저 {user_id} 삭제 완료"}