소프트웨어 개발/프론트엔드

🚀 [Swagger TypeScript API 활용] 3강. OpenAPI 스펙 작성 & 클라이언트 코드 생성 (FastAPI Todo 예제)

브라더댄 2025. 1. 27. 01:18
728x90
반응형
SMALL

이번 강의에서는 FastAPI로 간단한 Todo 리스트 백엔드를 구축하고, 해당 API의 OpenAPI 스펙을 통해 swagger-typescript-api로 클라이언트 코드를 자동 생성하는 전 과정을 살펴봅니다. 이를 통해 실제 프로젝트와 유사한 상황을 체험해볼 수 있을 것입니다.


1. FastAPI로 간단한 Todo 백엔드 구성하기

1) FastAPI 설치

먼저 Python 환경에서 FastAPI와 Uvicorn을 설치해줍니다.

pip install fastapi uvicorn sqlalchemy

2) 프로젝트 구조 예시

fastapi-todo/
├── main.py
└── requirements.txt
  • main.py에 라우팅, 모델, API 로직을 정의합니다.

3) Todo 모델 및 API 라우팅

main.py:

# backend/main.py
from typing import Annotated, Optional, List
from fastapi import FastAPI, HTTPException, Depends, Query
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from sqlmodel import Field, Session, SQLModel, create_engine, select

app = FastAPI(
    title="Todo API",
    description="A simple Todo list application using FastAPI",
    version="1.0.0"
)

# CORS 구성
origins = [
    "http://localhost:5173",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 시작시 데이터베이스 생성
@app.on_event("startup")
def on_startup():
    create_db_and_tables()

# 데이터베이스 엔진 생성
sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"
connect_args = {"check_same_thread": False}

engine = create_engine(sqlite_url, connect_args=connect_args)

# 데이터베이스 생성함수
def create_db_and_tables():
    SQLModel.metadata.create_all(engine)

# 데이터베이스 세션 제공
def get_session():
    with Session(engine) as session:
        yield session

SessionDep = Annotated[Session, Depends(get_session)]

# SQL Model
class TodoItem(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    title: str = Field(index=True)
    description: Optional[str] = Field(default=None)
    done: bool = False

# API 엔드포인트 (CRUD)
@app.get("/todos", response_model=List[TodoItem])
def get_todos(
    session: SessionDep,
    offset: int=0,
    limit: Annotated[int, Query(le=100)] = 100
) -> list[TodoItem]:
    todos = session.exec(select(TodoItem).offset(offset).limit(limit)).all()
    return todos

@app.post("/todos", response_model=TodoItem)
def create_todo(session: SessionDep, todo: TodoItem, ) -> TodoItem:
    session.add(todo)
    session.commit()
    session.refresh(todo)
    return todo

@app.get("/todos/{todo_id}", response_model=TodoItem)
def get_todo_by_id(session: SessionDep, todo_id: int):
    item = session.get(TodoItem, id)
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")
    return item

@app.put("/todos/{todo_id}", response_model=TodoItem)
def update_todo(session: SessionDep, todo_id: int, todo_in: TodoItem):
    todo = session.get(TodoItem, todo_id)
    if not todo:
        raise HTTPException(status_code=404, detail="Item not found")
    update_todo = todo_in.model_dump(exclude_unset=True)
    todo.sqlmodel_update(update_todo)
    session.add(todo)
    session.commit()
    session.refresh(todo)
    return todo

@app.delete("/todos/{todo_id}")
def delete_todo(session: SessionDep, todo_id: int):
    todo = session.get(TodoItem, todo_id)
    if not todo:
        raise HTTPException(status_code=404, detail="Item not found")
    session.delete(todo)
    session.commit()
    return {"message": "Item deleted successfully"}
  • TodoItem: Pydantic 모델을 사용해 Todo 데이터 구조를 명세합니다.
  • 엔드포인트:
    • GET /todos: 전체 Todo 목록 조회
    • POST /todos: Todo 생성
    • GET /todos/{todo_id}: 단일 Todo 조회
    • PUT /todos/{todo_id}: Todo 수정
    • DELETE /todos/{todo_id}: Todo 삭제

4) 서버 실행

uvicorn main:app --reload
  • 기본 포트: http://127.0.0.1:8000
  • API 문서: http://127.0.0.1:8000/docs
  • OpenAPI 스펙: http://127.0.0.1:8000/openapi.json

2. OpenAPI 스펙 확인하기

FastAPI는 자동으로 /openapi.json 엔드포인트를 제공합니다. 이 엔드포인트가 **swagger-typescript-api**에서 참조할 OpenAPI 스펙이 됩니다.

  • 예: http://127.0.0.1:8000/openapi.json
  • 구조: FastAPI가 작성한 엔드포인트 정보를 바탕으로 OpenAPI 3.0.2 형식의 JSON을 자동 생성합니다.
  • 활용: 이를 그대로 swagger-typescript-api 도구에 넘겨, 클라이언트를 자동 생성할 수 있습니다.

 

3. swagger-typescript-api를 이용한 클라이언트 코드 생성

1) 개발 환경

  • Node.js, npm(or Yarn) 설치되어 있다고 가정합니다.
  • 원하는 폴더에서 npm init -y 등을 통해 패키지 초기화 후, swagger-typescript-api를 설치합니다.
npm install swagger-typescript-api --save-dev

2) 명령어 실행

FastAPI 서버가 동작 중인 상태에서, OpenAPI JSON URL을 --path 옵션에 전달해줍니다.

npx swagger-typescript-api \
  --path "http://127.0.0.1:8000/openapi.json" \
  --output "./src/generated" \
  --name "ApiClient.ts"
  • --path: 스펙 파일(또는 URL) 경로 지정. 여기서는 FastAPI가 제공하는 URL을 사용합니다.
  • --output: 생성된 파일 저장 폴더 (예: ./generated)
  • --name: 결과 파일명 (예: TodoApiClient.ts)

 

4. 생성된 클라이언트 코드 살펴보기

명령어 실행이 완료되면 ./generated/TodoApiClient.ts 파일이 생성됩니다. 내부를 확인해보면, 대략 다음과 같은 요소들이 자동으로 포함됩니다.

/* eslint-disable */
/* tslint:disable */
/*
 * ---------------------------------------------------------------
 * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API        ##
 * ##                                                           ##
 * ## AUTHOR: acacode                                           ##
 * ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
 * ---------------------------------------------------------------
 */

/** HTTPValidationError */
export interface HTTPValidationError {
  /** Detail */
  detail?: ValidationError[];
}

/** TodoItem */
export interface TodoItem {
  /** Id */
  id: number;
  /** Title */
  title: string;
  /** Description */
  description?: string | null;
  /**
   * Done
   * @default false
   */
  done?: boolean;
}

// 이하 생략
  • 인터페이스(Interface) 정의: TodoItem과 같은 Pydantic 모델을 그대로 TypeScript 타입으로 변환.
  • 메서드: 각 경로(GET /todos, POST /todos, 등)에 해당하는 함수들이 자동 생성.

Tip: axios 옵션을 사용하면 Axios 기반 코드로 생성되며, Fetch API 기반으로도 생성 가능합니다. 프로젝트 스타일에 맞춰 사용하세요.


6. 마무리 & 정리

  1. FastAPI를 통해 OpenAPI 스펙을 손쉽게 얻을 수 있습니다.
  2. **swagger-typescript-api**는 이 스펙을 활용하여 자동화된 TypeScript 클라이언트 코드를 생성해주며, 타입 안정성생산성을 크게 높여줍니다.
  3. Todo 리스트와 같은 간단한 예제에서도 충분히 체감할 수 있는 장점이 있으니, 실제 업무에 적용하면 더 큰 효과를 얻을 수 있습니다.

다음 4강에서는 React(Vite) 프로젝트와 연동하여 화면에 데이터를 표시하는 과정과, 협업 효율을 높일 수 있는 베스트 프랙티스들을 살펴보겠습니다.

728x90
반응형
LIST