Skip to content

Commit 5c06706

Browse files
committed
Reworked the version handling of Apollo Federation. (#6839)
1 parent d6ceea4 commit 5c06706

38 files changed

+578
-738
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using System.Collections.Generic;
2+
using HotChocolate.Types.Descriptors;
3+
using HotChocolate.Types.Descriptors.Definitions;
4+
5+
namespace HotChocolate.ApolloFederation;
6+
7+
internal static class FederationVersionExtensions
8+
{
9+
private static readonly Dictionary<Uri, FederationVersion> _uriToVersion = new()
10+
{
11+
[new Uri(FederationVersionUrls.Federation20)] = FederationVersion.Federation20,
12+
[new Uri(FederationVersionUrls.Federation21)] = FederationVersion.Federation21,
13+
[new Uri(FederationVersionUrls.Federation22)] = FederationVersion.Federation22,
14+
[new Uri(FederationVersionUrls.Federation23)] = FederationVersion.Federation23,
15+
[new Uri(FederationVersionUrls.Federation24)] = FederationVersion.Federation24,
16+
[new Uri(FederationVersionUrls.Federation25)] = FederationVersion.Federation25,
17+
};
18+
19+
private static readonly Dictionary<FederationVersion, Uri> _versionToUri = new()
20+
{
21+
[FederationVersion.Federation20] = new(FederationVersionUrls.Federation20),
22+
[FederationVersion.Federation21] = new(FederationVersionUrls.Federation21),
23+
[FederationVersion.Federation22] = new(FederationVersionUrls.Federation22),
24+
[FederationVersion.Federation23] = new(FederationVersionUrls.Federation23),
25+
[FederationVersion.Federation24] = new(FederationVersionUrls.Federation24),
26+
[FederationVersion.Federation25] = new(FederationVersionUrls.Federation25),
27+
};
28+
29+
public static FederationVersion GetFederationVersion<T>(
30+
this IDescriptor<T> descriptor)
31+
where T : DefinitionBase
32+
{
33+
var contextData = descriptor.Extend().Context.ContextData;
34+
if (contextData.TryGetValue(FederationContextData.FederationVersion, out var value) &&
35+
value is FederationVersion version and > FederationVersion.Unknown)
36+
{
37+
return version;
38+
}
39+
40+
// TODO : resources
41+
throw new InvalidOperationException("The configuration state is invalid.");
42+
}
43+
44+
public static FederationVersion GetFederationVersion(
45+
this IDescriptorContext context)
46+
{
47+
if (context.ContextData.TryGetValue(FederationContextData.FederationVersion, out var value) &&
48+
value is FederationVersion version and > FederationVersion.Unknown)
49+
{
50+
return version;
51+
}
52+
53+
// TODO : resources
54+
throw new InvalidOperationException("The configuration state is invalid.");
55+
}
56+
57+
public static Uri ToUrl(this FederationVersion version)
58+
{
59+
if(_versionToUri.TryGetValue(version, out var url))
60+
{
61+
return url;
62+
}
63+
64+
// TODO : resources
65+
throw new ArgumentException("The federation version is not supported.", nameof(version));
66+
}
67+
68+
public static FederationVersion ToVersion(this Uri url)
69+
{
70+
if(_uriToVersion.TryGetValue(url, out var version))
71+
{
72+
return version;
73+
}
74+
75+
// TODO : resources
76+
throw new ArgumentException("The federation url is not supported.", nameof(url));
77+
}
78+
79+
public static bool TryToVersion(this Uri url, out FederationVersion version)
80+
=> _uriToVersion.TryGetValue(url, out version);
81+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ internal static class FederationContextData
77
public const string ExternalSetter = "HotChocolate.ApolloFederation.ExternalSetter";
88
public const string EntityResolver = "HotChocolate.ApolloFederation.EntityResolver";
99
public const string FederationVersion = "HotChocolate.ApolloFederation.Version";
10+
public const string ExportedDirectives = "HotChocolate.ApolloFederation.ExportedDirectives";
1011
public const string DataField = "data";
1112
public const string TypeField = "__type";
1213
}

src/HotChocolate/ApolloFederation/src/ApolloFederation/FederationTypeInterceptor.cs

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ internal sealed class FederationTypeInterceptor : TypeInterceptor
3939
BindingFlags.Static | BindingFlags.Public)!;
4040

4141
private readonly List<ObjectType> _entityTypes = new();
42-
private readonly Dictionary<string, HashSet<string>> _imports = new();
42+
private readonly Dictionary<Uri, HashSet<string>> _imports = new();
4343
private IDescriptorContext _context = default!;
4444
private ITypeInspector _typeInspector = default!;
45+
private TypeRegistry _typeRegistry = default!;
4546
private ObjectType _queryType = default!;
4647
private ExtendedTypeDirectiveReference _keyDirectiveReference = default!;
4748
private SchemaTypeDefinition _schemaTypeDefinition = default!;
@@ -57,6 +58,7 @@ internal override void InitializeContext(
5758
{
5859
_typeInspector = context.TypeInspector;
5960
_context = context;
61+
_typeRegistry = typeRegistry;
6062
_keyDirectiveReference = new ExtendedTypeDirectiveReference(_typeInspector.GetType(typeof(KeyDirective)));
6163
ModifyOptions(context, o => o.Mode = TagMode.ApolloFederation);
6264
}
@@ -102,7 +104,7 @@ public override IEnumerable<TypeReference> RegisterMoreTypes(
102104
yield return _typeInspector.GetTypeRef(typeof(LinkDirective));
103105
}
104106
}
105-
107+
106108
public override void OnBeforeCompleteName(
107109
ITypeCompletionContext completionContext,
108110
DefinitionBase definition)
@@ -125,7 +127,7 @@ public override void OnAfterCompleteName(
125127

126128
var hasRuntimeType = (IHasRuntimeType)definition;
127129
var type = hasRuntimeType.RuntimeType;
128-
130+
129131
if (type != typeof(object) &&
130132
type.IsDefined(typeof(PackageAttribute)))
131133
{
@@ -134,6 +136,7 @@ public override void OnAfterCompleteName(
134136
}
135137

136138
type = completionContext.Type.GetType();
139+
137140
if (type.IsDefined(typeof(PackageAttribute)))
138141
{
139142
RegisterImport(type);
@@ -167,22 +170,105 @@ void RegisterImport(MemberInfo element)
167170
}
168171

169172
public override void OnTypesCompletedName()
173+
{
174+
RegisterExportedDirectives();
175+
RegisterImports();
176+
}
177+
178+
private void RegisterImports()
170179
{
171180
if (_imports.Count == 0)
172181
{
173182
return;
174183
}
175184

185+
var version = _context.GetFederationVersion();
186+
var federationTypes = new HashSet<string>();
187+
188+
foreach (var import in _imports)
189+
{
190+
if (!import.Key.TryToVersion(out var importVersion))
191+
{
192+
continue;
193+
}
194+
195+
if (importVersion > version)
196+
{
197+
// todo: throw helper
198+
throw new SchemaException(
199+
SchemaErrorBuilder.New()
200+
.SetMessage(
201+
"The following federation types were used and are not supported by " +
202+
"the current federation version: {0}",
203+
string.Join(", ", import.Value))
204+
.Build());
205+
}
206+
207+
federationTypes.UnionWith(import.Value);
208+
}
209+
210+
if (version == FederationVersion.Federation10)
211+
{
212+
return;
213+
}
214+
176215
var dependency = new TypeDependency(
177216
_typeInspector.GetTypeRef(typeof(LinkDirective)),
178217
TypeDependencyFulfilled.Completed);
179218
_schemaType.Dependencies.Add(dependency);
180219

220+
_schemaTypeDefinition
221+
.GetLegacyDefinition()
222+
.AddDirective(
223+
new LinkDirective(version.ToUrl(), federationTypes),
224+
_typeInspector);
225+
181226
foreach (var import in _imports)
182227
{
228+
if (import.Key.TryToVersion(out _))
229+
{
230+
continue;
231+
}
232+
183233
_schemaTypeDefinition
184234
.GetLegacyDefinition()
185-
.AddDirective(new LinkDirective(new Uri(import.Key), import.Value), _typeInspector);
235+
.AddDirective(
236+
new LinkDirective(import.Key, import.Value),
237+
_typeInspector);
238+
}
239+
}
240+
241+
private void RegisterExportedDirectives()
242+
{
243+
if (!_context.ContextData.TryGetValue(ExportedDirectives, out var value) ||
244+
value is not List<Type> exportedDirectives)
245+
{
246+
return;
247+
}
248+
249+
var composeDirectives = new List<ComposeDirective>();
250+
foreach (var exportedDirective in exportedDirectives)
251+
{
252+
var typeReference = _typeInspector.GetTypeRef(exportedDirective);
253+
if (_typeRegistry.TryGetType(typeReference, out var exportedDirectiveType))
254+
{
255+
composeDirectives.Add(new ComposeDirective(exportedDirectiveType.Type.Name));
256+
}
257+
}
258+
259+
if (composeDirectives.Count > 0)
260+
{
261+
var dependency = new TypeDependency(
262+
_typeInspector.GetTypeRef(typeof(ComposeDirective)),
263+
TypeDependencyFulfilled.Completed);
264+
_schemaType.Dependencies.Add(dependency);
265+
266+
foreach (var directive in composeDirectives)
267+
{
268+
_schemaTypeDefinition
269+
.GetLegacyDefinition()
270+
.AddDirective(directive, _typeInspector);
271+
}
186272
}
187273
}
188274

src/HotChocolate/ApolloFederation/src/ApolloFederation/FederationVersion.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ public enum FederationVersion
1313
Federation23 = 2_3,
1414
Federation24 = 2_4,
1515
Federation25 = 2_5,
16-
Federation26 = 2_6,
17-
Latest = Federation26,
16+
// Federation26 = 2_6,
17+
Latest = Federation25,
1818
}

src/HotChocolate/ApolloFederation/src/ApolloFederation/FederationVersionExtensions.cs

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/HotChocolate/ApolloFederation/src/ApolloFederation/HotChocolate.ApolloFederation.csproj

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,15 @@
104104
<Compile Update="Types\Directives\RequiresScopesDescriptorExtensions.cs">
105105
<DependentUpon>RequiresScopesDirective.cs</DependentUpon>
106106
</Compile>
107-
<Compile Update="Types\Directives\FederationResources.Designer.cs">
107+
<Compile Update="Properties\FederationResources.Designer.cs">
108108
<DesignTime>True</DesignTime>
109109
<AutoGen>True</AutoGen>
110110
<DependentUpon>FederationResources.resx</DependentUpon>
111111
</Compile>
112+
<EmbeddedResource Update="Properties\FederationResources.resx">
113+
<Generator>ResXFileCodeGenerator</Generator>
114+
<LastGenOutput>FederationResources.Designer.cs</LastGenOutput>
115+
</EmbeddedResource>
112116
<Compile Update="Types\Directives\RequiresScopesAttribute.cs">
113117
<DependentUpon>RequiresScopesDirective.cs</DependentUpon>
114118
</Compile>
@@ -119,15 +123,4 @@
119123
<None Include="$(MSBuildThisFileDirectory)..\MSBuild\HotChocolate.ApolloFederation.targets" Pack="true" PackagePath="build/HotChocolate.ApolloFederation.targets" Visible="false" />
120124
</ItemGroup>
121125

122-
<ItemGroup>
123-
<Folder Include="Properties\" />
124-
</ItemGroup>
125-
126-
<ItemGroup>
127-
<EmbeddedResource Update="Types\Directives\FederationResources.resx">
128-
<Generator>ResXFileCodeGenerator</Generator>
129-
<LastGenOutput>FederationResources.Designer.cs</LastGenOutput>
130-
</EmbeddedResource>
131-
</ItemGroup>
132-
133126
</Project>

src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/Directives/AuthenticatedAttribute.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
using System.Reflection;
2-
using HotChocolate.ApolloFederation.Types;
32
using HotChocolate.Types.Descriptors;
43

5-
namespace HotChocolate.ApolloFederation;
4+
namespace HotChocolate.ApolloFederation.Types;
65

76
/// <summary>
87
/// <code>

0 commit comments

Comments
 (0)