Skip to content
Draft

Web Development

Draft provides first-class support for web development, from APIs to full-stack applications.

Draft compiles to WebAssembly for browser execution and provides a native server runtime for backend services.

Terminal window
draft new my-web-app --template web
cd my-web-app

Project structure:

my-web-app/
├── draft.toml
├── src/
│ ├── main.draft # Server entry point
│ ├── routes/
│ │ ├── mod.draft
│ │ ├── users.draft
│ │ └── posts.draft
│ └── models/
│ └── user.draft
├── public/
│ ├── index.html
│ ├── styles.css
│ └── app.wasm
└── draft.toml
import http
import json
action main()
@server = @http#Server::new()
@server#get("/", fn(@req) =>
@http#Response::html("<h1>Welcome to Draft!</h1>")
fin action.)
@server#get("/api/health", fn(@req) =>
@http#Response::json({"status": "ok"})
fin action.)
@server#listen(8080)
fin action.
import http
import json
@users = []
action main()
@server = @http#Server::new()
@server#get("/api/users", fn(@req) =>
@http#Response::json(@users)
fin action.)
@server#post("/api/users", fn(@req) =>
@data = @req#json()
@user = {
"id": string(@users#length + 1),
"name", @data["name"],
"email", @data["email"]
}
@users#push(@user)
@http#Response::json(@user, status: 201)
fin action.)
@server#get("/api/users/:id", fn(@req) =>
@id = @req#params["id"]
@user = find_user(@id)
if @user != nil
@http#Response::json(@user)
else
@http#Response::json({"error": "Not found"}, status: 404)
fin if.
fin action.)
@server#listen(8080)
fin action.
import http
import time
action main()
@server = @http#Server::new()
@server#use(fn(@req, @next) =>
@start = @time#now()
@response = @next()
@duration = @time#elapsed(@start)
@io#write_line(@req#method + " " + @req#path + " - " + string(@duration) + "ms")
return @response
fin action.)
@server#use(fn(@req, @next) =>
@response = @next()
@response#header("X-Powered-By", "Draft")
return @response
fin action.)
@server#listen(8080)
fin action.

Draft compiles to WebAssembly for browser execution:

@// src/client.draft
import http
import dom
action main()
@button = @dom#select("#submit")
@button#on_click(fn() =>
@response = @http#post("/api/data", @dom#form_data("#form"))
@dom#select("#result")#text(@response#body)
fin action.)
fin action.

Compile to WASM:

Terminal window
draft build src/client.draft --target wasm -o public/app.wasm
import fs
import markdown
action main()
@posts = @fs#walk_dir("content/posts")
for @post in @posts
@content = @fs#read_file(@post)
@html = @markdown#to_html(@content)
@output = render_template("post", {"content": @html})
@fs#write_file("public/" + @post + ".html", @output)
fin for.
fin action.
import sqlite
action main()
@db = @sqlite#open("app.db")
@db#execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)")
@db#execute("INSERT INTO users (name) VALUES (?)", "Alice")
@rows = @db#query("SELECT * FROM users")
for @row in @rows
write(@row["name"])
fin for.
fin action.
import http
import jwt
action main()
@server = @http#Server::new()
@server#post("/api/login", fn(@req) =>
@data = @req#json()
@user = authenticate(@data["username"], @data["password"])
if @user != nil
@token = @jwt#encode({"user_id": @user#id}, "secret")
@http#Response::json({"token": @token})
else
@http#Response::json({"error": "Invalid credentials"}, status: 401)
fin if.
fin action.)
@server#listen(8080)
fin action.
import http
action main()
@server = @http#Server::new()
@server#websocket("/ws", fn(@socket) =>
@socket#on_message(fn(@message) =>
@socket#broadcast(@message)
fin action.)
fin action.)
@server#listen(8080)
fin action.
Terminal window
draft build --release --target wasm
FROM draftlang/draft:latest
COPY . /app
WORKDIR /app
RUN draft build --release
EXPOSE 8080
CMD ["./app"]
Terminal window
draft deploy

Draft includes a built-in template engine:

import template
@html = @template#render("index.html", {
"title", "My App",
"users", @users
})
import http
import sessions
action main()
@session_store = @sessions#Store::new()
@server = @http#Server::new()
@server#use(@sessions#middleware(@session_store))
@server#get("/profile", fn(@req) =>
@user_id = @req#session["user_id"]
if @user_id == nil
return @http#Response::redirect("/login")
fin if.
@http#Response::html(render_profile(@user_id))
fin action.)
@server#listen(8080)
fin action.
import http
action main()
@server = @http#Server::new()
@server#error_handler(fn(@req, @error) =>
@http#Response::json({
"error", @error#message,
"status", 500
}, status: 500)
fin action.)
@server#listen(8080)
fin action.