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
@environment
@workspace
@smtp
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
}
Environment configuration files: @environment
metadata {
id: "env-id"
name: "Production"
}
variables [
{
key: "API_URL"
value: "https://api.example.com"
enabled: true
},
{
key: "API_VERSION"
value: "v2"
enabled: true
},
]
secrets [
{
key: "API_KEY"
value: ""
enabled: true
},
]
Workspace configuration: @workspace
metadata {
id: "workspace-id"
name: "My Project"
version: 0
}
snapshot 1768400471602
groups {
group-id: {
id: "group-id"
name: "User APIs"
entity: rest
parentId: null
workspaceId: "workspace-id"
}
}
SMTP server configuration: @smtp
metadata {
id: "smtp-id"
port: 50611
username: ""
password: null
}
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:
Parse REST Entity
Access Parsed Data
Validate Schema
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:
Parse YSL
File is parsed into structured data.
Find variables
{{variable}} patterns are identified.
Resolve values
Variables are replaced with values from the active environment.
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