Fitz 소개: HTTP·Postgres·JWT·WebSockets를 문법에 포함한 언어

발행: (2026년 6월 6일 PM 08:07 GMT+9)
7 분 소요
원문: Dev.to

Source: Dev.to

Fitz는 Rust로 만든 새로운 프로그래밍 언어이며, 점진적으로 타입을 지정하는 컴파일러를 갖추고 있습니다. 핵심 아이디어는 FastAPI + SQLAlchemy + python‑jose + Celery + Pydantic + uvicorn + Alembic + typer 를 파이썬 위에 겹쳐 쓰는 대신, 각각이 해결하는 문제들을 언어 자체에 내장한다는 것입니다: HTTP 라우팅, OpenAPI/AsyncAPI 자동 생성, async/await, JWT 인증, 비밀번호 해싱, 순수 Rust Postgres 드라이버를 이용한 ORM, 스키마 마이그레이션, WebSocket, cron, 백그라운드 작업, CLI 빌더, 헬스체크, OpenTelemetry 기반 관측, 불투명 타입으로 다루는 시크릿, 그리고 fitz deploy 오케스트레이터까지. 하나의 바이너리. 핵심 스택에 외부 의존성 전혀 없음. Repo: github.com/Thegreekman76/fitz · Docs: thegreekman76.github.io/fitz

type User { id: Int, email: Str, name: Str, role: Str }
type Credentials { email: Str, password: Str }
type LoginResponse { token: Str }

let SECRET = "demo-secret-change-me-in-prod"
let ADA_HASH = hash.password("secret-ada-123")

@auth_provider
fn check_token(headers: Map) -> Result {
    let auth: Str = match headers.get("authorization") {
        Ok(v) => v,
        Err(_) => return Err("missing Authorization header"),
    }
    let parts = auth.split(" ")
    if (parts.len() != 2 or parts[0] != "Bearer") {
        return Err("expected 'Bearer '")
    }
    let claims = jwt.decode(parts[1], SECRET)?
    return find_user(claims["email"])
}

@post("/login")
fn login(creds: Credentials) -> LoginResponse {
    let user: User = match find_user(creds.email) {
        Ok(u) => u,
        Err(_) => return 401 { "error": "invalid credentials" },
    }
    if (not hash.verify(creds.password, ADA_HASH)) {
        return 401 { "error": "invalid credentials" }
    }
    let claims = { "email": user.email, "role": user.role }
    return LoginResponse { token: jwt.encode(claims, SECRET) }
}

@authenticated
@get("/me")
fn me(user: User) -> User => user

@admin
@get("/admin/users")
fn admin_list(user: User) -> List { ... }

이 코드가 단 하나의 import도, 외부 의존성도 없이 수행하는 일

  • 포트 43928에서 HTTP 서버를 시작합니다.
  • /openapi.json 에서 OpenAPI 3.1 스키마를 자동으로 생성합니다.
  • /docs 에서는 Scalar UI를 자동으로 제공하고, 작동하는 “Authorize” 버튼을 포함합니다.
  • JWT 토큰을 서명·검증합니다 (HS256/384/512 지원).
  • Argon2id 로 비밀번호를 해시합니다 (OWASP 권고, bcrypt 대신).
  • 모든 @authenticated / @admin 핸들러에 @auth_provider 가 선언됐는지, 제공자가 올바른 User 타입을 반환하는지, @admin 핸들러가 Userrole: Str 필드를 가지고 있는지를 정적으로 검증합니다.
  • fitz build 로 단일 네이티브 바이너리를 만들 수 있으며, fitz run 과 비트‑단위로 동일합니다.

인증, 해시, JWT, bearerAuth 보안 스키마가 포함된 OpenAPI, 401/403 응답 등 모든 기능이 fitz 바이너리 자체에 들어 있습니다. requirements.txt, package.json, Cargo.toml 같은 파일이 사용자에게는 존재하지 않습니다.


“일급(first‑class) 객체”가 중요한 이유

“일급 시민(first‑class citizen)”이라는 표현은 자주 쓰이지만, 실제 의미는 구체적이어야 합니다.

FastAPI에서는 @app.get("/users") 가 객체 인스턴스의 메서드일 뿐이며, 프레임워크는 선택적으로 끼워 넣는 라이브러리입니다. 라우터는 파이썬 데이터 구조이고, 인증은 Depends(...) 로 구현됩니다. 이 모든 요소는 타입 체커에게 특별히 보이지 않으며, 단순히 메타데이터를 만들어 내는 함수 호출·데코레이터에 불과합니다.

Fitz에서는 @get("/users")컴파일러가 직접 이해하는 데코레이터 입니다. 타입 체커는 경로 템플릿, 경로 매개변수와 매개변수 타입, 본문 타입, 반환 타입을 모두 검증합니다. OpenAPI 생성기는 런타임 객체를 introspect 하지 않고 AST 를 바로 살펴서 스키마를 만든다—“등록(register)”이라는 데코레이터가 필요 없습니다. 핸들러에서 반환하는 User 타입은 자동 생성된 스키마와 Scalar UI에 나타나는 User 와 정확히 동일합니다.

이 차이는 처음엔 사소해 보이지만 일주일만 사용해 보면 크게 느껴집니다. 이제 “Pydantic 이 SQLAlchemy 와 필드 옵션이 달라서 충돌한다”는 문제에 시달리지 않고, 바로 엔드포인트를 작성할 수 있게 됩니다.


구성 요소

HTTP + OpenAPI + Scalar UI, 모두 자동

type Post { id: Int, title: Str, body: Str, tags: List }

@get("/posts")
fn list_posts() -> List { ... }

@post("/posts")
fn create_post(post: Post) -> Post { ... }

위 코드만 있으면 충분합니다. /openapi.json/docs (Scalar UI)는 자동으로 생성됩니다. 경로 매개변수 (/posts/{id}) 도 타입이 지정되고 자동 변환됩니다. JSON 본문 역직렬화 시 필수 필드 누락, 기본값 적용, nullable 검증, 불필요한 필드 거부 등을 모두 수행합니다. @server(docs=false) 로 비활성화할 수도 있습니다.

WebSocket, 타입 지정, AsyncAPI 자동 생성

type ChatMessage { from: Str, text: Str }

@server(43929, ws_heartbeat_secs=30)
fn main() => 0

@authenticated
@ws("/chat")
async fn chat(conn: WsConn, user: User) {
    loop {
        let msg = match conn.recv() {
            Ok(m) => m,
            Err(_) => break,
        }
        conn.broadcast(ChatMessage { from: user.name, text: msg.text })
    }
}

각 프레임은 선언된 타입으로 자동 마샬

0 조회
Back to Blog

관련 글

더 보기 »

모바일 한여름 열풍

!Cover image for Mobile Midsommer Madnesshttps://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploa...