Web Development
Draft provides first-class support for web development, from APIs to full-stack applications.
Overview
Section titled “Overview”Draft compiles to WebAssembly for browser execution and provides a native server runtime for backend services.
Getting Started
Section titled “Getting Started”Create a Web Project
Section titled “Create a Web Project”draft new my-web-app --template webcd my-web-appProject 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.tomlServer
Section titled “Server”Basic HTTP Server
Section titled “Basic HTTP Server”import httpimport 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.REST API
Section titled “REST API”import httpimport 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.Middleware
Section titled “Middleware”import httpimport 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.Client-Side Draft
Section titled “Client-Side Draft”Draft compiles to WebAssembly for browser execution:
@// src/client.draftimport httpimport 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:
draft build src/client.draft --target wasm -o public/app.wasmStatic Site Generation
Section titled “Static Site Generation”import fsimport 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.Database Access
Section titled “Database Access”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.Authentication
Section titled “Authentication”import httpimport 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.WebSocket
Section titled “WebSocket”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.Deployment
Section titled “Deployment”Build for Production
Section titled “Build for Production”draft build --release --target wasmDocker
Section titled “Docker”FROM draftlang/draft:latestCOPY . /appWORKDIR /appRUN draft build --releaseEXPOSE 8080CMD ["./app"]Deploy
Section titled “Deploy”draft deployTemplates
Section titled “Templates”Draft includes a built-in template engine:
import template
@html = @template#render("index.html", { "title", "My App", "users", @users})Session Management
Section titled “Session Management”import httpimport 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.Error Handling
Section titled “Error Handling”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.