Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable configuring dynamic behavior through client options #36887

Merged
merged 25 commits into from
Jun 8, 2023

Conversation

annelo-msft
Copy link
Member

@annelo-msft annelo-msft commented Jun 7, 2023

Property naming conventions for DynamicData

Previously, in order to write code that used dynamic content the same way as an Azure model type, users needed to pass a DynamicCaseMapping enum value to ToDynamicFromJson().

This approach had a number of concerns, from the verbosity of the code that customers needed to write to achieve the intended usage of the type, to concerns about how applicable the enum was to other domains.

This new approach maintains the principle that changing the naming convention of used with dynamic content is 100% opt-in -- by default dynamic property names are mapped exactly to content property names. Following .NET precedent used in other APIs that do this type of case-mapping, it moves the opt-in to a one-time configuration parameter, so it doesn't propagate across every instance where dynamic content is used.

Summary of the API changes

  • DynamicCaseMapping is renamed to PropertyNamingConvention, with values that align with names from STJ JsonNamingPolicy. The intention is that we can evolve this to use other policies provided in STJ in the future, based on customer need.
  • PropertyNamingConvention is moved to Azure.Core.Serialization. With this shift, it can be used to create RequestContent and in other serialization domains, e.g. to replace the PropertyNamingPolicy enum on CosmosSerializationOptions in their Track 2 library.
  • ProtocolOptions is added to ClientOptions -- callers set the naming convention to be used with response content on the client -- this scopes the convention to a given service. So, for example, one service can use camel case and another can use snake case, and it will all function correctly when users write code substitutable for code written at the convenience layer, without needing to pass parameters to ToDynamicFromJson().

Approaches considered

We spent a lot of time exploring a number of different approaches to solving this problem before arriving at this solution. For completeness, here is the list of explorations done:

Adresses #36642

@annelo-msft
Copy link
Member Author

Need to incorporate comments from the original PR for this: #36868

@azure-sdk
Copy link
Collaborator

azure-sdk commented Jun 7, 2023

API change check

APIView has identified API level changes in this PR and created following API reviews.

Azure.Core

public enum PropertyNamingConvention
{
None = 0,
CamelCase = 1,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I worry these names aren't clear enough. I thought this was how we're managing dynamic binding resolution (i.e., allowing pascal case), but it looks like we're also using this on RequestContent.Create to control how we serialize?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For what it's worth, I still really like [Flags] public enum DynamicBindingFlags { None = 0, AllowPascalCase = 1, IgnoreCase = 2, IgnoreSeparators = 4, ... } as a separate concept to really hammer home the dynamic renaming half of the equation.

Copy link
Member Author

@annelo-msft annelo-msft Jun 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We explored the flags enum approach, and it had a number of negatives. This is the approach I'd like to take because I think it sets us up best to evolve the type in response to customer feedback. It follows precedents set in a variety of other .NET APIs, for databases and serialization, so I have higher confidence that it will be both consistent and evolvable over other approaches we've considered.

@annelo-msft annelo-msft requested a review from AlexanderSher June 8, 2023 18:23
@annelo-msft annelo-msft marked this pull request as ready for review June 8, 2023 19:34
Copy link
Member

@JoshLove-msft JoshLove-msft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a nice compromise between making sure the re-casing is opt-in and also making it convenient for users. I left a few comments about the API naming, but I assume that will be discussed again before shipping.

@annelo-msft annelo-msft mentioned this pull request Jun 8, 2023
41 tasks
@annelo-msft annelo-msft enabled auto-merge (squash) June 8, 2023 21:38
@annelo-msft annelo-msft merged commit 1b82fa6 into Azure:main Jun 8, 2023
@KrzysztofCwalina
Copy link
Member

What happens when client options say one thing and ToDynamic says another? I assume the ToDynamic wins, but it might be good to describe it in the PR descriptions.

@annelo-msft
Copy link
Member Author

What happens when client options say one thing and ToDynamic says another? I assume the ToDynamic wins, but it might be good to describe it in the PR descriptions.

The precedence rules are:

  • ToDynamic value overrides ClientOptions value
  • Property indexer bypasses all settings

This is documented in the samples, but I'm happy to add it to any refdoc comments where you think it would be helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants