Skip to content

Commit f652452

Browse files
committed
Sync open source content 🐝 (from cc0300de91a92e138494a3509c3733af6a0b86a5)
1 parent dd4bd25 commit f652452

File tree

1 file changed

+312
-0
lines changed

1 file changed

+312
-0
lines changed

docs/manage/forward-compatibility.mdx

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
---
2+
title: Forward compatibility
3+
description: >
4+
Learn how Speakeasy-generated SDKs handle forward compatibility
5+
with new fields, enum values, and unexpected data.
6+
---
7+
8+
import { Callout, CodeWithTabs, Table } from "@/mdx/components";
9+
10+
# Forward compatibility
11+
12+
This guide explains how Speakeasy-generated SDKs maintain forward compatibility when APIs evolve. Forward compatibility ensures older SDK versions continue to work correctly when the API adds new fields, enum values, or other data.
13+
14+
## Forward compatibility at a glance
15+
16+
<Callout type="info">
17+
Forward compatibility ensures older SDK versions continue to work when APIs
18+
evolve. The table below shows which changes are safe and which require special
19+
handling.
20+
</Callout>
21+
22+
<Table
23+
data={[
24+
{
25+
change: "New Field Added",
26+
status: "",
27+
impact:
28+
"**Safe change.** Older SDKs automatically ignore unknown fields in API responses, allowing seamless evolution.",
29+
},
30+
{
31+
change: "New Enum Value in Open Enum",
32+
status: "",
33+
impact:
34+
"**Safe change.** With `x-speakeasy-unknown-values: allow`, SDKs handle new enum values gracefully through language-specific mechanisms.",
35+
},
36+
{
37+
change: "New Enum Value in Closed Enum",
38+
status: "",
39+
impact:
40+
"**Breaking change.** Older SDKs will reject responses with unknown enum values. Convert to open enums using `x-speakeasy-unknown-values: allow`.",
41+
},
42+
{
43+
change: "Type Change",
44+
status: "",
45+
impact:
46+
"**Breaking change.** Changing a field's type (e.g., string to integer) will cause deserialization errors in older SDKs.",
47+
},
48+
{
49+
change: "Required request field → Optional",
50+
status: "",
51+
impact:
52+
"**Safe change.** Older SDKs will continue to send the field, while newer SDKs can omit it when not needed.",
53+
},
54+
{
55+
change: "Optional request field → Required",
56+
status: "⚠️",
57+
impact:
58+
"**Depends on client implementation.** If clients were already sending the optional field, they'll continue working. If they weren't, requests will fail with validation errors.",
59+
},
60+
{
61+
change: "Required response field → Optional",
62+
status: "",
63+
impact:
64+
"**Breaking change.** Older SDKs expect this field to always be present and may throw errors when it's missing.",
65+
},
66+
{
67+
change: "Required response field → Optional with Default",
68+
status: "",
69+
impact:
70+
"**Safe with proper default value.** When the field is omitted, the API returns a default value, preventing errors in older SDKs.",
71+
},
72+
]}
73+
columns={[
74+
{ key: "change", header: "API Change" },
75+
{ key: "status", header: "Status" },
76+
{ key: "impact", header: "Impact & Handling" },
77+
]}
78+
/>
79+
80+
## Common forward compatibility scenarios
81+
82+
This section covers the most frequent scenarios encountered when evolving APIs and how Speakeasy handles them to maintain forward compatibility.
83+
84+
### Handling new fields
85+
86+
Adding new fields to API responses is safe because older SDK versions ignore these fields. When an API response includes fields not defined in the SDK's model, these fields are simply not deserialized.
87+
88+
<CodeWithTabs>
89+
90+
```yaml !!tabs Original Schema
91+
type: object
92+
properties:
93+
name:
94+
type: string
95+
created_at:
96+
type: string
97+
format: date-time
98+
```
99+
100+
```yaml !!tabs Updated Schema
101+
type: object
102+
properties:
103+
name:
104+
type: string
105+
created_at:
106+
type: string
107+
format: date-time
108+
updated_at: # New field
109+
type: string
110+
format: date-time
111+
```
112+
113+
</CodeWithTabs>
114+
115+
Older SDK versions will continue to work without errors, ignoring the `updated_at` field. This allows APIs to evolve by adding new data without breaking existing integrations.
116+
117+
### Handling new enum values
118+
119+
APIs often need to add new enum values over time. Speakeasy provides the `x-speakeasy-unknown-values` extension to handle this gracefully.
120+
121+
```yaml
122+
status:
123+
type: string
124+
x-speakeasy-unknown-values: allow
125+
enum:
126+
- active
127+
- inactive
128+
- pending
129+
```
130+
131+
When the API adds a new enum value (e.g., `suspended`), older SDK versions handle it according to the language:
132+
133+
- **TypeScript**
134+
- **Python**
135+
- **Go**
136+
- **Java**
137+
138+
This prevents runtime errors when new enum values are encountered, allowing APIs to add new states without breaking existing clients.
139+
140+
### Handling unexpected data
141+
142+
Speakeasy-generated SDKs include built-in mechanisms to handle unexpected data:
143+
144+
1. **Validation errors**: SDKs provide detailed validation errors when unexpected data is received, making debugging easier
145+
146+
2. **OneOf schemas**: When using `oneOf` schemas, SDKs can handle evolving data structures by attempting to match against known variants
147+
148+
3. **Optional fields**: Fields marked as optional in the OpenAPI spec won't cause validation errors if missing
149+
150+
### Handling unexpected response codes
151+
152+
APIs evolve over time and may introduce new response codes. Speakeasy-generated SDKs are designed to handle unexpected response codes gracefully:
153+
154+
```yaml
155+
responses:
156+
"2xx":
157+
description: Success response
158+
content:
159+
application/json:
160+
schema:
161+
$ref: "#/components/schemas/SuccessResponse"
162+
"4xx":
163+
description: Error response
164+
content:
165+
application/json:
166+
schema:
167+
$ref: "#/components/schemas/ErrorResponse"
168+
```
169+
170+
#### Benefits of status code ranges
171+
172+
1. **Flexible status codes**: Using `2xx` and `4xx` patterns allows APIs to add new specific status codes (like `201` or `429`) without breaking existing SDKs
173+
174+
2. **Consistent error handling**: All error responses follow the same structure, making it easier to handle new error types
175+
176+
3. **Graceful degradation**: Even when encountering unexpected status codes, SDKs can still extract useful information from the response
177+
178+
When an API returns a status code that wasn't explicitly defined in the original specification, Speakeasy SDKs:
179+
180+
- Match it to the appropriate range (`2xx`, `4xx`, `5xx`)
181+
- Parse the response using the defined schema for that range
182+
- Provide access to both the status code and response body
183+
184+
## Advanced forward compatibility techniques
185+
186+
These advanced techniques help maintain forward compatibility in more complex scenarios.
187+
188+
### Deprecating fields
189+
190+
When evolving APIs, deprecating fields is a common necessity. Speakeasy provides extensions to handle field deprecation gracefully while maintaining forward compatibility:
191+
192+
```yaml
193+
properties:
194+
name:
195+
type: string
196+
sku:
197+
type: string
198+
deprecated: true
199+
x-speakeasy-deprecation-message: We no longer support the SKU property.
200+
```
201+
202+
#### Benefits of proper deprecation
203+
204+
1. Fields remain accessible to older SDK versions
205+
2. New SDK versions mark these fields with proper deprecation annotations
206+
3. Generated documentation includes deprecation notices
207+
4. Developers receive clear guidance on migration
208+
209+
#### Field removal process
210+
211+
When planning to remove a field entirely:
212+
213+
1. Mark the field as optional first
214+
2. Add deprecation notices with the `deprecated` keyword and `x-speakeasy-deprecation-message`
215+
3. Allow sufficient time for users to update implementations
216+
4. Remove the field only after a suitable deprecation period
217+
218+
### Forward-compatible unions
219+
220+
To create forward-compatible unions that can handle new data types added in the future, use the oneOf pattern with a string fallback:
221+
222+
```yaml
223+
oneOf:
224+
- { type: "dog" }
225+
- { type: "cat" }
226+
- { type: string }
227+
```
228+
229+
#### Benefits of string fallback
230+
231+
1. Provides strongly typed handling for known variants (`dog` and `cat` types)
232+
2. Gracefully captures any future variants as string values
233+
3. Prevents runtime errors when new variants are introduced
234+
4. Allows SDK users to handle unknown variants safely
235+
236+
<Callout type="info" title="Language-specific union handling">
237+
Each language handles these unions differently: - **TypeScript**: Uses native
238+
union types with string fallback - **Python**: Leverages `typing.Union` with
239+
string fallback - **Go**: Generates helper methods for both known and unknown
240+
types - **Java**: Provides type discrimination with generic string handling
241+
</Callout>
242+
243+
## Guard-rails for breaking changes
244+
245+
Speakeasy provides several tools to detect and prevent breaking changes:
246+
247+
### Version your API
248+
249+
Create a versioning strategy for your API to manage breaking changes:
250+
251+
- Use path-based versioning (e.g., `/v1/resource`, `/v2/resource`)
252+
- Include version in request headers (`Api-Version: 2023-01-01`)
253+
- Maintain multiple API versions simultaneously during migration periods
254+
255+
### Add defaults for optional fields
256+
257+
When making required fields optional:
258+
259+
- Always include default values to maintain backward compatibility
260+
- Document the default behavior clearly
261+
- Use the `default` property in your OpenAPI specification:
262+
```yaml
263+
properties:
264+
status:
265+
type: string
266+
default: "active"
267+
```
268+
269+
### Open your enums
270+
271+
Convert closed enums to open enums using the Speakeasy extension:
272+
273+
```yaml
274+
status:
275+
type: string
276+
x-speakeasy-unknown-values: allow
277+
enum:
278+
- active
279+
- inactive
280+
- pending
281+
```
282+
283+
### Use the OpenAPI diff tool
284+
285+
The [OpenAPI diff tool](/docs/speakeasy-reference/cli/openapi/diff) identifies potential breaking changes between API specification versions:
286+
287+
```bash
288+
speakeasy openapi diff --base v1.yaml --revision v2.yaml
289+
```
290+
291+
This highlights changes that might break backward compatibility, such as:
292+
293+
- Removing required fields
294+
- Changing field types
295+
- Modifying oneOf schemas
296+
297+
### SDK version management
298+
299+
Speakeasy automatically manages SDK versioning based on the nature of changes:
300+
301+
- Patch version for non-breaking changes
302+
- Minor version for backward-compatible additions
303+
- Major version for breaking changes
304+
305+
### Breaking change notifications
306+
307+
When generating SDKs, Speakeasy detects breaking changes and provides clear notifications about what changed and how to handle the transition.
308+
309+
<Callout type="info" title="Related resources">
310+
For more information about handling breaking changes, see the [breaking
311+
changes guide](./breaking-changes).
312+
</Callout>

0 commit comments

Comments
 (0)