Operation calls
Call OpenAPI operations by operation ID with the call syntax.
Basic syntax
call SourceName.operationId
call SourceName.operationId { options }
The method and path come from the spec. The options block accepts the same keys as a fetch step: body, paginate, until, retry, since, and backfill. There's no params or headers option.
Simple calls
GET operations
// OpenAPI: GET /pets, operationId listPets
call Petstore.listPets
// OpenAPI: GET /pets/{petId}, operationId getPetById
let petId = "123"
call Petstore.getPetById
POST operations
// OpenAPI: POST /pets, operationId addPet
call Petstore.addPet {
body: {
name: "Fluffy",
tag: "cat"
}
}
PUT, PATCH, and DELETE
let id = "123"
call API.updateItem {
body: { name: "New Name", status: "active" }
}
call API.patchItem {
body: { status: "inactive" }
}
call API.deleteItem
Path parameters
Operation paths with placeholders are filled from context variables of the same name. For GET /pets/{petId}, bind a variable called petId:
let petId = "123"
call Petstore.getPetById
// Generates: GET /pets/123
Inside a loop, bind the placeholder from the current item:
for pet in pets {
let petId = pet.id
call Petstore.getPetById
store response -> petDetails { key: .id }
}
Interpolated values are URL-encoded, so a path parameter can't inject extra path segments or a query string.
Query parameters
There's no general query-parameter option. The query string is built from:
paginate— pagination parameters (see below).since— the incremental-sync parameter or header.
If you need an arbitrary fixed query parameter, use a plain get "/path?key=value" fetch instead of an OAS call.
Request body
Inline body
call API.createItem {
body: {
name: "Test Item",
price: 29.99
}
}
Body from a variable
map data -> Payload {
name: .name,
status: "active"
}
call API.createItem { body: data }
Pagination
call API.listItems {
paginate: offset(offset, 100),
until: length(response.items) == 0
}
Cursor pagination
call API.listItems {
paginate: cursor(cursor, 100, "meta.nextCursor"),
until: response.meta.nextCursor == null
}
Combining options
call API.searchItems {
paginate: cursor(after, 50, "pageInfo.endCursor"),
until: response.pageInfo.hasNextPage == false,
retry: {
maxAttempts: 3,
backoff: exponential
}
}
Response handling
After a call, the body is available as response. Use match on a schema, a guard, or the wildcard:
action FetchWithHandling {
let id = itemId
call API.getItem
match response {
Item -> store response -> items { key: .id },
_ -> abort "Unexpected response"
}
}
match arms match a schema name, SchemaName where <guard>, or _. Object or literal patterns aren't supported.
Operation chaining
action CreateAndFetch {
call API.createItem {
body: { name: "New Item" }
}
// response.id from the creation
let id = response.id
call API.getItem
store response -> items { key: .id }
}
Error handling
Use flow directives in match arms. Note that retry uses the retry block keys (no delay), abort takes a bare string, and jump can chain a follow-up directive:
let id = itemId
call API.riskyOperation
match response {
_ where response.code == 401 -> jump RefreshToken then retry,
_ where response.code == 404 -> skip,
_ where response.code == 429 -> retry { maxAttempts: 5, backoff: exponential },
_ -> continue
}
Best practices
Match operation IDs exactly
# In the OpenAPI spec
operationId: listUsers
call API.listUsers // must match exactly
Use descriptive operation IDs
# Good
operationId: createInvoice
operationId: getInvoiceById
# Avoid
operationId: post1
operationId: get2