Sapi
End-to-end reference for building APIs with Sapi (compiled to Rust with Axum + Tokio).
1. Introduction
Sapi is a high-level language focused on API development. A .sapi file defines service configuration, routes, SQL queries, validation, auth, and response structures.
The Sapi compiler generates a production-ready Rust server and can build binaries for local or Linux deployment.
2. Installation
Windows installer (recommended)
Download the installer directly from GitHub:
https://github.com/dSlyders/sapi-lang/releases/latest/download/sapi-install.exe
After installation, open a new terminal and verify:
sapi -V
Alternative links
- Latest releases page: https://github.com/dSlyders/sapi-lang/releases/latest
- All releases: https://github.com/dSlyders/sapi-lang/releases
Developer prerequisites
For local compilation with sapi build, sapi run or sapi watch, install prerequisites:
sapi install prerequisites
Install VS Code plugin tooling:
sapi install plugin vscode
3. Quick start
sapi new my-api
cd my-api
sapi run
sapi new generates a starter project, including main.sapi and sapi.conf.
4. CLI commands
If the source file is omitted, Sapi uses main.sapi by default.
| Command | Description |
|---|---|
sapi build [file.sapi] | Compile a release server binary. |
sapi build --linux | Cross-build Linux binary. |
sapi run [file.sapi] | Build and run once. |
sapi watch [file.sapi] | Watch files and auto-rebuild/restart. |
sapi doc [file.sapi] --html | Generate documentation. |
sapi new <project> | Create a new Sapi project. |
sapi install prerequisites | Install local build prerequisites for current OS. |
sapi install plugin vscode | Install or update VS Code plugin. |
sapi migrate ... | SQLx-style migration command group. |
5. Language basics
Service and routes
service MyApi {
port: 3000
swagger: true
cors: true
}
MyApi get "/ping" {
return "pong"
}
MyApi post "/users" {
body json {
string name
int age
}
return 201: { string message = "created", string user = name }
}
MyApi get "/users/{id}" {
route { int id }
return { int userId = id }
}
Types
| Type | Example |
|---|---|
string | string name = "Alice" |
int | int age = 30 |
float | float ratio = 1.25 |
bool | bool active = true |
list:string | list:string tags = ["a", "b"] |
json | json payload = { "ok": true } |
Control flow
if score >= 90 {
return "A"
} else if score >= 75 {
return "B"
} else {
return "C"
}
Functions
fn double(int n) {
int result = n * 2
return result
}
6. Database and SQL
Database blocks are now URL-based only. Use url with an explicit string or env(...).
database MainDB {
url: env("DATABASE_URL")
log {
path: "logs/sql.log"
level: "debug"
slow: 180
}
}
sql findUser = `SELECT id, name FROM users WHERE id = {id}` : {
int id
string name
} use MainDB
MyApi get "/users/{id}" {
route { int id }
await FindUser row = findUser({ id: id }).one()
return { int id = row.id, string name = row.name }
}
postgres://..., mysql://..., mariadb://..., sqlite:...
7. Migrations
Sapi includes SQLx-style migration commands.
| Command | Description |
|---|---|
sapi migrate add -r init_schema | Create a reversible migration pair. |
sapi migrate run | Apply pending migrations. |
sapi migrate revert | Revert last migration. |
sapi migrate info | Show migration status. |
sapi migrate build-script | Generate Cargo build.rs migration watcher. |
sapi migrate prepare | Generate SQLx offline metadata. |
sapi migrate database create|drop|reset|setup | Database utility commands. |
Useful flags include --database-url, --connect-timeout, and --no-dotenv.
8. JWT auth and guard
auth Auth {
secret: env("JWT_SECRET")
algorithm: "HS256"
expiry: 3600
claims: {
int userId
string role
}
}
MyApi get "/profile" {
guard Auth
return "authorized"
}
MyApi delete "/admin/users/{id}" {
guard Auth "admin"
route { int id }
return { string message = "deleted" }
}
9. Run and watch
| Behavior | sapi run | sapi watch |
|---|---|---|
| Builds code | Yes | Yes |
| Starts server | Yes | Yes |
| Auto restart on save | No | Yes |
When swagger: true is enabled, runtime output includes:
- API URL:
http://localhost:PORT - Swagger URL:
http://localhost:PORT/swagger
10. Deployment
# Build production binary
sapi build
# Build Linux binary from Windows
sapi build --linux
The output binary is standalone for server deployment.
Nginx reverse proxy example
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
11. Documentation generation
# OpenAPI JSON to stdout
sapi doc main.sapi
# HTML docs
sapi doc main.sapi --html --output docs
LANGUAGE.html and sync to release docs.
12. Full .sapi example
service MyApi {
port: 3000
swagger: true
cors: true
}
database MainDB {
url: env("DATABASE_URL")
log {
path: "logs/sql-main.log"
level: "info"
slow: 200
}
}
auth Auth {
secret: env("JWT_SECRET")
algorithm: "HS256"
expiry: 3600
claims: {
int userId
string role
}
}
sql findUser = `
SELECT id, name, role
FROM users
WHERE id = {id}
` : {
int id
string name
string role
} use MainDB
MyApi get "/ping" {
return "pong"
}
MyApi get "/users/{id}" {
route { int id }
await FindUser user = findUser({ id: id }).one()
return {
int id = user.id
string name = user.name
string role = user.role
}
}
MyApi get "/me" {
guard Auth
return "authenticated"
}
MyApi delete "/admin/users/{id}" {
guard Auth "admin"
route { int id }
return { string status = "deleted" }
}