Skip to main content
The Yasumu Schema Language (YSL) is a custom format designed specifically for defining API testing workflows. Unlike JSON or YAML, YSL is optimized for readability, clean git diffs, and embedded code blocks.

Why YSL?

Yasumu uses .ysl files instead of traditional formats like JSON for several reasons:

Human-readable

Clean syntax without excessive punctuation makes files easy to read and understand.

Git-friendly

Structured format produces clean, minimal diffs in version control.

Embedded code

Native support for TypeScript code blocks without escaping.

Type-safe

Schema validation ensures file integrity and compatibility.

Basic syntax

YSL files start with an annotation declaring the file type, followed by structured blocks:
@rest

metadata {
  name: "Get request"
  method: "GET"
}

request {
  url: "https://example.com"
  body: null
}

script {
  console.log("tested");
}

File types

YSL supports several file types identified by annotations:
REST API request definitions:
@rest

metadata {
  name: "Create User"
  method: "POST"
  id: "unique-id"
  groupId: null
}

request {
  url: "{{API_URL}}/users"
  headers: [
    {
      key: "Content-Type"
      value: "application/json"
      enabled: true
    }
  ]
  parameters: []
  searchParameters: []
  body: {
    type: "application/json"
    content: "'{"name": "John", "email": "[email protected]"}'"
  }
}

dependencies []

script {
  export function onRequest(req, res) {
    // Pre-request logic
  }
  
  export function onResponse(req, res) {
    // Post-response logic
  }
}

test {
  // Test assertions
}

Data types

YSL supports several data types:
Text values enclosed in quotes:
name: "My Request"
url: "https://example.com"
Numeric values without quotes:
port: 50611
version: 0
snapshot: 1768400471602
true or false values:
enabled: true
secure: false
Absence of value:
body: null
parentId: null
password: null
Nested structures with curly braces:
metadata {
  id: "123"
  name: "Request"
}

body: {
  type: "application/json"
  content: "'{}'"
}
Lists enclosed in square brackets:
headers: [
  {
    key: "Authorization"
    value: "Bearer token"
    enabled: true
  },
  {
    key: "Content-Type"
    value: "application/json"
    enabled: true
  }
]

dependencies: [
  "request-id-1",
  "request-id-2"
]
TypeScript code without escaping:
script {
  export function onRequest(req, res) {
    const timestamp = Date.now();
    req.headers.set('X-Timestamp', timestamp.toString());
    
    console.log('Preparing request at', new Date(timestamp));
  }
}

Schema validation

Each YSL file type has a defined schema for validation. Here’s how REST entities are validated:
import { t } from '@yasumu/schema';

const KeyValuePairSchema = t.object({
  key: t.string(),
  value: t.string(),
  enabled: t.boolean(),
});

const RestSchema = t.script({
  annotation: '@rest',
  blocks: {
    metadata: t.object({
      name: t.string(),
      method: t.string(),
      id: t.string(),
      groupId: t.nullable(t.string()),
    }),
    request: t.object({
      url: t.nullable(t.string()),
      headers: t.list(KeyValuePairSchema),
      parameters: t.list(KeyValuePairSchema),
      searchParameters: t.list(KeyValuePairSchema),
      body: t.nullable(t.object({
        type: t.string(),
        content: t.nullable(t.string()),
      })),
    }),
    dependencies: t.list(t.string()),
    script: t.nullable(t.code()),
    test: t.nullable(t.code()),
  },
});

Parsing YSL files

Use the @yasumu/schema package to parse YSL files:
import { YasumuSchemaScriptActions } from '@yasumu/schema';

const code = `
@rest

metadata {
  name: "Get request"
  method: "GET"
}

request {
  url: "https://example.com"
  body: null
}

script {
  console.log("tested");
}
`;

const parsed = YasumuSchemaScriptActions.parse(code);
console.log(parsed);

Best practices

Consistent formatting: Use consistent indentation (2 spaces) for better readability.
Meaningful IDs: While IDs are auto-generated, they should be unique and stable across the workspace.
Quote strings: Always quote string values, even if they don’t contain spaces.
Trailing commas: Use trailing commas in arrays for cleaner git diffs when adding items.
Do not manually edit the snapshot timestamp in workspace files. It’s managed automatically by Yasumu for synchronization.

Variable interpolation

YSL supports variable interpolation using double curly braces:
request {
  url: "{{API_URL}}/users/{{userId}}"
  headers: [
    {
      key: "Authorization"
      value: "Bearer {{ACCESS_TOKEN}}"
      enabled: true
    }
  ]
}
Variables are resolved from the active environment at runtime:
1

Parse YSL

File is parsed into structured data.
2

Find variables

{{variable}} patterns are identified.
3

Resolve values

Variables are replaced with values from the active environment.
4

Execute request

Request is sent with interpolated values.
Learn more about environment variables.

Code blocks

Code blocks in YSL support full TypeScript syntax without escaping:
script {
  import { Buffer } from 'node:buffer';
  
  export function onRequest(req, res) {
    // Access request object
    console.log('Method:', req.method);
    console.log('URL:', req.url);
    
    // Modify headers
    req.headers.set('X-Custom', 'value');
    
    // Generate authentication
    const credentials = `${username}:${password}`;
    const encoded = Buffer.from(credentials).toString('base64');
    req.headers.set('Authorization', `Basic ${encoded}`);
  }
  
  export function onResponse(req, res) {
    // Access response
    console.log('Status:', res.status);
    console.log('Body:', res.body);
    
    // Store data in environment
    if (res.status === 200) {
      const data = JSON.parse(res.body);
      req.environment.set('userId', data.id);
    }
  }
}
Learn more about scripting.

File organization

YSL files are organized in a specific directory structure:
yasumu/
├── workspace.ysl              # Workspace config (1 per workspace)
├── smtp.ysl                   # SMTP config (1 per workspace)
├── yasumu-lock.json           # Lock file (managed automatically)
├── rest/
│   ├── request-1.ysl          # Individual REST requests
│   ├── request-2.ysl
│   └── request-3.ysl
└── environment/
    ├── development.ysl        # Environment configs
    ├── staging.ysl
    └── production.ysl
Each REST request and environment gets its own .ysl file. This makes version control diffs cleaner and allows for parallel editing without conflicts.

Next steps

REST API Testing

Learn how REST entities are structured in YSL

Environments

Understand environment YSL files

Workspaces

Learn about workspace YSL structure

Scripting

Write code blocks in YSL files

Build docs developers (and LLMs) love