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

WIP: Apollo Federation V2 merge #6769

Closed
wants to merge 91 commits into from
Closed
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
60a5ea0
Require braces in .editorconfig
AntonC9018 Dec 4, 2023
37fe9d0
Start Migration
michaelstaib Nov 17, 2023
97cb6d0
edits
michaelstaib Nov 17, 2023
56a8bb9
Use result of Assert instead of pattern matching
AntonC9018 Dec 4, 2023
1905492
Add empty list abstraction to simplify node creation logic
AntonC9018 Dec 4, 2023
f23ebf7
Use raw string literals in test
AntonC9018 Dec 4, 2023
32ec7fd
Refactor condition
AntonC9018 Dec 4, 2023
6af10a8
Use raw strings in test
AntonC9018 Dec 4, 2023
b6ef984
Import some of the new code
AntonC9018 Dec 6, 2023
a34ea84
Introduce more order
AntonC9018 Dec 6, 2023
1eba675
Attributes
AntonC9018 Dec 6, 2023
90dd9fe
Add some of the other stuff
AntonC9018 Dec 6, 2023
3d320db
package.lock after restore?
AntonC9018 Dec 8, 2023
a95e52c
Remove redundant imports, fix naming of a few symbols, ignore naming …
AntonC9018 Dec 8, 2023
260672e
Remove imports in tests
AntonC9018 Dec 8, 2023
a368ec6
Add the few new errors
AntonC9018 Dec 8, 2023
0a4deb3
Resources designer regenerated
AntonC9018 Dec 8, 2023
1483a0f
Add virtual method into ScopedStateParameterExpressionBuilder, cache …
AntonC9018 Dec 8, 2023
04ce611
Refactor ReferenceResolverArgumentExpressionBuilder properly
AntonC9018 Dec 8, 2023
2e1871a
Fix initialization of version values
AntonC9018 Dec 8, 2023
b4fc2b0
Fix typo in comment
AntonC9018 Dec 8, 2023
73e52ef
Make maxDepth a const
AntonC9018 Dec 8, 2023
d65f532
The type should not be nullable in the new method
AntonC9018 Dec 8, 2023
2072408
Fix / clarify interceptor
AntonC9018 Dec 8, 2023
83ac7b1
Attributes
AntonC9018 Dec 8, 2023
efc589e
Restore descriptor overloads
AntonC9018 Dec 8, 2023
3625f0d
Fix descriptor extensions
AntonC9018 Dec 8, 2023
47c53e3
Insert braces to scope locals
AntonC9018 Dec 8, 2023
fe724d1
Fix V1 code
AntonC9018 Dec 9, 2023
323db7c
sealing classes in tests
AntonC9018 Dec 9, 2023
84ff546
Restore some old code that's been removed
AntonC9018 Dec 9, 2023
8390a6a
Try and generalize the apollo attributes code in my sort of way
AntonC9018 Dec 9, 2023
86a28d9
Fix typo in error
AntonC9018 Dec 9, 2023
73bbf2a
Forsake my code for DirectiveAttribute
AntonC9018 Dec 9, 2023
7c4c7ba
Make it obvious that the link imports will be copied
AntonC9018 Dec 13, 2023
769aa7f
Fix wrong tests
AntonC9018 Dec 13, 2023
e5ee1aa
Add a helper function for representing input as object
AntonC9018 Dec 13, 2023
51f3fa4
Clear out some things in the interceptor
AntonC9018 Dec 13, 2023
c651e40
Formatting in tests
AntonC9018 Dec 13, 2023
38f2eae
Chop attribute formatting
AntonC9018 Dec 13, 2023
7cdb4bb
Make sure our builder is in fact invoked
AntonC9018 Dec 13, 2023
38ce671
Required imports
AntonC9018 Dec 13, 2023
5c2a8d2
Packages?
AntonC9018 Dec 13, 2023
91e67f4
Update test snapshots
AntonC9018 Dec 13, 2023
ae9e2f2
Update schema printer snapshots
AntonC9018 Dec 13, 2023
ff8ac9e
Ignore last argument of key directive
AntonC9018 Dec 13, 2023
6f08792
Factor out argument node creation for Key directive
AntonC9018 Dec 13, 2023
2b2d602
Fix formatting for parens
AntonC9018 Dec 13, 2023
e6ce035
Remove unused IsEmpty
AntonC9018 Dec 13, 2023
8999c4a
Refinements
michaelstaib Dec 13, 2023
695de79
Refinements
michaelstaib Dec 13, 2023
057be97
Started doing the policy api
AntonC9018 Dec 17, 2023
604a62c
Move MaybeList to helpers
AntonC9018 Dec 18, 2023
eb5f525
Designer
AntonC9018 Dec 18, 2023
77891a3
Merge remote-tracking branch 'origin/anton/apollo-fed-v2' into anton/…
AntonC9018 Dec 18, 2023
33ad2bd
Trailing commas (to be moved to another PR)
AntonC9018 Dec 18, 2023
62a13cf
Refactor scope guards to use throw helpers
AntonC9018 Dec 19, 2023
fffee44
Replace not null or empty scope guards with custom message to regular…
AntonC9018 Dec 19, 2023
60d9176
Apply braces code style in solution (move to another branch?)
AntonC9018 Dec 19, 2023
b565181
Prototyping policy?
AntonC9018 Dec 19, 2023
a3e29ea
Remove wrong doc comment
AntonC9018 Dec 19, 2023
602fa95
Fix PolicyCollection
AntonC9018 Jan 15, 2024
6b203bc
Different names for directive and scalar
AntonC9018 Jan 15, 2024
87ad350
Fix tests
AntonC9018 Jan 15, 2024
3447948
cref -> href
AntonC9018 Jan 15, 2024
70d6b2b
edits
michaelstaib Jan 16, 2024
e8b6653
edits
michaelstaib Jan 16, 2024
2f6ff5e
edits
michaelstaib Jan 16, 2024
c918455
edits
michaelstaib Jan 16, 2024
b16e7aa
edits
michaelstaib Jan 16, 2024
dd28bd5
edits
michaelstaib Jan 16, 2024
1e17510
edits
michaelstaib Jan 16, 2024
495835c
edits
michaelstaib Jan 16, 2024
5909a11
edits
michaelstaib Jan 16, 2024
4bb38e6
edits
michaelstaib Jan 17, 2024
a3186ca
edits
michaelstaib Jan 17, 2024
5f52d05
edits
michaelstaib Jan 17, 2024
ffde862
edits
michaelstaib Jan 17, 2024
14db52b
edits
michaelstaib Jan 17, 2024
79281a3
edits
michaelstaib Jan 17, 2024
e15d078
edits
michaelstaib Jan 17, 2024
29a37c9
edits
michaelstaib Jan 17, 2024
6ca7698
edits
michaelstaib Jan 17, 2024
03311de
it-compiles
michaelstaib Jan 17, 2024
539522b
something-works
michaelstaib Jan 17, 2024
4e0c5cc
something-more-works
michaelstaib Jan 17, 2024
3703983
Merge branch 'main' into anton/apollo-fed-v2
michaelstaib Jan 17, 2024
3a81bde
edits
michaelstaib Jan 17, 2024
a228a21
edits
michaelstaib Jan 17, 2024
560cff4
tests
michaelstaib Jan 17, 2024
3c27293
tests
michaelstaib Jan 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,12 @@ resharper_trailing_comma_in_multiline_lists = true
resharper_wrap_before_binary_pattern_op = false
resharper_wrap_chained_binary_expressions = chop_if_long
resharper_wrap_chained_binary_patterns = chop_if_long

# Require braces on all control statements
resharper_csharp_braces_for_ifelse = required
resharper_csharp_braces_for_for = required
resharper_csharp_braces_for_foreach = required
resharper_csharp_braces_for_while = required
resharper_csharp_braces_for_using = required
resharper_csharp_braces_for_lock = required
resharper_csharp_braces_for_fixed = required
2 changes: 1 addition & 1 deletion src/HotChocolate/ApolloFederation/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@

<PropertyGroup>
<Nullable>enable</Nullable>
<TargetFrameworks>$(Library2TargetFrameworks)</TargetFrameworks>
<TargetFrameworks>$(Library3TargetFrameworks)</TargetFrameworks>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System.Reflection;
using HotChocolate.Types.Descriptors;

namespace HotChocolate.ApolloFederation;

/// <summary>
/// <code>
/// directive @authenticated on
/// ENUM
/// | FIELD_DEFINITION
/// | INTERFACE
/// | OBJECT
/// | SCALAR
/// </code>
///
/// The @authenticated directive is used to indicate that the target element is accessible only to the authenticated supergraph users.
/// For more granular access control, see the <see cref="RequiresScopesDirectiveType">RequiresScopeDirectiveType</see> directive usage.
/// Refer to the <see href="https://www.apollographql.com/docs/router/configuration/authorization#authenticated">Apollo Router article</see>
/// for additional details.
/// <example>
/// type Foo @key(fields: "id") {
/// id: ID
/// description: String @authenticated
/// }
/// </example>
/// </summary>
[AttributeUsage(
AttributeTargets.Class |
AttributeTargets.Enum |
AttributeTargets.Interface |
AttributeTargets.Method |
AttributeTargets.Property |
AttributeTargets.Struct)]
public sealed class ApolloAuthenticatedAttribute : DescriptorAttribute
{
protected internal override void TryConfigure(
IDescriptorContext context,
IDescriptor descriptor,
ICustomAttributeProvider element)
{
switch (descriptor)
{
case IEnumTypeDescriptor enumTypeDescriptor:
{
enumTypeDescriptor.ApolloAuthenticated();
break;
}
case IObjectTypeDescriptor objectFieldDescriptor:
{
objectFieldDescriptor.ApolloAuthenticated();
break;
}
case IObjectFieldDescriptor objectFieldDescriptor:
{
objectFieldDescriptor.ApolloAuthenticated();
break;
}
case IInterfaceTypeDescriptor interfaceTypeDescriptor:
{
interfaceTypeDescriptor.ApolloAuthenticated();
break;
}
case IInterfaceFieldDescriptor interfaceFieldDescriptor:
{
interfaceFieldDescriptor.ApolloAuthenticated();
break;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using HotChocolate.Types.Descriptors;
using static HotChocolate.ApolloFederation.ThrowHelper;

namespace HotChocolate.ApolloFederation;

/// <summary>
/// <code>
/// directive @composeDirective(name: String!) repeatable on SCHEMA
/// </code>
///
/// By default, Supergraph schema excludes all custom directives. The @composeDirective is used to specify
/// custom directives that should be exposed in the Supergraph schema.
///
/// <example>
/// extend schema @composeDirective(name: "@custom")
/// @link(url: "https://specs.apollo.dev/federation/v2.5", import: ["@composeDirective"])
/// @link(url: "https://myspecs.dev/custom/v1.0", import: ["@custom"])
///
/// directive @custom on FIELD_DEFINITION
///
/// type Query {
/// helloWorld: String! @custom
/// }
/// </example>
/// </summary>
[AttributeUsage(
AttributeTargets.Class
| AttributeTargets.Struct,
Inherited = true,
AllowMultiple = true)]
public sealed class ComposeDirectiveAttribute : SchemaTypeDescriptorAttribute
{
/// <summary>
/// Initializes new instance of <see cref="ComposeDirectiveAttribute"/>
/// </summary>
/// <param name="name">
/// Name of the directive that should be preserved in the supergraph composition.
/// </param>
public ComposeDirectiveAttribute(string name)
{
Name = name;
}

/// <summary>
/// Gets the composed directive name.
/// </summary>
public string Name { get; }

public override void OnConfigure(IDescriptorContext context, ISchemaTypeDescriptor descriptor, Type type)
{
if (string.IsNullOrEmpty(Name))
{
throw ComposeDirective_Name_CannotBeEmpty(type);
}
descriptor.ComposeDirective(Name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using HotChocolate.Types.Descriptors;
using static HotChocolate.ApolloFederation.ThrowHelper;

namespace HotChocolate.ApolloFederation;

/// <summary>
/// <code>
/// directive @contact(
/// "Contact title of the subgraph owner"
/// name: String!
/// "URL where the subgraph's owner can be reached"
/// url: String
/// "Other relevant notes can be included here; supports markdown links"
/// description: String
/// ) on SCHEMA
/// </code>
///
/// Contact schema directive can be used to provide team contact information to your subgraph schema. This information is automatically parsed and displayed by Apollo Studio.
/// See <see href="https://www.apollographql.com/docs/graphos/graphs/federated-graphs/#contact-info-for-subgraphs">Subgraph Contact Information</see> for additional details.
///
///
/// <example>
/// <code>
/// schema @contact(description : "send urgent issues to [#oncall](https://yourteam.slack.com/archives/oncall).", name : "My Team Name", url : "https://myteam.slack.com/archives/teams-chat-room-url"){
/// query: Query
/// }
/// </code>
/// </example>
/// </summary>
[AttributeUsage(
AttributeTargets.Class |
AttributeTargets.Struct,
Inherited = true)]
public sealed class ContactAttribute : SchemaTypeDescriptorAttribute
{
/// <summary>
/// Initializes new instance of <see cref="ContactAttribute"/>
/// </summary>
/// <param name="name">
/// Contact title of the subgraph owner
/// </param>
/// <param name="url">
/// URL where the subgraph's owner can be reached
/// </param>
/// <param name="description">
/// Other relevant contact notes; supports markdown links
/// </param>
public ContactAttribute(string name, string? url = null, string? description = null)
{
Name = name;
Url = url;
Description = description;
}

/// <summary>
/// Gets the contact title of the subgraph owner.
/// </summary>
public string Name { get; }

/// <summary>
/// Gets the url where the subgraph's owner can be reached.
/// </summary>
public string? Url { get; }

/// <summary>
/// Gets other relevant notes about subgraph contact information. Can include markdown links.
/// </summary>
public string? Description { get; }

public override void OnConfigure(IDescriptorContext context, ISchemaTypeDescriptor descriptor, Type type)
{
if (string.IsNullOrEmpty(Url))
{
throw Contact_Name_CannotBeEmpty(type);
}
descriptor.Contact(Name, Url, Description);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,19 @@
namespace HotChocolate.ApolloFederation;

/// <summary>
/// This attribute is used to mark types as an extended type
/// of a type that is defined by another service when
/// using apollo federation.
/// <code>
/// directive @extends on OBJECT | INTERFACE
/// </code>
///
/// The @extends directive is used to represent type extensions in the schema. Federated extended types should have
/// corresponding @key directive defined that specifies primary key required to fetch the underlying object.
/// <example>
/// # extended from the Users service
/// type Foo @extends @key(fields: "id") {
/// id: ID
/// description: String
/// }
/// </example>
/// </summary>
[AttributeUsage(
AttributeTargets.Class |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Reflection;
using HotChocolate.Types.Descriptors;

namespace HotChocolate.ApolloFederation;

/// <summary>
/// <code>
/// # federation v1 definition
/// directive @external on FIELD_DEFINITION
///
/// # federation v2 definition
/// directive @external on OBJECT | FIELD_DEFINITION
/// </code>
///
/// The @external directive is used to mark a field as owned by another service.
/// This allows service A to use fields from service B while also knowing at runtime
/// the types of that field. All the external fields should either be referenced from the @key,
/// @requires or @provides directives field sets.
///
/// Due to the smart merging of entity types, Federation v2 no longer requires @external directive
/// on @key fields and can be safely omitted from the schema. @external directive is only required
/// on fields referenced by the @requires and @provides directive.
///
/// <example>
/// type Foo @key(fields: "id") {
/// id: ID!
/// remoteField: String @external
/// localField: String @requires(fields: "remoteField")
/// }
/// </example>
/// </summary>
public sealed class ExternalAttribute : ObjectFieldDescriptorAttribute
{
protected override void OnConfigure(
IDescriptorContext context,
IObjectFieldDescriptor descriptor,
MemberInfo member)
=> descriptor.External();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using System.Reflection;
using HotChocolate.Types.Descriptors;

namespace HotChocolate.ApolloFederation;

/// <summary>
/// <code>
/// directive @inaccessible on FIELD_DEFINITION
/// | OBJECT
/// | INTERFACE
/// | UNION
/// | ENUM
/// | ENUM_VALUE
/// | SCALAR
/// | INPUT_OBJECT
/// | INPUT_FIELD_DEFINITION
/// | ARGUMENT_DEFINITION
/// </code>
///
/// The @inaccessible directive is used to mark location within schema as inaccessible
/// from the GraphQL Router. Applying @inaccessible directive on a type is equivalent of applying
/// it on all type fields.
///
/// While @inaccessible fields are not exposed by the router to the clients, they are still available
/// for query plans and can be referenced from @key and @requires directives. This allows you to not
/// expose sensitive fields to your clients but still make them available for computations.
/// Inaccessible can also be used to incrementally add schema elements (e.g. fields) to multiple
/// subgraphs without breaking composition.
///
/// <example>
/// type Foo @inaccessible {
/// hiddenId: ID!
/// hiddenField: String
/// }
/// </example>
/// </summary>
[AttributeUsage(
AttributeTargets.Class
| AttributeTargets.Enum
| AttributeTargets.Field
| AttributeTargets.Interface
| AttributeTargets.Method
| AttributeTargets.Parameter
| AttributeTargets.Property
| AttributeTargets.Struct
)]
public sealed class InaccessibleAttribute : DescriptorAttribute
{
protected internal override void TryConfigure(
IDescriptorContext context,
IDescriptor descriptor,
ICustomAttributeProvider element)
{
switch (descriptor)
{
case IEnumTypeDescriptor enumTypeDescriptor:
{
enumTypeDescriptor.Inaccessible();
break;
}
case IObjectTypeDescriptor objectFieldDescriptor:
{
objectFieldDescriptor.Inaccessible();
break;
}
case IObjectFieldDescriptor objectFieldDescriptor:
{
objectFieldDescriptor.Inaccessible();
break;
}
case IInterfaceTypeDescriptor interfaceTypeDescriptor:
{
interfaceTypeDescriptor.Inaccessible();
break;
}
case IInterfaceFieldDescriptor interfaceFieldDescriptor:
{
interfaceFieldDescriptor.Inaccessible();
break;
}
case IInputObjectTypeDescriptor inputObjectTypeDescriptor:
{
inputObjectTypeDescriptor.Inaccessible();
break;
}
case IInputFieldDescriptor inputFieldDescriptor:
{
inputFieldDescriptor.Inaccessible();
break;
}
case IUnionTypeDescriptor unionTypeDescriptor:
{
unionTypeDescriptor.Inaccessible();
break;
}
case IEnumValueDescriptor enumValueDescriptor:
{
enumValueDescriptor.Inaccessible();
break;
}
}
}
}
Loading
Loading