From 0ddf9735afcde8ebe528d5b8eb8d1e80033d579b Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 20 Mar 2025 21:06:55 +0000
Subject: [PATCH] docs: add migration guide (#302)
---
MIGRATION.md | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 250 insertions(+)
create mode 100644 MIGRATION.md
diff --git a/MIGRATION.md b/MIGRATION.md
new file mode 100644
index 0000000..c269b47
--- /dev/null
+++ b/MIGRATION.md
@@ -0,0 +1,250 @@
+# OpenAI Go Migration Guide
+
+
+
+This SDK includes breaking changes from the previous version to improve the ergonomics of constructing parameters and accessing responses.
+
+# Request parameters
+
+## Required primitives parameters serialize their zero values (`string`, `int64`, etc.)
+
+> [!CAUTION] > **This change can cause new behavior in existing code, without compiler warnings.**
+
+```diff
+type FooParams struct {
+- Age param.Field[int64] `json:"age,required"`
+- Name param.Field[string] `json:"name"`
++ Age int64 `json:"age,required"`
++ Name param.Opt[string] `json:"name,omitzero"`
+}
+```
+
+
+
+| Previous |
+New |
+
+
+|
+
+```go
+_ = FooParams{
+ Name: openai.String("Jerry")
+}
+`{"name": "Jerry"}` // (after serialization)
+```
+
+ |
+
+
+```go
+_ = FooParams{
+ Name: openai.String("Jerry")
+}
+`{"name": "Jerry", "age": 0}` // <== Notice the age field
+```
+
+ |
+
+
+
+The required field `"age"` is now present as `0`. Required primitive fields without the \`json:"...,omitzero"\` struct tag
+are always serialized, including their zero values.
+
+## Transition from `param.Field[T]` to `omitzero`
+
+The new SDK uses \`json:"...,omitzero"\` semantics from Go 1.24+ for JSON encoding[^1].
+
+`omitzero` is used for structs, slices, maps, string enums, and optional primitive types wrapped in `param.Opt[T]` (e.g. `param.Opt[string]`).
+
+**Fields of a request struct:**
+
+```diff
+type FooParams struct {
+- RequiredString param.Field[string] `json:"required_string,required"`
++ RequiredString string `json:"required_string,required"`
+
+- OptionalString param.Field[string] `json:"optional_string"`
++ OptionalString param.Opt[string] `json:"optional_string,omitzero"`
+
+- Array param.Field[[]BarParam] `json"array"`
++ Array []BarParam `json"array,omitzero"`
+
+- Map param.Field[map[string]BarParam] `json"map"`
++ Map map[string]BarParam `json"map,omitzero"`
+
+- RequiredObject param.Field[BarParam] `json:"required_object,required"`
++ RequiredObject BarParam `json:"required_object,omitzero,required"`
+
+- OptionalObject param.Field[BarParam] `json:"optional_object"`
++ OptionalObject BarParam `json:"optional_object,omitzero"`
+
+- StringEnum param.Field[BazEnum] `json:"string_enum"`
++ StringEnum BazEnum `json:"string_enum,omitzero"`
+}
+```
+
+**Previous vs New SDK: Constructing a request**
+
+```diff
+foo = FooParams{
+- RequiredString: openai.String("hello"),
++ RequiredString: "hello",
+
+- OptionalString: openai.String("hi"),
++ OptionalString: openai.String("hi"),
+
+- Array: openai.F([]BarParam{
+- BarParam{Prop: ... }
+- }),
++ Array: []BarParam{
++ BarParam{Prop: ... }
++ },
+
+- RequiredObject: openai.F(BarParam{ ... }),
++ RequiredObject: BarParam{ ... },
+
+- OptionalObject: openai.F(BarParam{ ... }),
++ OptionalObject: BarParam{ ... },
+
+- StringEnum: openai.F[BazEnum]("baz-ok"),
++ StringEnum: "baz-ok",
+}
+```
+
+`param.Opt[string]` can be constructed with `openai.String(string)`. Similar functions exist for other primitive
+types like `openai.Int(int)`, `openai.Bool(bool)`, etc.
+
+## Request Unions: Removing interfaces and moving to structs
+
+For a type `AnimalUnionParam` which could be either a `string | CatParam | DogParam`.
+
+
+| Previous | New |
+
+|
+
+```go
+type AnimalParam interface {
+ ImplAnimalParam()
+}
+
+func (Dog) ImplAnimalParam() {}
+func (Cat) ImplAnimalParam() {}
+```
+
+ |
+
+
+```go
+type AnimalUnionParam struct {
+ OfCat *Cat `json:",omitzero,inline`
+ OfDog *Dog `json:",omitzero,inline`
+}
+```
+
+ |
+
+
+
+|
+
+```go
+var dog AnimalParam = DogParam{
+ Name: "spot", ...
+}
+var cat AnimalParam = CatParam{
+ Name: "whiskers", ...
+}
+```
+
+ |
+
+
+```go
+dog := AnimalUnionParam{
+ OfDog: &DogParam{Name: "spot", ... },
+}
+cat := AnimalUnionParam{
+ OfCat: &CatParam{Name: "whiskers", ... },
+}
+```
+
+ |
+
+
+
+|
+
+```go
+var name string
+switch v := animal.(type) {
+case Dog:
+ name = v.Name
+case Cat:
+ name = v.Name
+}
+```
+
+ |
+
+
+```go
+// Accessing fields
+var name *string = animal.GetName()
+```
+
+ |
+
+
+
+## Sending explicit `null` values
+
+The old SDK had a function `param.Null[T]()` which could set `param.Field[T]` to `null`.
+
+The new SDK uses `param.NullOpt[T]()` for to set a `param.Opt[T]` to `null`,
+and `param.NullObj[T]()` to set a param struct `T` to `null`.
+
+```diff
+- var nullObj param.Field[BarParam] = param.Null[BarParam]()
++ var nullObj BarParam = param.NullObj[BarParam]()
+
+- var nullPrimitive param.Field[int64] = param.Null[int64]()
++ var nullPrimitive param.Opt[int64] = param.NullOpt[int64]()
+```
+
+## Sending custom values
+
+The `openai.Raw[T](any)` function has been removed. All request structs now support a
+`.WithExtraField(map[string]any)` method to customize the fields.
+
+```diff
+foo := FooParams{
+ A: param.String("hello"),
+- B: param.Raw[string](12) // sending `12` instead of a string
+}
++ foo.WithExtraFields(map[string]any{
++ "B": 12,
++ })
+```
+
+# Response Properties
+
+## Checking for presence of optional fields
+
+The `.IsNull()` method has been changed to `.IsPresent()` to better reflect its behavior.
+
+```diff
+- if !resp.Foo.JSON.Bar.IsNull() {
++ if resp.Foo.JSON.Bar.IsPresent() {
+ println("bar is present:", resp.Foo.Bar)
+ }
+```
+
+| Previous | New | Returns true for values |
+| -------------- | ------------------- | ----------------------- |
+| `.IsNull()` | `!.IsPresent()` | `null` or Omitted |
+| `.IsMissing()` | `.Raw() == ""` | Omitted |
+| `.Invalid()` | `.IsExplicitNull()` | `null` |
+
+[^1]: The SDK doesn't require Go 1.24, despite supporting the `omitzero` feature