서버에서의 Swift

발행: (2025년 12월 25일 오전 02:47 GMT+9)
4 min read
원문: Dev.to

Source: Dev.to

Cover image for Swift On Server's

Vapor Drawing Backend – 프로젝트 개요

Vapor (Swift)로 구축된 협업 노트 작성 백엔드로, 실시간 협업, 인증, 그리고 drawing‑strokes 영속성을 지원합니다.

기술 스택

  • 프레임워크: Vapor 4.115.0
  • 데이터베이스: MongoDB with Fluent ORM
  • 인증: JWT (JSON Web Tokens)
  • 실시간: WebSockets
  • 언어: Swift 6.0

Source:

구현된 기능

1. 인증 시스템

JWT 기반 인증으로 사용자 등록 및 로그인 기능을 제공합니다.

// User model with email and password
final class User: Model, Content, Authenticatable {
    static let schema = "users"

    @ID(key: .id)
    var id: UUID?

    @Field(key: "email")
    var email: String

    @Field(key: "password_hash")
    var passwordHash: String
}

엔드포인트

  • POST /api/v1/auth/register – 새 사용자 등록
  • POST /api/v1/auth/login – 사용자 로그인
  • GET /api/v1/auth/me – 현재 사용자 조회 (보호된 라우트)

2. JWT 미들웨어

JWT 토큰을 검증하고 라우트를 보호하는 커스텀 미들웨어입니다.

struct AuthMiddleware: AsyncMiddleware {
    func respond(to request: Request, chainingTo next: any AsyncResponder) async throws -> Response {
        let payload: UserToken = try await request.jwt.verify(as: UserToken.self)

        guard let user = try await User.find(payload.userID, on: request.db) else {
            throw Abort(.unauthorized, reason: "User not found")
        }
        request.auth.login(user)

        return try await next.respond(to: request)
    }
}

3. Fluent ORM을 이용한 MongoDB

FluentMongoDriver를 사용한 데이터베이스 설정과 자동 마이그레이션을 제공합니다.

// Configure MongoDB
try app.databases.use(
    .mongo(
        connectionString: Environment.get("MONGODB_URI") ?? "mongodb://localhost:27017"
    ),
    as: .mongo
)

// Run migrations
app.migrations.add(User.Migration())
app.migrations.add(NotesModel.Migration())

4. 노트 관리

그리기 스트로크 지원을 포함한 노트에 대한 전체 CRUD 작업을 제공합니다.

final class NotesModel: Model, Content {
    @Field(key: "title")
    var title: String

    @Field(key: "strokes")
    var strokes: [DrawingStroke]

    @Parent(key: "user_id")
    var user: User
}

struct DrawingStroke: Codable {
    let points: [DrawingPoint]
    let color: DrawingColor
    let width: Double
    let timestamp: Date
}

엔드포인트

  • POST /api/v1/notes – 노트 생성
  • GET /api/v1/notes – 모든 노트 조회
  • GET /api/v1/notes/get/:id – 단일 노트 조회
  • PUT /api/v1/notes/:id – 노트 업데이트
  • DELETE /api/v1/notes/:id – 노트 삭제

5. 실시간 WebSocket 협업

노트 세션 관리를 위한 WebSocket 매니저로 협업 편집을 지원합니다.

final class WebSocketManager {
    private var connections: [UUID: WebSocket] = [:]
    private var noteCollaborators: [UUID: Set] = [:]

    func joinNoteSession(noteID: UUID, userID: UUID)
    func leaveNoteSession(noteID: UUID, userID: UUID)
    func broadcastToNote(noteID: UUID, message: String, excludeUserID: UUID?)
}

WebSocket 기능

  • 노트 세션 참여/탈퇴
  • 실시간 스트로크 업데이트
  • 모든 협업자에게 방송 (보낸 사람 제외)
  • 개인 메시징

엔드포인트: WS /api/v1/auth/handleInvite (보호된 라우트)

6. 노트 공유

JWT 토큰을 이용해 외부 사용자와 노트를 공유합니다.

// Share token endpoint
GET /api/v1/notes/shared/:shareToken

// Verifies JWT token and returns note
let payload = try await req.jwt.verify(shareToken, as: ShareTokenPayload.self)

프로젝트 구조

Sources/NoterPlayBackend/
├── Controllers/
│   ├── AuthenticationController.swift
│   ├── NotesController.swift
│   └── InviteController.swift
├── Middleware/
│   └── AuthMiddleware.swift
├── Models/
│   ├── User.swift
│   ├── NotesModel.swift
│   ├── UserToken.swift
│   ├── ShareTokenPayload.swift
│   └── InviteModel.swift
├── WSManager/
│   └── WebSocketManager.swift
├── configure.swift
└── routes.swift

시작하기

# Install dependencies
swift package resolve

# Run the server
swift run

# With Docker
docker-compose up

Vapor Drawing Github

Vapor와 Swift를 사용해 ❤️로 만들었습니다.

Back to Blog

관련 글

더 보기 »

Swift #28: Foundation

!David Goyeshttps://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fu...

Combine #13: 자원 관리

share 및 multicast_: share 대부분의 Combine Publishers는 struct이며 파이프라인만을 기술하고, 공유 상태를 저장하지 않습니다. 공유 상태가 생성되지 않습니다.