Skip to content

Commit af3bc95

Browse files
committed
Sync open source content 🐝 (from c6672fc5bfee70a545f585a07abdacf450db5899)
1 parent af93d03 commit af3bc95

5 files changed

Lines changed: 255 additions & 34 deletions

File tree

_meta.global.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ const meta = {
179179
},
180180
},
181181
},
182+
"data-transforms": {
183+
title: "Data transforms",
184+
},
182185
webhooks: {
183186
title: "Add webhooks to your SDKs",
184187
},

docs/cli-generation/customize-cli.mdx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,12 +281,12 @@ The CLI target wraps a generated Go SDK, so many shared SDK/runtime customizatio
281281

282282
The CLI target generates and embeds a Go SDK under the hood. Many shared SDK/runtime concepts still apply, including:
283283

284-
- [Server configuration](/docs/customize-sdks/servers)
285-
- [Authentication and security](/docs/customize-sdks/authentication/overview)
286-
- [Retries](/docs/customize-sdks/runtime/retries)
287-
- [Pagination](/docs/customize-sdks/runtime/pagination)
288-
- [Error handling](/docs/customize-sdks/responses/errors)
289-
- [Global parameters](/docs/customize-sdks/globals)
284+
- [Server configuration](/docs/sdks/customize/servers)
285+
- [Authentication and security](/docs/sdks/customize/authentication/overview)
286+
- [Retries](/docs/sdks/customize/runtime/retries)
287+
- [Pagination](/docs/sdks/customize/runtime/pagination)
288+
- [Error handling](/docs/sdks/customize/responses/errors)
289+
- [Global parameters](/docs/sdks/customize/globals)
290290

291291
For Go-specific SDK configuration, see the [Go configuration reference](/docs/speakeasy-reference/generation/go-config).
292292

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
---
2+
title: "Data transforms"
3+
description: "Use jq expressions to automatically transform data between the API wire format and the SDK interface."
4+
---
5+
6+
import { Callout } from "@/mdx/components";
7+
8+
# Data transforms
9+
10+
When the shape of data on the wire differs from the shape SDK users should see, use the `x-speakeasy-transform-from-api` and `x-speakeasy-transform-to-api` extensions to bridge the gap automatically. These extensions apply [jq expressions](https://jqlang.org/manual/) to transform data during serialization and deserialization, so SDK users work with a clean interface while the underlying API format is preserved.
11+
12+
<Callout title="Language support" type="info">
13+
Data transforms currently generate transform code for the **Go** target only. Other SDK targets (TypeScript, Python, Java, C#) will silently ignore these extensions.
14+
</Callout>
15+
16+
## When to use data transforms
17+
18+
Data transforms are useful when:
19+
20+
- The API returns a response shape that could be cleaner for SDK consumers, such as deeply nested structures that should be flattened
21+
- The API schema cannot be changed, but the SDK should present a better interface
22+
- Fields need to be derived from other fields, such as combining `first_name` and `last_name` into `display_name`
23+
24+
## Extensions
25+
26+
Place these extensions on a schema in the OpenAPI spec, typically on request body or response schemas.
27+
28+
- `x-speakeasy-transform-from-api`: Transforms data **from** the API response before the SDK user sees it.
29+
- `x-speakeasy-transform-to-api`: Transforms data **to** the API request format before sending.
30+
31+
Both extensions can be used on the same schema when transforms are needed in both directions.
32+
33+
### Format
34+
35+
The value must be a YAML mapping with a `jq` key:
36+
37+
```yaml
38+
x-speakeasy-transform-from-api:
39+
jq: '.your_expression_here'
40+
```
41+
42+
<Callout title="Note" type="info">
43+
The only supported transform type is `jq`. Invalid syntax produces a build error with the expression and the parse error.
44+
</Callout>
45+
46+
## Examples
47+
48+
### Copy a field
49+
50+
```yaml
51+
components:
52+
schemas:
53+
Resource:
54+
type: object
55+
x-speakeasy-transform-from-api:
56+
jq: '. + { backup_id: .id }'
57+
properties:
58+
id:
59+
type: string
60+
```
61+
62+
### Rename a field
63+
64+
```yaml
65+
components:
66+
schemas:
67+
Resource:
68+
type: object
69+
x-speakeasy-transform-to-api:
70+
jq: '{ displayName: .name }'
71+
properties:
72+
name:
73+
type: string
74+
```
75+
76+
### Add a derived field
77+
78+
```yaml
79+
components:
80+
schemas:
81+
User:
82+
type: object
83+
x-speakeasy-transform-from-api:
84+
jq: '. + { display_name: .first_name + " " + .last_name }'
85+
properties:
86+
first_name:
87+
type: string
88+
last_name:
89+
type: string
90+
```
91+
92+
### Flatten a nested structure
93+
94+
```yaml
95+
components:
96+
schemas:
97+
Order:
98+
type: object
99+
x-speakeasy-transform-from-api:
100+
jq: '. + { status: .metadata.status } | del(.metadata)'
101+
properties:
102+
id:
103+
type: string
104+
metadata:
105+
type: object
106+
properties:
107+
status:
108+
type: string
109+
```
110+
111+
### Conditional field addition
112+
113+
```yaml
114+
components:
115+
schemas:
116+
Account:
117+
type: object
118+
x-speakeasy-transform-from-api:
119+
jq: 'if .status == "active" then . + { is_active: true } else . end'
120+
properties:
121+
status:
122+
type: string
123+
```
124+
125+
### Remove a field before sending
126+
127+
```yaml
128+
components:
129+
schemas:
130+
UpdateRequest:
131+
type: object
132+
x-speakeasy-transform-to-api:
133+
jq: 'del(.internal_field)'
134+
properties:
135+
name:
136+
type: string
137+
internal_field:
138+
type: string
139+
```
140+
141+
### Bidirectional transforms
142+
143+
Apply both extensions on the same schema to transform data in both directions:
144+
145+
```yaml
146+
components:
147+
schemas:
148+
Service:
149+
type: object
150+
x-speakeasy-transform-to-api:
151+
jq: '{ displayName: .name, maxInstances: .max_instance_count }'
152+
x-speakeasy-transform-from-api:
153+
jq: '. + { name: .displayName, max_instance_count: .maxInstances }'
154+
properties:
155+
displayName:
156+
type: string
157+
maxInstances:
158+
type: integer
159+
```
160+
161+
### Convert an array to a map
162+
163+
Transform arrays from the API into a simpler map structure:
164+
165+
```yaml
166+
requestBody:
167+
content:
168+
application/json:
169+
schema:
170+
type: object
171+
x-speakeasy-transform-to-api:
172+
jq: |
173+
.tags |= (
174+
if type == "object" then
175+
to_entries | map({key: .key, value: .value})
176+
else
177+
.
178+
end
179+
)
180+
properties:
181+
tags:
182+
type: array
183+
items:
184+
type: object
185+
properties:
186+
key:
187+
type: string
188+
value:
189+
type: string
190+
```
191+
192+
### Build composite identifiers
193+
194+
Create combined identifiers from separate API fields:
195+
196+
```yaml
197+
responses:
198+
"200":
199+
content:
200+
application/json:
201+
schema:
202+
type: object
203+
x-speakeasy-transform-from-api:
204+
jq: |
205+
.id = "projects/\(.project_id)/regions/\(.region)/databases/\(.name)"
206+
properties:
207+
project_id:
208+
type: string
209+
region:
210+
type: string
211+
name:
212+
type: string
213+
```

docs/terraform/customize-terraform/entity-mapping.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,12 @@ data.example_things.items[0].id
579579
`x-speakeasy-wrapped-attribute` to customize it.
580580
</Callout>
581581

582+
### Data transforms
583+
584+
When the shape of data on the wire differs from the structure a Terraform provider should expose, use the `x-speakeasy-transform-from-api` and `x-speakeasy-transform-to-api` extensions to apply [jq expressions](https://jqlang.org/manual/) that automatically reshape data during serialization and deserialization.
585+
586+
For full details on format, available extensions, and examples, see [Data transforms](/docs/sdks/customize/data-transforms).
587+
582588
### Resources with Soft Delete
583589

584590
By default, a generated managed resource uses the HTTP 404 Not Found status code on read to automatically remove the resource from the Terraform state which causes the next Terraform plan to propose recreating the resource. For resource APIs that support soft delete (grace time period before the resource is fully deleted), the `x-speakeasy-soft-delete-property` annotation adds a check against a read response property to also propose resource recreation.

0 commit comments

Comments
 (0)