auth0/auth0.net

Please add methods PutAppMetadata<T> and PutUserMetadata<T> for User to function as a merge

mharrisn opened this issue · 3 comments

Checklist

  • I have looked into the Readme and have not found a suitable solution or answer.
  • I have looked into the API documentation and have not found a suitable solution or answer.
  • I have searched the issues and have not found a suitable solution or answer.
  • I have searched the Auth0 Community forums and have not found a suitable solution or answer.
  • I agree to the terms within the Auth0 Code of Conduct.

Describe the problem you'd like to have solved

It appears that if you call the existing methods SetAppMetadata or SetUserMetadata, they replace the entire JSON representation of app_metadata and user_metadata respectively. Given the dynamic nature of these spaces, it would be ideal to have the ability to only set the portion of the object that your use case is concerned with. This would avoid the risk of inadvertently overwriting JSON that another application/team requires without a lot of JSON manipulation code - plus we keep the benefits of type safety.

Describe the ideal solution

Assuming I have classes like this:

public class AcmeAppMetadata {
    public MyGreatFeatureSettings MyGreatFeatureSettings {get; set;}
}
public class MyGreatFeatureSettings {
    public int? NumberOfTimesIveBeenCalledAwesome {get; set;}
}

So if we want to update the app metadata for only the myGreatFeatureSettings child object of the metadata object, we could use something like a Put:

// Get the slice of metadata we care about
var userData = myUser.GetAppMetadata<AcmeAppMetadata>();
userData.MyGreatFeatureSettings.NumberOfTimesIveBeenCalledAwesome = 1000;

// Set only the slice of metadata that we care about - without impacting any other JSON nodes
myUser.PutAppMetadata<AcmeAppMetadata>(userData);

Alternatives and current workarounds

Calling SetAppMetadata blows out the entire JSON Object with only what's defined in the current object being applied. This is problematic for larger teams where there may be different use cases that need to be covered. An option to Put/Merge the object would be fantastic.

To avoid potentially overwriting nodes that other teams may need, I have to write a bunch of JSON traversing code to modify AppMetadata in dotnet. This feature would make it trivial to modify the portions of the JSON that are a concern for our use case without impacting other teams.

Additional context

No response

Thanks for reaching out. I am not sure I understand what you are asking.

Given the dynamic nature of these spaces, it would be ideal to have the ability to only set the portion of the object that your use case is concerned with. This would avoid the risk of inadvertently overwriting JSON that another application/team requires without a lot of JSON manipulation code - plus we keep the benefits of type safety.

Put is about replacing the entire object, so I do not see how it would help in the above scenario.

Can you elaborate how the following:

// Get the slice of metadata we care about
var userData = myUser.GetAppMetadata<AcmeAppMetadata>();
userData.MyGreatFeatureSettings.NumberOfTimesIveBeenCalledAwesome = 1000;

// Set only the slice of metadata that we care about - without impacting any other JSON nodes
myUser.PutAppMetadata<AcmeAppMetadata>(userData);

would differ from what we currently have:

// Get the slice of metadata we care about
var userData = myUser.GetAppMetadata<AcmeAppMetadata>();
userData.MyGreatFeatureSettings.NumberOfTimesIveBeenCalledAwesome = 1000;

// Set only the slice of metadata that we care about - without impacting any other JSON nodes
myUser.SetAppMetadata<AcmeAppMetadata>(userData);

I just don't see the difference, as put is basically the HTTP METHOD that corresponds with "set" terminology. I have a feeling you are referring to patch rather than put. However, that is not something the user class should be concerned about and something you need to write your self. Alof of classes in any kind of SDK expose getter/setters, if you want to only partially set something you'll need to work around that as well, so I am not sure I can see the difference here.

Thank you for the reply - I apologize for the confusion - PATCH behavior is what I meant. The ability to update only a portion of the entire object would be incredibly useful from a DX perspective. There is an API available as part of the post-login Action Triggers that seems to be perfect:

api.user.setAppMetadata(name, value)
api.user.setUserMetadata(name, value)

//  name | string. The name of metadata property.
//  value | any. The value of the metadata property. This may be set to null to remove the metadata property.

My request came from the fact that writing this on my own is cumbersome and error-prone. We have several dev teams that need to write data to the appMetaData. The risk of someone making a mistake is much greater when using the dotnet SDK since it's so easy to accidentally clobber the entire object when the intention is only to update a particular key. So I think a great solution could be something like:

// Set only the slice of metadata that we care about - without impacting any other JSON nodes
var key = "MyGreatFeatureSettings";
myUser.PatchAppMetadata< MyGreatFeatureSettings >(key, userData);

It would also be cool to have the ability to get a partial slice by allowing for an optional key to be passed to get:

// Get the slice of metadata we care about. (Add ability to pass a string argument)
var key = "MyGreatFeatureSettings";
var userData = myUser.GetAppMetadata<MyGreatFeatureSettings>(key);
userData.NumberOfTimesIveBeenCalledAwesome = 1000;

Thanks for getting back with that information.

I do have to admit that I do not think this should be part of the User class in our SDK. We provide a .NET library around the Auth0 Management API. The API accepts a user_metadata/app_metadata object, and it overrides whatever is already on the server with what you send along. Our SDK represents that behavior.

Even more so I think an API like that can be confusing for people who manually create an update request, and that think that when they start from a blank app_metadata (because they used new User(), and they call PatchAppMetadata , it would not override things on the server. While it will if there is existing app_metadata they did not retrieve first. Therefore it makes more sense for our SDK to not be concerned about existing vs new metadata, but enforce you to take control of that.

If you need additional logic to the layer we provide on top of the API, nothing stops you from doing that in your own code, which you can still distribute across the different teams you are talking about.

Closing this for now, as I believe this isn't something we want to add currently.