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

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.

CommandDescription
sapi build [file.sapi]Compile a release server binary.
sapi build --linuxCross-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] --htmlGenerate documentation.
sapi new <project>Create a new Sapi project.
sapi install prerequisitesInstall local build prerequisites for current OS.
sapi install plugin vscodeInstall 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

TypeExample
stringstring name = "Alice"
intint age = 30
floatfloat ratio = 1.25
boolbool active = true
list:stringlist:string tags = ["a", "b"]
jsonjson 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 }
}
Supported URL schemes: postgres://..., mysql://..., mariadb://..., sqlite:...

7. Migrations

Sapi includes SQLx-style migration commands.

CommandDescription
sapi migrate add -r init_schemaCreate a reversible migration pair.
sapi migrate runApply pending migrations.
sapi migrate revertRevert last migration.
sapi migrate infoShow migration status.
sapi migrate build-scriptGenerate Cargo build.rs migration watcher.
sapi migrate prepareGenerate SQLx offline metadata.
sapi migrate database create|drop|reset|setupDatabase 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

Behaviorsapi runsapi watch
Builds codeYesYes
Starts serverYesYes
Auto restart on saveNoYes

When swagger: true is enabled, runtime output includes:

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
Canonical source: edit 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" }
}