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

feat: Support universe domain for Discovery based libraries #2675

Merged
merged 5 commits into from
Feb 22, 2024

Conversation

amanda-tarafa
Copy link
Contributor

@jskeet as always, one commit at a time. And I've left a note for you to flag the method we are using from generated code.

@amanda-tarafa amanda-tarafa requested a review from jskeet February 15, 2024 09:16
@amanda-tarafa amanda-tarafa requested a review from a team as a code owner February 15, 2024 09:16
/// Otherwise <paramref name="defaultUri"/>.
/// </list>
/// </returns>
protected internal string GetEffectiveUri(string explicitUri, string defaultUri)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jskeet this is the method that we'll be using from generated code to calculate the base URI and the batch URI. I'll send that PR out tomorrow.

Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

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

A few nits, but generally fine.

public static class HttpRequestMessageExtensions
{
/// <summary>
/// Set's the given key/value pair as a request option.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Remove apostrophe.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, and on the Get's below as well

/// <summary>
/// Extension methods for <see cref="HttpRequestMessage"/>.
/// </summary>
public static class HttpRequestMessageExtensions
Copy link
Collaborator

Choose a reason for hiding this comment

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

Rather than making this public, I wonder whether it would be better to have the same code in both projects. That way we can remove it entirely (eventually - it may be a very long time) without affecting the public API at all. We only really want it to be used in our projects, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, we only want it in our projects. But it's really in 3 projects that we need this: Google.Apis.Core, Google.Apis and Google.Apis.Auth. And, apart from the triplication, we need to keep it very much in sync because what is set on one side, needs to be equivalently read on the other side.
Plus, the dreprecation path for this is very very clear, with the alternative being "use the .NET provided Options collection instead", which is to say, I think we can deprecate it eventually, and remove after some significant time without a major version.

What do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually removing it would then be a binary breaking change, so I'd be nervous about doing that in a minor version.

Given that they need to be kept in sync, how about doing this in one source file that's linked in all three projects? I don't mind it being in the same namespace in all three assemblies.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We discussed offline. A linked file generates some ambiguity issues in test projects so we are going with 3 identical copies.

// it for the batch endpoint as well. The batch endpoint does not have an
// override mechanism, so we pass explicitUri as null in that case.

if (explicitUri is not null)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Possibly convert this all into a conditional ?: operator? (Could even use ?? and then a single ?: operator:

explicitUri ??
(UniverseDomain is not null 
? defaultUri?.Replace(DefaultUniverseDomain, UniverseDomain)
: defaultUri)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep done

/// <summary>
/// Key for a universe domain in a <see cref="HttpRequestMessage"/> options.
/// </summary>
public const string UniverseDomainKey = "__UniverseDomainKey";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does this need to be public?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not really, but all the other keys here were public already.
And we don't have to duplicate it in Google.Apis.Auth.
Happy to make it internal or private though, let me know.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Would prefer to "default to internal" in general. We've definitely made more things public here than was probably wise (and the Google.Apis vs Google.Apis.Core split doesn't help; something we should consider addressing if we ever create a new major version) but I think it's worth trying to stop adding extra public things that don't need to be public.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, made internal.

{
HttpRequestMessage request = new HttpRequestMessage();

GoogleCredential credential = GoogleCredential.FromAccessToken("fake_token");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe just declare this using type IHttpExecuteInterceptor here, to avoid the "as" below?

Copy link
Collaborator

Choose a reason for hiding this comment

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

(Ditto for other tests)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Uy yes, done

}

[Fact]
public async Task UniverseDomain_CustomInRequestAndCredential()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe "DifferentCustomInRequestAndCredential"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep better

if (targetUniverseDomain != credentialUniverseDomain)
{
throw new InvalidOperationException(
$"The service client universe domain {targetUniverseDomain} does not match the credential universe domain {credentialUniverseDomain}.");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Indent

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, done

@amanda-tarafa amanda-tarafa force-pushed the universe-domain-discovery branch from 60c67de to 5f8263e Compare February 16, 2024 00:49
Copy link
Contributor Author

@amanda-tarafa amanda-tarafa left a comment

Choose a reason for hiding this comment

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

@jskeet I've addressed or replied to all your comments. Changes are in ordered commits starting with "Address review".

Let me know what you think about the two remaining threads regarding visibility. I prefer them as they are, but that's not a hard preference for either.

public static class HttpRequestMessageExtensions
{
/// <summary>
/// Set's the given key/value pair as a request option.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, and on the Get's below as well

/// <summary>
/// Extension methods for <see cref="HttpRequestMessage"/>.
/// </summary>
public static class HttpRequestMessageExtensions
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, we only want it in our projects. But it's really in 3 projects that we need this: Google.Apis.Core, Google.Apis and Google.Apis.Auth. And, apart from the triplication, we need to keep it very much in sync because what is set on one side, needs to be equivalently read on the other side.
Plus, the dreprecation path for this is very very clear, with the alternative being "use the .NET provided Options collection instead", which is to say, I think we can deprecate it eventually, and remove after some significant time without a major version.

What do you think?

// it for the batch endpoint as well. The batch endpoint does not have an
// override mechanism, so we pass explicitUri as null in that case.

if (explicitUri is not null)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep done

/// <summary>
/// Key for a universe domain in a <see cref="HttpRequestMessage"/> options.
/// </summary>
public const string UniverseDomainKey = "__UniverseDomainKey";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not really, but all the other keys here were public already.
And we don't have to duplicate it in Google.Apis.Auth.
Happy to make it internal or private though, let me know.

{
HttpRequestMessage request = new HttpRequestMessage();

GoogleCredential credential = GoogleCredential.FromAccessToken("fake_token");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Uy yes, done

}

[Fact]
public async Task UniverseDomain_CustomInRequestAndCredential()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep better

if (targetUniverseDomain != credentialUniverseDomain)
{
throw new InvalidOperationException(
$"The service client universe domain {targetUniverseDomain} does not match the credential universe domain {credentialUniverseDomain}.");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, done

Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

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

All "address review" commits look good to me. I have a preference for avoiding the public extension method, but can live with it if you don't want the internal complexity of a linked source file.

@amanda-tarafa amanda-tarafa force-pushed the universe-domain-discovery branch from 5f8263e to ab34224 Compare February 21, 2024 17:56
Copy link
Contributor Author

@amanda-tarafa amanda-tarafa left a comment

Choose a reason for hiding this comment

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

@jskeet Outstanding visibility concerns addressed in sorted "Address review" commits. PTAL.

(I'll squash most of these before merging)

/// <summary>
/// Key for a universe domain in a <see cref="HttpRequestMessage"/> options.
/// </summary>
public const string UniverseDomainKey = "__UniverseDomainKey";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, made internal.

/// <summary>
/// Extension methods for <see cref="HttpRequestMessage"/>.
/// </summary>
public static class HttpRequestMessageExtensions
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We discussed offline. A linked file generates some ambiguity issues in test projects so we are going with 3 identical copies.


using System.Net.Http;

namespace Google.Apis.Util.Extensions;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why the ".Extensions" bit? We don't have that for TaskExtensions for example.
Perhaps this was left over from trying to do the link version?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's intentional, because in tests we already import Google.Apis.Util for other things. So, if we don't put these in specific namespaces, we'd still have the problem of ambiguity.

Note that most the namespaces in Google.Apis.Core are missing the Core bit (except for a few newly added and interal classes) so in Google.Apis.Core we also have Google.Apis.Util, so there I had to do Google.Apis.Core.Util.Extensions.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Righto. Will take a closer look in the morning, but approve now as I'm sure it's fine - feel free to merge.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, I know what we can do, we can test the one in Google.Apis instead of the one in Google.Apis.Core and then we can get rid of the Extensions in both. We still need to keep the Google.Apis.Core.Util though (instead of Google.Apis.Util that we normally have in Google.Apis.Core).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Another option is to not use them as extension methods in tests - call them with fully-qualified names (Google.Apis.Utils.HttpRequestMessageExtensions.Xyz()) so the collision doesn't matter.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, but that still needs us to have the odd Google.Apis.Core.Utils: it's just Google.Apis.Utils even in Google.Apis.Core, that's the main problem, that in Google.Apis.Core we don't use Core in namespaces. I'm pushing shortly, I've had to use Core or else there's no way to disambiguate, but I was able to drop the Extensions bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Pushed:

  • The third commit is new, so that everything is normalized.
  • And the two Addres Review commits have changed. We still have to use Google.Apis.Core.Utils in Google.Apis.Core even though the norma would have been to use Google.Apis.Utils.

We don't use Core in Google.Apis.Core, just Google.Apis.
The decision is hidden in HttpRequestMessage extension methods.

Note that we had to use the namespace Google.Apis.Core.Utils in the Google.Apis.Core project even though normally it would have been just Google.Apis.Utils.
- The universe domain may be specified through the client service initializer.
- A helper method to calculate effective URIs that takes into account the universe domain. This method is to be used by generated code, see googleapis/gapic-generator-csharp#746.
- The universe domain is passed as a request option for the credential to validate against when intercepting and before setting the token.
@amanda-tarafa amanda-tarafa force-pushed the universe-domain-discovery branch from 17f1315 to 26e3450 Compare February 22, 2024 17:00
@amanda-tarafa
Copy link
Contributor Author

I've squashed everything into more meaningful commits, I'll merge on green.

@amanda-tarafa amanda-tarafa merged commit ec8fdef into main Feb 22, 2024
6 checks passed
@amanda-tarafa amanda-tarafa deleted the universe-domain-discovery branch February 22, 2024 17:02
amanda-tarafa added a commit that referenced this pull request Feb 22, 2024
Features

- Universe domain support:
- feat: [#2675](#2675) Universe domain support for Discovery based libraries.
- feat: [#2635](#2635) Universe domain support for authentication.
amanda-tarafa added a commit that referenced this pull request Feb 22, 2024
Features

- Universe domain support:
  - feat: [#2675](#2675) Universe domain support for Discovery based libraries.
  - feat: [#2635](#2635) Universe domain support for authentication.
amanda-tarafa added a commit that referenced this pull request Feb 22, 2024
Features

- Universe domain support:
  - feat: [#2675](#2675) Universe domain support for Discovery based libraries.
  - feat: [#2635](#2635) Universe domain support for authentication.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants