Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ATL-S syntax (5 minutes)

Write HTTP apps in short .atl. Sugar expands to the same runtime as classic forms; older verbose styles still work.

Hello route

module app

get "/hello" {
  def hello(req) {
    return json({ message: "hi" })
  }
}

fn main() -> Int {
  return 0
}
atlantus check --path .

Route blocks

get    "/users"      { def index(req)   { return json(list()) } }
get    "/users/{id}" { def show(req)    { return json(get_one(req.param("id"))) } }
post   "/users"      { def create(req)  { return json(create(req.json()), 201) } }
put    "/users/{id}" { def update(req)  { return json(update(req.param("id"), req.json())) } }
delete "/users/{id}" { def destroy(req) {
  if delete_one(req.param("id")) {
    return status(204)
  }
  return json({ error: "not_found" }, 404)
}}
  • One def / fn per block
  • Method + path become HTTP routes
  • Untyped req is the request; omitted return is a response

def and fn

def add(a: Int, b: Int) -> Int {
  return a + b
}

fn add(a: Int, b: Int) -> Int {
  return a + b
}

JSON responses

Write thisMeans this
json(body) / ok(body)HTTP 200 + JSON body
json(body, 201) / created(body)HTTP 201 + JSON body
status(204) / no_content()Status only

Request helpers

Write thisMeans this
req.param("id")Path param {id}
req.json()Parsed JSON body
req.header("authorization")Header value
req.method() / req.path()Method / path

Elegant handlers

Short status + early-exit sugar (desugars to the same natives as above):

Write thisMeans this
not_found(msg?)404 error envelope
unauthorized / forbidden / bad_request401 / 403 / 400
unprocessable(msg_or_fields?)422 validation_failed
let x = require_found(e, msg?)value or 404
let x = require_json(req)body or 422
let x = require_auth(req)user id or 401
require_fields(map, ["a","b"])422 if missing field
get "/users/{id}" {
  def show(req) {
    let user = require_found(db_get("users", req.param("id")), "not found")
    return ok(user)
  }
}

post "/users" {
  def create(req) {
    let body = require_json(req)
    require_fields(body, ["name"])
    return created(body)
  }
}

Null checks with none

let user = find(id)
if user is none {
  return not_found()
}
return ok(user)

Control flow

if n > 0 {
  return ok({ ok: true })
} else if n == 0 {
  return ok({ ok: "zero" })
} else {
  return bad_request("n must be >= 0")
}

Maps and arrays

let user = { "name": "Ada", "id": 1 }
let tags = ["atl", "web"]

Next: Language overview · HTTP & JSON.