|
A key consideration in Go SDK design is how to handle unknown
request and response fields and shapes, and relatedly accessing raw
JSON data. Here’s how these compare between v2 and v3.
|
|
|
|
v2 uses separate request and response types. v3 proposes unified
types and introduces an APIData datastructure to capture intent
outside of spec’d fields.
|
type ConfigParam struct {
DarkMode bool `json:"dark_mode"`
Tabs TabConfigParam `json:"tab_config"`
paramObj
}
type TabConfigParam struct {
Spaces int `json:"spaces"`
HardTabs bool `json:"hard_tabs"`
paramObj
}
type Config struct {
DarkMode bool `json:"dark_mode"`
Tabs TabConfig `json:"tab_config"`
JSON struct {
DarkMode respjson.Field
Tabs respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
}
type TabConfig struct {
Spaces int `json:"spaces"`
HardTabs bool `json:"hard_tabs"`
JSON struct {
Spaces respjson.Field
HardTabs respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
}
configReq := api.ConfigParam{}
|
type Config struct {
DarkMode bool `json:"dark_mode"`
Tabs TabConfig `json:"tab_config"`
APIData apidata.APIData `json:"-"`
}
type TabConfig struct {
Spaces int `json:"spaces"`
HardTabs bool `json:"hard_tabs"`
APIData apidata.APIData `json:"-"`
}
configReq := api.Config{}
|
|
For adding undocumented fields in requests, the WithJSONSet
option remains.
|
client.SetConfig(
configReq,
option.WithJSONSet("enable_new_feature", true),
)
|
client.SetConfig(
configReq,
option.WithJSONSet("enable_new_feature", true),
)
|
|
The alternative approach, changing configReq, goes from using an
any map to a simple key / value.
|
configReq.SetExtraFields(map[string]any{
"enable_new_feature": true,
})
client.SetConfig(configReq)
|
configReq.SetField("enable_new_feature", true)
client.SetConfig(configReq)
|
|
Adding nested undocumented fields follows the same patterns.
|
client.SetConfig(
configReq,
option.WithJSONSet("tab_config.prefer_vertical_tabs", true),
)
configReq.Tabs.SetExtraFields(map[string]any{
"prefer_vertical_tabs": true,
})
client.SetConfig(configReq)
|
client.SetConfig(
configReq,
option.WithJSONSet("tab_config.prefer_vertical_tabs", true),
)
configReq.Tabs.SetField("prefer_vertical_tabs", true)
client.SetConfig(configReq)
|
|
Sending undocumented request shapes can still use the
WithRequestBody approach.
|
client.SetConfig(configReq, option.WithRequestBody(123))
|
client.SetConfig(configReq, option.WithRequestBody(123))
|
|
But the param.Override approach is replaced with mutation methods
on APIData.
|
configReq := param.Override[api.ConfigParam](123)
client.SetConfig(configReq)
|
configReq := api.Config{
APIData: apidata.ReplaceWholeObject(123),
}
client.SetConfig(configReq)
|
|
When sending undocumented value types inside objects,
WithJSONSet still works.
|
client.SetConfig(
configReq,
option.WithJSONSet("dark_mode", "auto"),
)
|
client.SetConfig(
configReq,
option.WithJSONSet("dark_mode", "auto"),
)
|
|
In v3, SetField also works — it overrides the field with the
new type.
|
|
configReq.SetField("dark_mode", "auto")
client.SetConfig(configReq)
|
|
When accessing undocumented response fields, v2 returns a
respjson.Field where v3 returns the raw value directly.
|
field := response.JSON.ExtraFields["enable_new_feature"]
raw := field.Raw()
|
raw, ok := response.GetField("enable_new_feature")
|
|
Accessing undocumented nested fields is also cleaner in v3.
|
extra := response.Tabs.JSON.ExtraFields
raw := extra["prefer_vertical_tabs"].Raw()
|
raw, ok := response.Tabs.GetField("prefer_vertical_tabs")
|
|
Accessing raw response values for the whole body and fields is
unchanged.
|
var raw []byte
_, err = client.GetConfig(
..., option.WithResponseBodyInto(&raw),
)
config, err := client.GetConfig(...)
raw := config.RawJSON()
innerRaw := config.Tabs.RawJSON()
|
var raw []byte
_, err = client.GetConfig(
..., option.WithResponseBodyInto(&raw),
)
config, err := client.GetConfig(...)
raw := config.RawJSON()
innerRaw := config.Tabs.RawJSON()
|