Post

Realworld with FastAPI

Realworld by FastAPI + layerd Architecture, TDD 도입시도

Realworld with FastAPI

시스템 아키텍처 및 API 문서


전체 아키텍처

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
┌─────────────────────────────────────────────────────────────────────────────┐
│                              FastAPI Application                             │
│                                  (main.py)                                   │
└─────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                              API Layer                                    │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐          │
│  │  auth   │  │ article │  │ comment │  │ profile │  │   tag   │          │
│  │ router  │  │ router  │  │ router  │  │ router  │  │ router  │          │
│  └────┬────┘  └────┬────┘  └────┬────┘  └────┬────┘  └────┬────┘          │
└───────┼────────────┼────────────┼────────────┼────────────┼─────────────────┘
        │            │            │            │            │
        ▼            ▼            ▼            ▼            ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                          🔧 Core Layer (dependencies.py)                     │
│                                                                              │
│   ┌──────────────────┐    ┌──────────────────┐    ┌──────────────────┐     │
│   │ get_current_user │    │  get_*_service   │    │ get_*_repository │     │
│   │   (JWT 인증)      │    │ (서비스 주입)     │    │ (레포지토리 주입)  │     │
│   └──────────────────┘    └──────────────────┘    └──────────────────┘     │
│                                                                              │
│   ┌──────────────────────────────────────────────────────────────────┐     │
│   │                    security.py (Argon2 + JWT)                     │     │
│   │  • hash_password()  • verify_password()  • create/verify_token() │     │
│   └──────────────────────────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                           Service Layer                                   │
│  ┌───────────────┐  ┌─────────────────┐  ┌─────────────────┐               │
│  │  UserService  │  │ ArticleService  │  │ CommentService  │               │
│  └───────────────┘  └─────────────────┘  └─────────────────┘               │
│  ┌─────────────────┐                                                        │
│  │ ProfileService  │  ← 비즈니스 로직 처리                                    │
│  └─────────────────┘                                                        │
└─────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                         Repository Layer                                  │
│                      (interfaces.py로 추상화)                                 │
│  ┌────────────────┐  ┌────────────────┐  ┌────────────────┐                │
│  │ UserRepository │  │ArticleRepository│ │CommentRepository│               │
│  └────────────────┘  └────────────────┘  └────────────────┘                │
│  ┌────────────────┐  ┌────────────────┐  ┌────────────────┐                │
│  │ TagRepository  │  │FavoriteRepository│ │FollowRepository│               │
│  └────────────────┘  └────────────────┘  └────────────────┘                │
└─────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                           Model Layer                                     │
│  ┌──────┐  ┌─────────┐  ┌─────────┐  ┌──────┐  ┌────────┐  ┌──────┐       │
│  │ User │  │ Article │  │ Comment │  │  Tag │  │Favorite│  │Follow│       │
│  └──────┘  └─────────┘  └─────────┘  └──────┘  └────────┘  └──────┘       │
└─────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                         Database (SQLite + SQLModel)                      │
└─────────────────────────────────────────────────────────────────────────────┘

API 엔드포인트

Auth (인증)

MethodEndpoint설명인증
POST/users회원가입
POST/users/login로그인
GET/user내 정보 조회
PUT/user내 정보 수정

요청/응답 예시:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// POST /users (회원가입)
{
  "user": {
    "email": "user@example.com",
    "password": "password123",
    "username": "user1"
  }
}

// 응답
{
  "user": {
    "email": "user@example.com",
    "username": "user1",
    "token": "jwt.token.here"
  }
}

Articles (게시글)

MethodEndpoint설명인증
GET/articles게시글 목록 조회
GET/articles?author={username}작성자로 필터링
GET/articles?tag={tag}태그로 필터링
GET/articles?favorited={username}좋아요한 글 필터링
POST/articles게시글 작성
GET/articles/{slug}게시글 상세 조회
PUT/articles/{slug}게시글 수정
DELETE/articles/{slug}게시글 삭제
POST/articles/{slug}/favorite좋아요
DELETE/articles/{slug}/favorite좋아요 취소

요청/응답 예시:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// POST /articles (게시글 작성)
{
  "article": {
    "title": "How to train your dragon",
    "description": "Ever wonder how?",
    "body": "It takes a Jacobian",
    "tagList": ["dragons", "training"]
  }
}

// 응답
{
  "article": {
    "slug": "how-to-train-your-dragon",
    "title": "How to train your dragon",
    "description": "Ever wonder how?",
    "body": "It takes a Jacobian",
    "tagList": ["dragons", "training"],
    "favorited": false,
    "favoritesCount": 0,
    "author": { ... }
  }
}

Comments (댓글)

MethodEndpoint설명인증
GET/articles/{slug}/comments댓글 목록 조회
POST/articles/{slug}/comments댓글 작성
DELETE/articles/{slug}/comments/{id}댓글 삭제

요청/응답 예시:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// POST /articles/{slug}/comments
{
  "comment": {
    "body": "Great article!"
  }
}

// 응답
{
  "comment": {
    "id": 1,
    "body": "Great article!",
    "author": { ... }
  }
}

Profiles (프로필)

MethodEndpoint설명인증
GET/profiles/{username}프로필 조회
POST/profiles/{username}/follow팔로우
DELETE/profiles/{username}/follow언팔로우

응답 예시:

1
2
3
4
5
6
7
8
9
// GET /profiles/{username}
{
  "profile": {
    "username": "jake",
    "bio": "I work at statefarm",
    "image": "https://...",
    "following": false
  }
}

Tags (태그)

MethodEndpoint설명인증
GET/tags태그 목록 조회

응답 예시:

1
2
3
4
// GET /tags
{
  "tags": ["reactjs", "angularjs", "dragons"]
}

요청 흐름도 (예: 게시글 작성)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
┌──────────┐   POST /articles    ┌──────────┐
│  Client  │ ─────────────────▶  │ article  │
│          │   + JWT Token       │  router  │
└──────────┘                     └────┬─────┘
                                      │
               ┌──────────────────────┼──────────────────────┐
               │                      ▼                      │
               │   ┌─────────────────────────────────────┐   │
               │   │      get_current_user()             │   │
               │   │   JWT 검증 → User 객체 반환           │   │
               │   └─────────────────────────────────────┘   │
               │                      │                      │
               │   ┌──────────────────▼──────────────────┐   │
               │   │         ArticleService              │   │
               │   │         create_article()            │   │
               │   │   • slug 생성                        │   │
               │   │   • 태그 처리                        │   │
               │   │   • 응답 빌드                        │   │
               │   └──────────────────┬──────────────────┘   │
               │                      │                      │
               │   ┌──────────────────▼──────────────────┐   │
               │   │       ArticleRepository             │   │
               │   │       TagRepository                 │   │
               │   │       (DB 저장)                      │   │
               │   └──────────────────┬──────────────────┘   │
               │                      │                      │
               └──────────────────────┼──────────────────────┘
                                      │
┌──────────┐   { article: {...} }     │
│  Client  │ ◀────────────────────────┘
│          │
└──────────┘

디렉토리 구조

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
app/
├── main.py              # 앱 진입점, 라우터 등록
├── api/                 # ** API 엔드포인트
│   ├── auth.py          # POST /users, /users/login, GET/PUT /user
│   ├── article.py       # /articles CRUD, /favorite
│   ├── comment.py       # /articles/{slug}/comments
│   ├── profile.py       # /profiles/{username}, /follow
│   └── tag.py           # GET /tags
├── core/                # ** 핵심 설정
│   ├── database.py      # DB 연결 (SQLite + SQLModel)
│   ├── dependencies.py  # DI 컨테이너 (의존성 주입)
│   └── security.py      # 인증 (Argon2 + JWT)
├── services/            # ** 비즈니스 로직
├── repositories/        # ** 데이터 접근
├── models/              # ** DB 모델
└── schemas/             # ** 요청/응답 스키마

아키텍처 특징

특징설명
레이어드 아키텍처API → Service → Repository → Model
의존성 역전 (DIP)interfaces.py로 Repository 추상화
의존성 주입 (DI)FastAPI Depends()를 통한 자동 주입
보안Argon2 해싱 + JWT 인증
DBSQLite + SQLModel (ORM)
테스트TDD지향, 테스트 목록 작성 후 기능 개발
This post is licensed under CC BY 4.0 by the author.