RequestScript
v1.1.0Resource calls now return results you can handle

Send a script.
Get JSON back.

RequestScript is a small, strictly typed scripting language that you send to a server to run. Instead of calling a fixed set of endpoints, put the logic in the request body and get exactly the result you need.

pnpm add requestscript
POST /run
request Forecast {
    const weather: com.example.Weather

    const t = weather.temperature(city: "Oslo")
    if (t.error != null) {
        return t.error.message
    }

    return { city: "Oslo", celsius: t.value }
}
Response200 OK
{
  "returnValue": { "city": "Oslo", "celsius": 4.5 }
}
  1. 01

    Strict types

    Every variable has a type that never changes, and values are never silently converted. if (1) is an error, not a guess.

  2. 02

    Exact numbers

    Integers never wrap and decimal arithmetic is exact, so 0.1 + 0.2 == 0.3 is true. Built for prices and quantities.

  3. 03

    Deliberately small

    No loops and no user-defined functions. A script runs top to bottom and returns a value, so it is easy to review.

  4. 04

    Recoverable failures

    A failing resource call hands the script an error it can inspect, instead of failing the whole request.

two kinds of scripts

One-off requests. Versioned contracts.

Every script is either a request, run once and discarded, or a contract: named, versioned, saved on the server and invoked later with JSON parameters.

request

Run it once

Post the script to the server, get the result back. Requests take no parameters.

POST /run
request Greeting {
    const name = "Ada"
    return "Hello ${name}!"
}
Response200 OK
{ "returnValue": "Hello Ada!" }
contract

Save it, version it, call it

Contracts are immutable per version. Publish @2 next to @1 and move clients over when they are ready.

POST /contracts
contract shop.orders.LineTotal@2(item: object, taxRate: decimal(1, 4)) {
    const subtotal: decimal = item.price * item.quantity
    return { total: subtotal + subtotal * taxRate }
}
POST /run/shop/orders/LineTotal@2
{ "parameters": { "item": { "price": 9.99, "quantity": 2 }, "taxRate": 0.0825 } }

embed it

Runs wherever TypeScript runs

The reference implementation is the requestscript package. Its root export is the language itself (lexer, parser, exact decimals and interpreter) with no server or database, so it runs in Node, at the edge and in the browser. The playground below runs on it.

app.ts · in your own code
import { createResourceResolver, interpret } from 'requestscript';

const result = await interpret(source, {
  resourceResolver: createResourceResolver([weather]),
  parameters: { city: 'Oslo' },
});

console.log(result.returnValue);
server.ts · or serve the HTTP API
import { createResourceResolver } from 'requestscript';
import { startServer } from 'requestscript/server';

// Connects to Postgres, runs migrations and listens.
await startServer({
  port: 3000,
  resourceResolver: createResourceResolver([weather]),
  middleware: [authMiddleware],
});

playground

Try it in your browser

Scripts run locally on the real interpreter, and the result is shaped exactly like the server's HTTP response. Pick an example or write your own.

⌘/Ctrl + Enter
Result
Declaration
request HelloWorld
Request
POST /run
Status
Not run yet
Response body
Press Run to execute the script in your browser.
Demo resources
  • com.example.Weather.temperature(city: string): decimal
  • shop.Inventory.stock(sku: string): int32

Help shape RequestScript

The language is open source and young, which makes now the best time to influence it. Report issues, fix bugs, improve the docs, or bring it to a new host language.