Babel Rosetta - HeyItWorked/babel-shelf GitHub Wiki

Babel Rosetta

Side-by-side comparison of the same operations in every language. Use this as a quick-reference cheat sheet when switching between implementations.


Define a Data Model

// Go — models.go
type Book struct {
    Id     int    `json:"id"`
    Title  string `json:"title"`
    Author string `json:"author"`
    Status string `json:"status"`
}
// TypeScript — models.ts
export interface Book {
  id: number;
  title: string;
  author: string;
  status: BookStatus;
}
# Python
@dataclass
class Book:
    id: int
    title: str
    author: str
    status: str
// Gleam (coming soon)
pub type Book {
  Book(id: Int, title: String, author: String, status: BookStatus)
}

Pattern: Every language needs to define "what a book looks like." Go uses structs with tags, TS uses interfaces, Python uses dataclasses, Gleam uses custom types. The shape is identical — just the syntax differs.


Define Allowed Values (Enum-Like)

// Go — string constants (no real enums)
const (
    StatusWantToRead = "want to read"
    StatusReading    = "reading"
    StatusFinished   = "finished"
)
// TypeScript — union type (compile-time only)
export type BookStatus = "want to read" | "reading" | "finished";
export const VALID_STATUSES: BookStatus[] = [STATUS_WANT_TO_READ, STATUS_READING, STATUS_FINISHED];
# Python — Enum class
from enum import Enum
class BookStatus(str, Enum):
    WANT_TO_READ = "want to read"
    READING = "reading"
    FINISHED = "finished"
// Gleam — custom type (true algebraic type)
pub type BookStatus {
  WantToRead
  Reading
  Finished
}
Language Compiler catches invalid value? Exhaustive match?
Go No (just strings) No
TypeScript Yes (union type) No (needs manual check)
Python Partial (Enum) No
Gleam Yes (custom type) Yes (compiler forces it)

Insert Into Database

// Go
row := db.QueryRow(
    `INSERT INTO books (title, author, status) VALUES ($1, $2, $3)
     RETURNING id, title, author, status`,
    book.Title, book.Author, book.Status,
)
err := row.Scan(&book.Id, &book.Title, &book.Author, &book.Status)
// TypeScript
const result = await pool.query<Book>(
    `INSERT INTO books (title, author, status) VALUES ($1, $2, $3)
     RETURNING id, title, author, status`,
    [book.title, book.author, book.status]
)
return result.rows[0]
# Python (psycopg2)
cursor.execute(
    """INSERT INTO books (title, author, status) VALUES (%s, %s, %s)
       RETURNING id, title, author, status""",
    (book.title, book.author, book.status)
)
row = cursor.fetchone()

Same SQL, different wrappers:

  • Go: manual Scan into each field with & pointers
  • TS: auto-maps columns to object keys
  • Python: fetchone() returns a tuple (or dict with RealDictCursor)

Handle an Error

// Go — explicit check, every time
book, err := insertBook(book)
if err != nil {
    http.Error(w, "could not create book", 500)
    return
}
// TypeScript — try/catch (or just let it throw)
try {
    const book = await insertBook(body)
    return c.json(book, 201)
} catch (e) {
    return c.text("could not create book", 500)
}
// Note: the actual codebase doesn't try/catch — it lets Hono catch uncaught errors
# Python — try/except
try:
    book = insert_book(body)
    return jsonify(book), 201
except Exception:
    return "could not create book", 500
// Gleam — Result type + use keyword
use book <- result.try(insert_book(conn, title, author, status))
// if insert_book returns Error, the whole function short-circuits
json_response(encode_book(book), 201)

Parse a URL Parameter

// Go — stdlib path value
id, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
    http.Error(w, "invalid id", 400)
    return
}
// TypeScript — Hono param
const id = Number(c.req.param("id"))
if (isNaN(id)) {
    return c.text("invalid id", 400)
}
# Python Flask
@app.get("/books/<int:id>")  # Flask parses for you
def get_book(id: int): ...
// Gleam — pattern match + parse
case wisp.path_segments(req) {
  ["books", id_string] -> {
    case int.parse(id_string) {
      Ok(id) -> get_book(id, ctx)
      Error(_) -> wisp.bad_request()
    }
  }
}

Return JSON

// Go — manual encoding
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(book)
// TypeScript — one-liner
return c.json(book, 201)
# Python Flask
return jsonify(book), 201
// Gleam — explicit encoding
wisp.json_response(
  json.to_string_tree(encode_book(book)),
  201
)

Verbosity spectrum: TypeScript < Python < Gleam < Go


Start the Server

// Go — one line, blocks forever
http.ListenAndServe(":8080", router)
// TypeScript (Bun) — export convention
export default { port: 8081, fetch: app.fetch }
# Python Flask
app.run(port=8080)
// Gleam — wisp + mist
wisp.mist_handler(handle_request, ctx)
|> mist.new
|> mist.port(8082)
|> mist.start_http

Testing — Send a Request

// Go — httptest recorder
req, _ := http.NewRequest("POST", "/books", strings.NewReader(`{"title":"Dune"}`))
rr := httptest.NewRecorder()
handler.ServeHTTP(rr, req)
// check rr.Code, rr.Body
// TypeScript — Hono's built-in test helper
const res = await app.request("/books", {
    method: "POST",
    body: JSON.stringify({ title: "Dune" }),
    headers: { "Content-Type": "application/json" }
})
// check res.status, await res.json()
# Python Flask
res = client.post("/books", json={"title": "Dune"})
# check res.status_code, res.get_json()

Key insight: Go and TS both test without starting a real HTTP server. Go uses httptest.NewRecorder() to capture the response in memory. Hono's app.request() does the same thing. No network involved.

⚠️ **GitHub.com Fallback** ⚠️