moonctl (mctl) — a spec-driven code generator for MoonBit (← goctl): parse a .api service spec and emit compilable moonapi scaffolding (routes + handler stubs).
Dependencies
service greet {
get /ping ping "health check"
get /users/:id get_user
post /users create_user "create a user"
}// Code generated by moonctl. DO NOT EDIT.
///|
/// Build the greet application with its routes wired to handlers.
pub fn build_app() -> @moonapi.App {
let app = @moonapi.App::new()
app.get("/ping", ctx => ping(ctx), summary="health check")
app.get("/users/:id", ctx => get_user(ctx))
app.post("/users", ctx => create_user(ctx), summary="create a user")
app
}
///|
pub fn ping(_ctx : @moonapi.Context) -> @moonasgi.Response {
@moonapi.text(200, "TODO: ping")
}
// ... one stub per handlerlet spec = @moonctl.parse(source) // -> Spec { service, routes, types }
let code = @moonctl.generate(spec) // -> compilable moonapi scaffold (String)$ mctl gen api greet.api # -> greet.mbt (moonapi scaffold)
$ mctl gen proto greet.proto # -> greet_grpc.mbt (moonrpc service stub)
$ mctl gen model user.api # -> user_model.mbt (moonorm model + migration)
$ mctl gen crud schema.sql # -> schema_model.mbt (moonorm model + typed CRUD)
$ mctl gen doc greet.api # -> greet_openapi.json + greet_swagger.html
$ mctl model datasource sqlite:shop.db # -> datasource_model.mbt (read a live DB's schema)
$ mctl api new blog # scaffold a moonapi service project under blog/
$ mctl rpc new echo # scaffold a moonrpc service project under echo/
$ mctl model new account # scaffold a moonorm data-layer project under account/
$ mctl docker greet # -> Dockerfile + .dockerignore
$ mctl kube greet # -> deploy/deployment.yaml + deploy/service.yaml
$ mctl plugin ./my-plugin greet.api # run an external plugin over the parsed speclet stub = @moonctl.generate_grpc(@moonctl.parse_proto(proto_src)) // -> moonrpc stub
let model = @moonctl.generate_model(@moonctl.parse(api_src)) // -> moonorm model + migrationlet code = @moonctl.generate_crud_from_ddl(sql_src) // -> moonorm model + CRUD (String)$ mctl model datasource sqlite:shop.db
$ mctl model datasource postgres://user:pass@localhost:5432/shop$ mctl api new blog # blog/{moon.mod.json, blog.api, src/{moon.pkg.json, app.mbt}, README.md}
$ mctl rpc new echo # echo/{moon.mod.json, echo.proto, src/{moon.pkg.json, service.mbt}, README.md}
$ mctl model new account # account/{moon.mod.json, schema.sql, src/{moon.pkg.json, model.mbt}, README.md}
$ mctl docker greet # Dockerfile (two-stage native build) + .dockerignore
$ mctl kube greet # deploy/deployment.yaml + deploy/service.yamllet files = @moonctl.scaffold_api("blog") // -> Array[GenFile] to writelet req = @moonctl.plugin_request(spec) // JSON for the plugin's stdin
let files = @moonctl.parse_gen_files(@json.parse(out)) // the plugin's stdout -> files to writelet spec = @moonctl.parse(api_src)
let json = @moonctl.generate_doc(spec, version=OpenApi31) // or Swagger20 / OpenApi30
let html = @moonctl.swagger_ui_stub(spec_url="/openapi.json")let out = @moonctl.render(
"{{range .routes}}{{.verb}} {{.path}} -> {{.handler}}\n{{end}}",
@moonctl.spec_to_value(spec),
)
// or drive codegen from a caller-supplied template:
let code = @moonctl.generate(spec, template=my_template) // == generate_withpub suberror DataSourceError {
BadDsn(String)
}pub suberror TemplateError {
ParseError(String)
ExecError(String)
}pub(all) struct DdlColumn {
name : String
type_ : String
primary_key : Bool
nullable : Bool
default_ : String?
}pub(all) struct Field {
name : String
type_ : String
}pub(all) struct GenFile {
path : String
content : String
}pub(all) struct PgTarget {
host : String
port : Int
user : String
password : String
database : String
}pub(all) struct Proto {
package_ : String
services : Array[ProtoService]
messages : Array[ProtoMessage]
}pub(all) struct ProtoField {
name : String
type_ : String
}pub(all) struct ReflectedColumn {
table : String
name : String
sql_type : String
primary_key : Bool
nullable : Bool
}pub(all) struct Route {
verb : String
path : String
handler : String
summary : String
}pub(all) struct Rpc {
name : String
request : String
response : String
client_streaming : Bool
server_streaming : Bool
}pub struct Template {
renderer : (Value) -> String raise TemplateError
funcs : Map[String, (Array[Value]) -> Value raise TemplateError]
}fn generate_crud_from_ddl(source : String) -> Stringfn generate_doc(spec : Spec, version? : DocVersion, title? : String, api_version? : String) -> Stringfn openapi_document(spec : Spec, version? : DocVersion, title? : String, api_version? : String) -> Jsonservice greet {
get /ping ping "health check"
get /users/:id get_user
post /users create_user "create a user"
}
type User {
id: int64
name: string
}syntax = "proto3";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest { string name = 1; }
message HelloReply { string message = 1; }fn swagger_ui_stub(spec_url? : String, title? : String) -> Stringmoonctl (mctl) — a spec-driven code generator for MoonBit (← goctl): parse a .api service spec and emit compilable moonapi scaffolding (routes + handler stubs).
Dependencies