1.1 What Restspace v2 is

Restspace v2 (RS2) is a runtime for building backends out of small, composable services — without writing a traditional web server. You describe what you want as configuration, mount it at a URL path, and the runtime handles the HTTP, the routing, the storage, the auth, and the sandboxing for you.

The whole system rests on one idea:

A service is a function on an HTTP message.

A request comes in as a message — a method, a URL, headers, and a body. A service transforms it and returns another message — a status, headers, and a body. That is the entire contract. A file store is such a function. A schema-validated database is such a function. A piece of your own JavaScript is such a function. Because they all share the same shape, they all compose.

Why that matters

In a conventional backend you wire up a framework, write route handlers, pull in a database client, bolt on auth middleware, add a caching layer, and so on — each with its own conventions. RS2 collapses that into a uniform model:

  • Everything is reachable over HTTP at a path you choose. There is no hidden internal API; the way your own code talks to the data store is the same way a browser does.
  • Cross-cutting concerns live in the runtime, not in each service. Authentication, role checks, rate limits, caching headers, idempotency, retries, tracing, and CORS are applied by the host around every service, so you configure them once instead of re-implementing them everywhere.
  • Custom code is a first-class citizen, but always sandboxed. You can drop in a JavaScript module (or a compiled WebAssembly component) and mount it like any built-in service. It runs under hard resource limits and can only reach the capabilities you explicitly grant it. There is no unsandboxed path.

What's in the box

RS2 ships a handful of prebuilt services that cover the common backend needs. You mount the ones you want:

Service What it does
file Streamed file storage; also serves static sites / SPAs
data Schema-validated JSON record store
query Stored, parameterized queries over your data
template Renders stored JSX templates to HTML
pipeline Composes other services into multi-step flows
wrapper Runs one fixed inline pipeline as a facade over a mount
auth Login, sessions, and role-based access control
proxy Forwards to a fixed external API with host-injected credentials
sms Stable send/status API over a swappable provider adapter
services The self-configuration API (edit the running tenant)
log Reads back the node's structured logs, scoped to your tenant

When the prebuilt services aren't enough, you write a custom service — a single JavaScript file, or a Rust/WebAssembly component — and deploy it to the same runtime. It gets the same HTTP front door, the same auth and limits, and talks to the other services through granted capabilities.

The shape of a running system

A single RS2 node (the running process) hosts one or more tenants. Each tenant is an isolated world: its own mounts, its own data, its own users, its own config. Within a tenant you declare mounts — each one places a service at a URL prefix:

{
  "mounts": [
    { "path": "/files", "service": "file", "config": { "access": "open" } },
    { "path": "/data",  "service": "data",
      "config": { "access": { "read": "all", "write": "A" }, "enforceSchema": true } },
    { "path": "/auth",  "service": "auth",
      "config": { "access": { "read": "authenticated", "invoke": "all" } } }
  ]
}

That config alone gives you a streamed file store at /files, a validated JSON database at /data, and the auth endpoints at /auth — no code written. (Auth also needs the tenant-level signing/user settings covered in Part 5.) Every mount's access is explicit because an omitted policy fails closed. From there you layer on queries, pipelines, and custom services as your backend grows.

The next section unpacks the mental model — tenants, mounts, services, and pipelines — in a bit more detail.


Manual home · Next: 1.2 The mental model →