Skip to content

Commit 51601be

Browse files
committed
fix(api): update variable syntax in API spec from ${...} to {...}
1 parent a882a54 commit 51601be

1 file changed

Lines changed: 65 additions & 65 deletions

File tree

cmd/sling/resource/llm_API_SPEC.md

Lines changed: 65 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ endpoints:
3535
endpoint_name:
3636
description: "Endpoint description"
3737
request:
38-
url: "${state.base_url}/resource"
38+
url: "{state.base_url}/resource"
3939
method: "GET"
4040

4141
response:
@@ -62,17 +62,17 @@ authentication:
6262
type: "bearer"
6363

6464
# Bearer token for authentication
65-
token: "${secrets.api_token}"
65+
token: "{secrets.api_token}"
6666

6767
# Basic authentication credentials
68-
username: "${secrets.username}"
69-
password: "${secrets.password}"
68+
username: "{secrets.username}"
69+
password: "{secrets.password}"
7070

7171
# OAuth2 Client Credentials Flow (most common for API integrations)
7272
type: "oauth2"
7373
flow: "client_credentials"
74-
client_id: "${secrets.oauth_client_id}"
75-
client_secret: "${secrets.oauth_client_secret}"
74+
client_id: "{secrets.oauth_client_id}"
75+
client_secret: "{secrets.oauth_client_secret}"
7676
authentication_url: "https://api.example.com/oauth/token"
7777
scopes: ["read:data", "write:data"]
7878

@@ -117,7 +117,7 @@ endpoints:
117117
state:
118118
# Get last sync timestamp from persistent state, default to 30 days ago
119119
updated_since: >
120-
${ coalesce(
120+
{ coalesce(
121121
sync.last_updated,
122122
date_format(date_add(now(), -30, 'day'), '%Y-%m-%dT%H:%M:%SZ')
123123
)
@@ -131,23 +131,23 @@ endpoints:
131131
# HTTP request configuration
132132
request:
133133
# Path relative to defaults.request.url
134-
url: ${state.base_url}/users
134+
url: '{state.base_url}/users'
135135
# Method overrides default if needed
136136
method: "GET"
137137
# Headers merged with defaults.request.headers
138138
headers:
139139
X-Custom-Header: "value"
140140
# URL query parameters
141141
parameters:
142-
page: "${state.page}"
143-
limit: "${state.limit}"
144-
updated_since: "${state.updated_since}" # Use the state variable
142+
page: "{state.page}"
143+
limit: "{state.limit}"
144+
updated_since: "{state.updated_since}" # Use the state variable
145145

146146
# Pagination configuration
147147
pagination:
148148
# How to update state for the next page request
149149
next_state:
150-
page: "${state.page + 1}"
150+
page: "{state.page + 1}"
151151
# Overrides default stop_condition
152152
stop_condition: "response.json.page >= response.json.total_pages"
153153

@@ -203,7 +203,7 @@ endpoints:
203203

204204
request:
205205
# Use the iterated user ID in the URL
206-
url: ${state.base_url}/users/${state.current_user_id}
206+
url: '{state.base_url}/users/{state.current_user_id}'
207207
method: "GET"
208208

209209
response:
@@ -240,7 +240,7 @@ endpoints:
240240
concurrency: 10 # Process 10 products concurrently
241241
242242
request:
243-
url: ${state.base_url}/products/${state.current_product_id}/inventory
243+
url: '{state.base_url}/products/{state.current_product_id}/inventory'
244244
# ... other request config ...
245245
response:
246246
# ... response config ...
@@ -259,18 +259,18 @@ authentication:
259259
260260
# Basic Auth
261261
type: "basic"
262-
username: "${secrets.username}"
263-
password: "${secrets.password}"
262+
username: "{secrets.username}"
263+
password: "{secrets.password}"
264264
265265
# Bearer Token
266266
type: "bearer"
267-
token: "${secrets.api_token}" # Can use secrets, env, or state vars
267+
token: "{secrets.api_token}" # Can use secrets, env, or state vars
268268
269269
# OAuth2 - Client Credentials Flow (recommended for server-to-server)
270270
type: "oauth2"
271271
flow: "client_credentials"
272-
client_id: "${secrets.oauth_client_id}"
273-
client_secret: "${secrets.oauth_client_secret}"
272+
client_id: "{secrets.oauth_client_id}"
273+
client_secret: "{secrets.oauth_client_secret}"
274274
authentication_url: "https://api.example.com/oauth/token"
275275
scopes:
276276
- "read:data"
@@ -279,8 +279,8 @@ authentication:
279279
# OAuth2 - Authorization Code Flow (interactive mode for CLI)
280280
type: "oauth2"
281281
flow: "authorization_code"
282-
client_id: "${secrets.oauth_client_id}"
283-
client_secret: "${secrets.oauth_client_secret}"
282+
client_id: "{secrets.oauth_client_id}"
283+
client_secret: "{secrets.oauth_client_secret}"
284284
authentication_url: "https://api.example.com/oauth/token"
285285
# redirect_uri: "" # Leave empty for automatic localhost server
286286
scopes:
@@ -289,29 +289,29 @@ authentication:
289289
# OAuth2 - Authorization Code Flow (manual mode for web apps)
290290
type: "oauth2"
291291
flow: "authorization_code"
292-
client_id: "${secrets.oauth_client_id}"
293-
client_secret: "${secrets.oauth_client_secret}"
292+
client_id: "{secrets.oauth_client_id}"
293+
client_secret: "{secrets.oauth_client_secret}"
294294
authentication_url: "https://api.example.com/oauth/token"
295295
redirect_uri: "https://myapp.example.com/callback"
296-
token: "${secrets.authorization_code}" # Pre-obtained authorization code
296+
token: "{secrets.authorization_code}" # Pre-obtained authorization code
297297
298298
# OAuth2 - Resource Owner Password Credentials (deprecated, avoid if possible)
299299
type: "oauth2"
300300
flow: "password"
301-
client_id: "${secrets.oauth_client_id}"
302-
client_secret: "${secrets.oauth_client_secret}"
303-
username: "${secrets.username}"
304-
password: "${secrets.password}"
301+
client_id: "{secrets.oauth_client_id}"
302+
client_secret: "{secrets.oauth_client_secret}"
303+
username: "{secrets.username}"
304+
password: "{secrets.password}"
305305
authentication_url: "https://api.example.com/oauth/token"
306306
scopes:
307307
- "read:user"
308308
309309
# OAuth2 - Refresh Token Flow
310310
type: "oauth2"
311311
flow: "refresh_token"
312-
client_id: "${secrets.oauth_client_id}" # Optional for some providers
313-
client_secret: "${secrets.oauth_client_secret}" # Optional for some providers
314-
refresh_token: "${secrets.refresh_token}"
312+
client_id: "{secrets.oauth_client_id}" # Optional for some providers
313+
client_secret: "{secrets.oauth_client_secret}" # Optional for some providers
314+
refresh_token: "{secrets.refresh_token}"
315315
authentication_url: "https://api.example.com/oauth/token"
316316
```
317317

@@ -329,21 +329,21 @@ authentication:
329329

330330
## Variable Scopes and Expressions
331331

332-
Sling uses `${...}` syntax for embedding expressions and accessing variables within YAML strings. Expressions are evaluated using the `goval` library with custom functions.
332+
Sling uses `{...}` syntax for embedding expressions and accessing variables within YAML strings. Expressions are evaluated using the `goval` library with custom functions.
333333

334334
Available variable scopes:
335-
- `env`: Environment variables (e.g., `${env.USER}`).
336-
- `secrets`: Sensitive credentials passed to Sling (e.g., `${secrets.api_key}`).
335+
- `env`: Environment variables (e.g., `{env.USER}`).
336+
- `secrets`: Sensitive credentials passed to Sling (e.g., `{secrets.api_key}`).
337337
- `state`: Variables defined in `defaults.state` or `endpoints.<name>.state`. These are local to each endpoint iteration and can be updated by pagination (`next_state`) or processors (`output: state.<var>`).
338-
- `sync`: Persistent state variables read at the start of an endpoint run (values from the previous run's `state` matching the `sync` list). Use `${coalesce(sync.var, state.var, default_value)}`.
339-
- `auth`: Authentication data after successful authentication (e.g., `${auth.token}` for OAuth2 access tokens, refresh tokens stored here).
338+
- `sync`: Persistent state variables read at the start of an endpoint run (values from the previous run's `state` matching the `sync` list). Use `{coalesce(sync.var, state.var, default_value)}`.
339+
- `auth`: Authentication data after successful authentication (e.g., `{auth.token}` for OAuth2 access tokens, refresh tokens stored here).
340340
- `request`: Information about the current HTTP request being made (available in rule/pagination evaluation). Includes `request.url`, `request.method`, `request.headers`, `request.payload`, `request.attempts`.
341341
- `response`: Information about the HTTP response received (available in rule/pagination/processor evaluation). Includes `response.status`, `response.headers`, `response.text`, `response.json` (parsed body), `response.records` (extracted records).
342342
- `record`: The current data record being processed by a processor (available only within `response.processors`).
343343
- `queue`: Access queues declared at the top level (e.g., `iterate.over: queue.my_queue`).
344344
- `null`: Represents a null value (e.g., `coalesce(state.value, null)`).
345345

346-
State variables (`state.`) within an endpoint have a defined render order. If `state.b` depends on `state.a` (`state.b: "${state.a + 1}"`), `state.a` will be evaluated first. Circular dependencies are detected and cause an error.
346+
State variables (`state.`) within an endpoint have a defined render order. If `state.b` depends on `state.a` (`state.b: "{state.a + 1}"`), `state.a` will be evaluated first. Circular dependencies are detected and cause an error.
347347

348348
## Endpoints
349349

@@ -369,26 +369,26 @@ Endpoints define specific API operations. They inherit settings from `defaults`
369369
```yaml
370370
request:
371371
# Request full URL, can includ state variables
372-
url: "${state.base_url}/users/${state.user_id}?active=true"
372+
url: "{state.base_url}/users/{state.user_id}?active=true"
373373
# Method: GET, POST, PUT, PATCH, DELETE, etc.
374374
method: "POST"
375375
# Headers: Merged with defaults.request.headers
376376
headers:
377377
Content-Type: "application/json"
378-
Authorization: "Bearer ${auth.token}"
379-
X-Request-ID: "${uuid()}"
378+
Authorization: "Bearer {auth.token}"
379+
X-Request-ID: "{uuid()}"
380380
# Parameters: Added as URL query parameters for GET/DELETE,
381381
# or form-encoded body for POST/PUT/PATCH if Content-Type is application/x-www-form-urlencoded
382382
parameters:
383-
page: ${state.page}
383+
page: {state.page}
384384
limit: 100
385385
status: "active"
386386
# Payload: Used as request body for POST/PUT/PATCH.
387387
# Can be a string, map, or list. Will be JSON-encoded if Content-Type is application/json.
388388
payload:
389389
user:
390390
name: "New User"
391-
email: "${state.user_email}"
391+
email: "{state.user_email}"
392392
# Timeout: Request timeout in seconds (default: 30)
393393
timeout: 60
394394
# Rate: Max requests per second for this endpoint (default: 2)
@@ -430,7 +430,7 @@ iterate:
430430
concurrency: 10
431431
request:
432432
parameters:
433-
date: ${date_format(state.current_day, "%Y-%m-%d")}
433+
date: '{date_format(state.current_day, "%Y-%m-%d")}'
434434
# ... other params ...
435435
```
436436

@@ -445,7 +445,7 @@ iterate:
445445
request:
446446
parameters:
447447
# Join the batch of IDs into a comma-separated string for the API parameter
448-
ids: ${join(state.variant_id_batch, ",")}
448+
ids: '{join(state.variant_id_batch, ",")}'
449449
```
450450

451451
## Pagination
@@ -458,14 +458,14 @@ pagination:
458458
# Expressions are evaluated based on the *current* state and response (if needed).
459459
next_state:
460460
# Example 1: Cursor-based (using last record ID)
461-
starting_after: "${response.records[-1].id}"
461+
starting_after: "{response.records[-1].id}"
462462
# Example 2: Page number based
463-
# page: "${state.page + 1}"
463+
# page: "{state.page + 1}"
464464
# Example 3: Offset based
465-
# offset: "${state.offset + state.limit}"
465+
# offset: "{state.offset + state.limit}"
466466
# Example 4: Using URL from response header (e.g., Link header)
467467
# url: >
468-
# ${
468+
# {
469469
# if(contains(response.headers.link, "rel=\"next\""),
470470
# trim(split_part(split(response.headers.link, ",")[0], ";", 0), "<>"),
471471
# null # Or keep current state.url? Needs careful handling.
@@ -562,7 +562,7 @@ endpoints:
562562
# Read the last sync timestamp from persistent state ('sync.last_sync_ts').
563563
# If it's the first run (sync.last_sync_ts is null), use a default start date.
564564
start_timestamp: >
565-
${ coalesce(
565+
{ coalesce(
566566
sync.last_sync_ts,
567567
date_format(date_add(now(), -7, 'day'), '%Y-%m-%dT%H:%M:%SZ')
568568
)
@@ -575,7 +575,7 @@ endpoints:
575575
576576
request:
577577
parameters:
578-
updated_since: "${state.start_timestamp}"
578+
updated_since: "{state.start_timestamp}"
579579
580580
response:
581581
processors:
@@ -589,8 +589,8 @@ endpoints:
589589

590590
**Workflow:**
591591
1. **Run Start:** Sling loads persisted sync values (e.g., `last_sync_ts` from the previous run) into the `sync.` scope.
592-
2. **State Initialization:** The endpoint's `state` is initialized. Expressions like `${coalesce(sync.last_sync_ts, ...)}` read the persisted value or use a default.
593-
3. **Requests:** Requests are made using the initialized state (e.g., `updated_since: "${state.start_timestamp}"`).
592+
2. **State Initialization:** The endpoint's `state` is initialized. Expressions like `{coalesce(sync.last_sync_ts, ...)}` read the persisted value or use a default.
593+
3. **Requests:** Requests are made using the initialized state (e.g., `updated_since: "{state.start_timestamp}"`).
594594
4. **Processing:** Processors update state variables (e.g., `output: state.last_sync_ts`, `aggregation: maximum`).
595595
5. **Run End:** The final values of the state variables listed in the `sync` array (e.g., `state.last_sync_ts`) are persisted for the next run.
596596

@@ -606,13 +606,13 @@ description: "API Description"
606606
607607
authentication:
608608
type: "bearer" # bearer|basic|oauth2|""
609-
token: "${secrets.api_token}" # Or username/password, or OAuth2 config
609+
token: "{secrets.api_token}" # Or username/password, or OAuth2 config
610610
611611
# OAuth2 Client Credentials example (most common for APIs):
612612
# type: "oauth2"
613613
# flow: "client_credentials"
614-
# client_id: "${secrets.oauth_client_id}"
615-
# client_secret: "${secrets.oauth_client_secret}"
614+
# client_id: "{secrets.oauth_client_id}"
615+
# client_secret: "{secrets.oauth_client_secret}"
616616
# authentication_url: "https://api.example.com/oauth/token"
617617
# scopes: ["read:data"]
618618
@@ -635,23 +635,23 @@ endpoints:
635635
description: "Fetch a list of items"
636636
state:
637637
# Example state for pagination or filtering
638-
starting_after: ${sync.last_item_id} # For cursor pagination + incremental
639-
created_since: ${coalesce(sync.last_sync_time, date_format(date_add(now(), -1, 'day'), '%Y-%m-%d'))}
638+
starting_after: '{sync.last_item_id}' # For cursor pagination + incremental
639+
created_since: '{coalesce(sync.last_sync_time, date_format(date_add(now(), -1, 'day'), '%Y-%m-%d'))}'
640640
641641
# Persist last item ID and timestamp for next run
642642
sync: [last_item_id, last_sync_time]
643643
644644
request:
645-
url: "${state.base_url}/items" # Relative to defaults.request.url
645+
url: "{state.base_url}/items" # Relative to defaults.request.url
646646
parameters:
647-
limit: ${state.limit}
648-
starting_after: ${state.starting_after}
649-
created_since: ${state.created_since}
647+
limit: '{state.limit}'
648+
starting_after: '{state.starting_after}'
649+
created_since: '{state.created_since}'
650650
651651
pagination:
652652
# Update 'starting_after' state with the ID of the last record from the response
653653
next_state:
654-
starting_after: "${response.records[-1].id}"
654+
starting_after: "{response.records[-1].id}"
655655
# Stop when the API indicates no more pages or returns an empty list
656656
stop_condition: "!response.json.has_more || length(response.records) == 0"
657657
@@ -690,7 +690,7 @@ endpoints:
690690
# into: "state.current_item_id"
691691
# concurrency: 10
692692
# request:
693-
# url: "${state.base_url}/items/${state.current_item_id}"
693+
# url: "{state.base_url}/items/{state.current_item_id}"
694694
# response:
695695
# records:
696696
# jmespath: "data" # Assuming single item response
@@ -702,7 +702,7 @@ endpoints:
702702

703703
## Expression Functions
704704

705-
You can use the following functions within `${...}` expressions in your API spec. Functions provide capabilities for data manipulation, type casting, date operations, control flow, and more.
705+
You can use the following functions within `{...}` expressions in your API spec. Functions provide capabilities for data manipulation, type casting, date operations, control flow, and more.
706706

707707
**IMPORTANT:** Always use double quotes (`"`) for string literals in expressions, never single quotes (`'`). This is required by the [goval](https://github.com/maja42/goval) expression library that Sling uses.
708708

@@ -777,7 +777,7 @@ Uses Go's `time` package and `strftime` conventions via [timefmt-go](https://git
777777
# Format for API parameter (ISO 8601 with timezone)
778778
request:
779779
parameters:
780-
updated_since: "${date_format(date_add(now(), -1, 'hour'), '%Y-%m-%dT%H:%M:%SZ')}"
780+
updated_since: "{date_format(date_add(now(), -1, 'hour'), '%Y-%m-%dT%H:%M:%SZ')}"
781781
```
782782

783783
### Value Handling Functions

0 commit comments

Comments
 (0)