Skip to content

Commit 2b61349

Browse files
nicknisiawolfden
andauthored
Update UpdateUserOpts to allow nil values to remove metadata fields (#453) (#457)
* Update UpdateUserOpts to allow for nil values so developers can remove metadata fields * Remove changelog file Co-authored-by: Adam Wolfman <[email protected]>
1 parent c4165ba commit 2b61349

File tree

3 files changed

+82
-9
lines changed

3 files changed

+82
-9
lines changed

pkg/usermanagement/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,18 @@ go get -u github.com/workos/workos-go/v4/pkg/usermanagement
1313
## How it works
1414

1515
See the [User Management integration guide](https://workos.com/docs/user-management/).
16+
17+
### Update user metadata and remove a key by sending JSON null
18+
19+
To set a metadata value to null (and remove it server-side), pass a `nil` pointer for that key. The `Metadata` field accepts `map[string]*string`.
20+
21+
```go
22+
lang := "en"
23+
user, err := usermanagement.UpdateUser(ctx, usermanagement.UpdateUserOpts{
24+
User: "user_123",
25+
Metadata: map[string]*string{
26+
"language": &lang,
27+
"legacy_code": nil, // serializes as JSON null
28+
},
29+
})
30+
```

pkg/usermanagement/client.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -213,15 +213,15 @@ const (
213213

214214
type UpdateUserOpts struct {
215215
User string
216-
Email string `json:"email,omitempty"`
217-
FirstName string `json:"first_name,omitempty"`
218-
LastName string `json:"last_name,omitempty"`
219-
EmailVerified bool `json:"email_verified,omitempty"`
220-
Password string `json:"password,omitempty"`
221-
PasswordHash string `json:"password_hash,omitempty"`
222-
PasswordHashType PasswordHashType `json:"password_hash_type,omitempty"`
223-
ExternalID string `json:"external_id,omitempty"`
224-
Metadata map[string]string `json:"metadata,omitempty"`
216+
Email string `json:"email,omitempty"`
217+
FirstName string `json:"first_name,omitempty"`
218+
LastName string `json:"last_name,omitempty"`
219+
EmailVerified bool `json:"email_verified,omitempty"`
220+
Password string `json:"password,omitempty"`
221+
PasswordHash string `json:"password_hash,omitempty"`
222+
PasswordHashType PasswordHashType `json:"password_hash_type,omitempty"`
223+
ExternalID string `json:"external_id,omitempty"`
224+
Metadata map[string]*string `json:"metadata,omitempty"`
225225
}
226226

227227
type DeleteUserOpts struct {

pkg/usermanagement/client_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,64 @@ func updateUserTestHandler(w http.ResponseWriter, r *http.Request) {
526526
w.Write(body)
527527
}
528528

529+
func TestUpdateUser_MetadataJSONSerialization_StringValues(t *testing.T) {
530+
lang := "en"
531+
opts := UpdateUserOpts{
532+
Metadata: map[string]*string{
533+
"language": &lang,
534+
},
535+
}
536+
537+
b, err := json.Marshal(opts)
538+
require.NoError(t, err)
539+
540+
var got map[string]interface{}
541+
require.NoError(t, json.Unmarshal(b, &got))
542+
543+
meta, ok := got["metadata"].(map[string]interface{})
544+
require.True(t, ok)
545+
require.Equal(t, "en", meta["language"])
546+
}
547+
548+
func TestUpdateUser_MetadataJSONSerialization_NilValueAsNull(t *testing.T) {
549+
opts := UpdateUserOpts{
550+
Metadata: map[string]*string{
551+
"legacy_code": nil,
552+
},
553+
}
554+
555+
b, err := json.Marshal(opts)
556+
require.NoError(t, err)
557+
558+
// Check raw contains null for the key
559+
require.Contains(t, string(b), "\"legacy_code\":null")
560+
561+
var got map[string]interface{}
562+
require.NoError(t, json.Unmarshal(b, &got))
563+
564+
meta, ok := got["metadata"].(map[string]interface{})
565+
require.True(t, ok)
566+
// JSON null becomes a nil interface value when decoding into map[string]any
567+
_, present := meta["legacy_code"]
568+
require.True(t, present)
569+
require.Nil(t, meta["legacy_code"])
570+
}
571+
572+
func TestUpdateUser_MetadataJSONSerialization_EmptyMapOmitted(t *testing.T) {
573+
opts := UpdateUserOpts{
574+
Metadata: map[string]*string{},
575+
}
576+
577+
b, err := json.Marshal(opts)
578+
require.NoError(t, err)
579+
580+
var got map[string]interface{}
581+
require.NoError(t, json.Unmarshal(b, &got))
582+
583+
_, present := got["metadata"]
584+
require.False(t, present)
585+
}
586+
529587
func TestDeleteUser(t *testing.T) {
530588
tests := []struct {
531589
scenario string

0 commit comments

Comments
 (0)