A full-stack web framework for MoonBit
moon new hello-moonway
cd hello-moonway
# moonway is a server-side framework: switch the project to the native backend
awk '{sub(/preferred_target = "wasm"/, "preferred_target = \"native\"")} 1' moon.mod > moon.mod.tmp && mv moon.mod.tmp moon.mod
moon add daqing/moonway
# register the dependency in the main package too
printf 'import {\n "daqing/moonway",\n}\n' >> cmd/main/moon.pkg///|
fn main {
let app = @moonway.new()
app.get("/", ctx => ctx.text("Hello, moonway!"))
app.listen(3000)
}moon run cmd/mainimport {
"daqing/moonway",
"daqing/moonway/db",
"moonbitlang/core/json",
}
supported_targets = "native"
pkgtype(kind: "executable")
options(
link: { "native": { "cc-link-flags": "-lsqlite3" } },
)///|
struct Post {
id : Int32
title : String
body : String
} derive(ToJson, FromJson)
///|
let posts : @db.Table = @db.table("posts", [
@db.column("id", @db.IntT, primary=true),
@db.column("title", @db.TextT),
@db.column("body", @db.TextT),
])
///|
fn main {
let app = @moonway.new()
let db = @moonway.sqlite("app.db")
if !db.migrate([@db.migration(1, "create posts", [posts.create_sql()])]) {
abort("migrations failed")
}
app.get("/posts", ctx => {
let items : Array[Json] = db.select_raw(posts, "1=1", [], limit=100)
ctx.json(Json::array(items))
})
app.post("/posts", ctx => {
let row : Json? = Some(@json.parse(ctx.body())) catch { _err => None }
match row {
Some(Object(fields)) =>
if db.insert_raw(posts, fields) {
ctx.status(201).json(Json::object(fields))
} else {
ctx.status(500).text("insert failed")
}
_ => ctx.status(400).text("invalid JSON body")
}
})
// A ready-to-use admin UI for your data, served at /admin
app.admin(db, [posts])
app.listen(3000)
}moonway generate scaffold Post title:string body:stringcreated models/post.mbt
created handlers/posts.mbt
created migrations/001_create_posts.mbt
updated admin registryThe moonway CLI ships with the framework — install it with moon install daqing/moonway/cmd/moonway.

$ moonway console
moonway 0.11.7 · connected to sqlite://app.db
> Posts.count()
42git config core.hooksPath .githookspub struct App {
routes : Array[Route]
middlewares : Array[(Context) -> Context]
cache_policy : CachePolicy[RedisClient]?
ws_routes : Array[WsRoute]
static_dir : String?
}