HotChocolate.ApolloFederation теперь полностью поддерживает Federation v2. Чтобы упростить интеграцию в экосистему HC, мы решили отказаться от поддержки этого пакета в пользу поддержки одного полнофункционального встроенного пакета.Предупреждение. Из-за серьезных изменений в общедоступном API мы не можем поддерживать новые версии
HotChocolateдо тех пор, пока не будет завершена их замена API (в настоящее время работа продолжается). Мы можем поддерживать только версии13.5.xи13.6.x
Apollo Federation — это мощная открытая архитектура, которая помогает вам создать единый суперграф , объединяющий несколько API-интерфейсов GraphQL. ApolloGraphQL.HotChocolate.Federation обеспечивает поддержку Apollo Federation для создания подграфов в экосистеме HotChocolate . Отдельные подграфы могут запускаться независимо друг от друга, но также могут определять отношения с другими подграфами с помощью федеративных директив. Подробности см. в документации Федерации Apollo.
Пакет ApolloGraphQL.HotChocolate.Federation публикуется в Nuget. Обновите файл .csproj , используя следующие ссылки на пакеты.
< ItemGroup >
<!-- make sure to also include HotChocolate package -->
< PackageReference Include = " HotChocolate.AspNetCore " Version = " 13.6.0 " />
<!-- federation package -->
< PackageReference Include = " ApolloGraphQL.HotChocolate.Federation " Version = " $LatestVersion " />
</ ItemGroup >После установки необходимых пакетов вам необходимо зарегистрировать Apollo Federation в вашем сервисе GraphQL.
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( )
// register your types and services
;
var app = builder . Build ( ) ;
app . MapGraphQL ( ) ;
app . Run ( ) ;Если вы хотите подписаться на схему Federation v1, вам необходимо вместо этого использовать расширение
.AddApolloFederation().
Обратитесь к документации HotChocolate для получения подробной информации о том, как создавать схемы GraphQL и настраивать сервер.
Федерация Аполлона требует, чтобы подграфы предоставляли некоторые дополнительные метаданные, чтобы они были осведомлены о суперграфах. Сущности — это объекты GraphQL, которые можно однозначно идентифицировать в суперграфе с помощью указанных @key s. Поскольку сущности могут расширяться с помощью различных подграфов, нам нужна дополнительная точка входа для доступа к сущностям, т. е. подграфы должны реализовывать преобразователи ссылок для сущностей, которые они поддерживают.
Дополнительные сведения о Федерации см. в документации Apollo.
Все интегрированные директивы предоставляются в виде атрибутов, которые можно применять непосредственно к классам/полям/методам.
[ Key ( " id " ) ]
public class Product
{
public Product ( string id , string name , string ? description )
{
Id = id ;
Name = name ;
Description = description ;
}
[ ID ]
public string Id { get ; }
public string Name { get ; }
public string ? Description { get ; }
// assumes ProductRepository with GetById method exists
// reference resolver method must be public static
[ ReferenceResolver ]
public static Product GetByIdAsync (
string id ,
ProductRepository productRepository )
=> productRepository . GetById ( id ) ;
}Это создаст следующий тип
type Product @key ( fields : " id " ) {
id : ID !
name : String !
description : String
}Директивы Федерации v1
Extends применимые к объектам, см. документацию @extendsExternal применим к полям, см. документацию @externalKey применимый к объектам, см. документацию @key .Provides применимость к полям, см. документацию @provides .Requires применимо к полям, см. документацию @requiresДирективы Federation v2 (включает все директивы v1)
ApolloTag применимый к схеме, см. документацию @tagApolloAuthenticated (начиная с версии 2.5), применимый к перечислению, полю, интерфейсу и объекту, документация @authenticatedComposeDirective (начиная с версии 2.1), применимый к схеме, см. документацию @composeDirectiveContact применим к схеме, см. использование @contactInaccessible применимо ко всем определениям типов, см. документацию @inaccessibleInterfaceObject (начиная с версии 2.3), применимый к объектам, см. документацию @interfaceObjectKeyInterface применим к интерфейсам, см. документацию по интерфейсу объекта @keyLink применима к схеме, см. документацию @link .RequiresScopes (начиная с версии 2.5), применимый к перечислению, полю, интерфейсу и объекту, документация @requiresScopesShareable использование применимо к схеме, см. документацию @shareableРазрешение объекта
Map применимая к параметрам метода преобразователя объектов, позволяет сопоставлять сложный аргумент с более простым значением представления, например, [Map("foo.bar")] string barReferenceResolver применим к общедоступным статическим методам в классе сущностей для указания преобразователя сущностей.В качестве альтернативы, если вам нужен более детальный контроль, вы можете использовать подход «сначала код» и вручную заполнить информацию о федерации в базовом дескрипторе типа GraphQL. Все федеративные директивы предоставляют соответствующие методы для применимого дескриптора.
public class Product
{
public Product ( string id , string name , string ? description )
{
Id = id ;
Name = name ;
Description = description ;
}
[ ID ]
public string Id { get ; }
public string Name { get ; }
public string ? Description { get ; }
}
public class ProductType : ObjectType < Product >
{
protected override void Configure ( IObjectTypeDescriptor < Product > descriptor )
{
descriptor
. Key ( " id " )
. ResolveReferenceWith ( t => GetProduct ( default ! , default ! ) ) ;
}
private static Product GetProduct (
string id ,
ProductRepository productRepository )
=> productRepository . GetById ( upc ) ;
}Это создаст следующий тип
type Product @key ( fields : " id " ) {
id : ID !
name : String !
description : String
}Директивы Федерации v1
ExtendsType применим к объектам, см. документацию @extendsExternal применим к полям, см. документацию @externalKey(fieldset) применимый к объектам, см. документацию @keyProvides(fieldset) применимый к полям, см. документацию @provides .Requires(fieldset) применимый к полям, см. документацию @requiresДирективы Federation v2 (включает все директивы v1)
ApolloTag применим ко всем определениям типов, см. документацию @tagApolloAuthenticated (начиная с версии 2.5), применимый к перечислению, полю, интерфейсу и объекту, документация @authenticatedComposeDirective(name) (начиная с версии 2.1), применимый к схеме, см. документацию @composeDirectiveContact(name, url?, description?) применимый к схеме, см. использование @contactInaccessible применимо ко всем определениям типов, см. документацию @inaccessibleInterfaceObject (начиная с версии 2.3), применимый к объектам, см. документацию @interfaceObjectKey(fieldset) применимый к объектам, см. документацию @keyLink(url, [import]?) применима к схеме, см. документацию @linkNonResolvableKey(fieldset) применимый к объектам, см. документацию по неразрешимым @keyRequiresScopes(scopes) (начиная с версии 2.5), применимые к перечислению, полю, интерфейсу и объекту, документация @requiresScopesShareable применимо к полям и объектам, см. документацию @shareableРазрешение объекта
ResolveReferenceWith , чтобы иметь возможность разрешать объекты Подробную информацию о поддержке сервером интерфейса командной строки см. в документации HotChocolate. Чтобы сгенерировать схему во время сборки, вам необходимо добавить дополнительную зависимость от пакета HotChocolate.AspNetCore.CommandLine и настроить сервер так, чтобы он мог использовать RunWithGraphQLCommands .
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( )
// register your types and services
;
var app = builder . Build ( ) ;
app . MapGraphQL ( ) ;
app . RunWithGraphQLCommands ( args ) ;Затем вы можете сгенерировать свою схему, запустив
dotnet run -- schema export --output schema.graphql По умолчанию ApolloGraphQL.HotChocolate.Federation сгенерирует схему, используя последнюю поддерживаемую версию Федерации. Если вы хотите согласиться на использование более старых версий, вы можете это сделать, указав версию при настройке расширения AddApolloFederationV2 .
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( FederationVersion . FEDERATION_23 )
// register your types and services
; Альтернативно вы также можете предоставить собственную FederatedSchema , ориентированную на конкретную версию Федерации.
public class CustomSchema : FederatedSchema
{
public CustomSchema ( ) : base ( FederationVersion . FEDERATION_23 ) {
}
}
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( new CustomSchema ( ) )
// register your types and services
; Если вы хотите настроить свою схему, применив некоторые директивы, вы также можете предоставить собственную FederatedSchema , которая может быть аннотирована атрибутами, расширяющими SchemaTypeDescriptorAttribute
[ AttributeUsage ( AttributeTargets . Class | AttributeTargets . Struct , Inherited = true , AllowMultiple = true ) ]
public sealed class CustomAttribute : SchemaTypeDescriptorAttribute
{
public override void OnConfigure ( IDescriptorContext context , ISchemaTypeDescriptor descriptor , Type type )
{
// configure your directive here
}
}
[ Custom ]
public class CustomSchema : FederatedSchema
{
public CustomSchema ( ) : base ( FederationVersion . FEDERATION_23 ) {
}
}
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( new CustomSchema ( ) )
// register your types and services
;Кроме того, вы также можете указать действие по настройке пользовательской схемы при построении объединенного подграфа.
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( schemaConfiguration : s =>
{
// apply your directive here
} )
// register your types and services
; @key Ваши подграфы могут использовать сущность в качестве возвращаемого типа поля, не добавляя никаких полей в эту сущность. Поскольку нам все еще нужно определение типа для создания допустимой схемы, мы можем определить объект- заглушку с помощью [NonResolvableKeyAttribute] .
public class Review {
public Review ( Product product , int score )
{
Product = product ;
Score = score
}
public Product Product { get ; }
public int Score { get ; }
}
[ NonResolvableKey ( " id " ) ]
public class Product {
public Product ( string id )
{
Id = id ;
}
public string Id { get ; }
} @composedDirective По умолчанию схема Supergraph исключает все пользовательские директивы. @composeDirective используется для указания пользовательских директив, которые должны быть сохранены в схеме Supergraph.
ApolloGraphQL.HotChocolate.Federation предоставляет общий класс FederatedSchema , который автоматически применяет определение @link Apollo Federation v2. При применении любых директив пользовательской схемы вам следует расширить этот класс и добавить необходимые атрибуты/директивы.
При применении @composedDirective вам также необходимо @link со своей спецификацией. Затем вашу пользовательскую схему следует передать в расширение AddApolloFederationV2 .
[ ComposeDirective ( " @custom " ) ]
[ Link ( " https://myspecs.dev/myCustomDirective/v1.0 " , new string [ ] { " @custom " } ) ]
public class CustomSchema : FederatedSchema
{
}
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( new CustomSchema ( ) )
// register your types and services
; Альтернативно вы можете применить @composedDirective , непосредственно применив его к целевой схеме с помощью действия настройки.
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( schemaConfiguration : s =>
{
s . Link ( " https://myspecs.dev/myCustomDirective/v1.0 " , new string [ ] { " @custom " } ) ;
s . ComposeDirective ( " @custom " ) ;
} )
// register your types and services
; @interfaceObjectApollo Federation v2 поддерживает интерфейсы сущностей — мощное расширение интерфейсов GraphQL, которое позволяет расширять функциональность интерфейса по суперграфу без необходимости реализовывать (или даже знать) все его типы реализации.
В подграфе, определяющем интерфейс, нам нужно применить @key
[ InterfaceType ]
[ KeyInterface ( " id " ) ]
public interface Product
{
[ ID ]
string Id { get ; }
string Name { get ; }
}
[ Key ( " id " ) ]
public class Book : Product
{
[ ID ]
public string Id { get ; set ; }
public string Name { get ; set ; }
public string Content { get ; set ; }
} Затем мы можем расширить интерфейс в другом подграфе, сделав его типом, применив @interfaceObject и ту же директиву @key . Это позволяет вам добавлять новые поля к каждой сущности, реализующей ваш интерфейс (например, добавляя поле Reviews ко всем реализациям Product ).
[ Key ( " id " ) ]
[ InterfaceObject ]
public class Product
{
[ ID ]
public string Id { get ; set ; }
public List < string > Reviews { get ; set ; }
} Директива @requiresScopes используется для указания того, что целевой элемент доступен только аутентифицированным пользователям суперграфа с соответствующими областями JWT. Дополнительные сведения см. в статье о маршрутизаторе Apollo.
public class Query
{
[ RequiresScopes ( scopes : new string [ ] { " scope1, scope2 " , " scope3 " } ) ]
[ RequiresScopes ( scopes : new string [ ] { " scope4 " } ) ]
public Product ? GetProduct ( [ ID ] string id , Data repository )
=> repository . Products . FirstOrDefault ( t => t . Id . Equals ( id ) ) ;
}Это создаст следующую схему
type Query {
product ( id : ID ! ): Product @requiresScopes ( scopes : [ [ " scope1, scope2 " , " scope3 " ], [ " scope4 " ] ])
} Вы можете использовать директиву @contact , чтобы добавить контактную информацию вашей команды в схему подграфа. Эта информация отображается в Studio, что помогает другим командам узнать, к кому обращаться за помощью с подграфом. Подробности смотрите в документации.
Нам нужно применить атрибут [Contact] к схеме. Вы можете применить атрибут [Contact] к пользовательской схеме и передать свою пользовательскую схему в расширение AddApolloFederationV2 .
[ Contact ( " MyTeamName " , " https://myteam.slack.com/archives/teams-chat-room-url " , " send urgent issues to [#oncall](https://yourteam.slack.com/archives/oncall) " ) ]
public class CustomSchema : FederatedSchema
{
}
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddGraphQLServer ( )
. AddType < ContactDirectiveType > ( ) ;
. AddApolloFederationV2 ( new CustomSchema ( ) )
// register your types and services
; или примените директиву @contact непосредственно к схеме, предоставив настраиваемое действие по настройке схемы.
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( schemaConfiguration : s =>
{
s . Contact ( " MyTeamName " , " https://myteam.slack.com/archives/teams-chat-room-url " , " send urgent issues to [#oncall](https://yourteam.slack.com/archives/oncall) " ) ;
} )
// register your types and services
; ApolloGraphQL.HotChocolate.Federation автоматически по умолчанию использует имя типа Query . При использовании пользовательских типов операций корневого Query необходимо явно настроить схему с этими пользовательскими значениями.
public class CustomQuery
{
public Foo ? GetFoo ( [ ID ] string id , Data repository )
=> repository . Foos . FirstOrDefault ( t => t . Id . Equals ( id ) ) ;
}
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddGraphQLServer ( )
. ModifyOptions ( opts => opts . QueryTypeName = " CustomQuery " )
. AddApolloFederationV2 ( )
. AddQueryType < CustomQuery > ( )
// register your other types and services
;
var app = builder . Build ( ) ;
app . MapGraphQL ( ) ;
app . Run ( ) ; Мигрировать с HotChocolate.Federation на ApolloGraphQL.HotChocolate.Federation легко. Просто обновите импорт пакета, чтобы он указывал на новый модуль.
<ItemGroup>
<!-- make sure to also include HotChocolate package -->
<PackageReference Include="HotChocolate.AspNetCore" Version="13.6.0" />
<!-- federation package -->
- <PackageReference Include="HotChocolate.ApolloFederation" Version="$LatestVersion" />
+ <PackageReference Include="ApolloGraphQL.HotChocolate.Federation" Version="$LatestVersion" />
</ItemGroup>и обновить импорт пространства имен
- using HotChocolate.ApolloFederation;
+ using ApolloGraphQL.HotChocolate.Federation;Хотя мы старались сделать процесс миграции максимально простым, нам пришлось внести несколько изменений в библиотеку. Из-за зависимости от некоторых внутренних API нам пришлось внести в библиотеку следующие критические изменения:
[Key] теперь применим только к классам , и вы больше не можете применять его к отдельным полям.[ReferenceResolver] теперь применим только к общедоступным статическим методам внутри сущности , он больше не применим к классам. [EntityResolver] может автоматически сопоставлять представление сущности с поддерживаемыми значениями @key / @requires . Поля скаляров @key автоматически сопоставляются, и мы можем использовать атрибут [Map] для автоматического сопоставления скалярных значений из сложных наборов выбора.
В настоящее время мы не поддерживаем автоматическое сопоставление значений списка и объекта.
В качестве обходного пути вам необходимо вручную проанализировать объект представления в вашей реализации.
[ ReferenceResolver ]
public static Foo GetByFooBar (
[ LocalState ] ObjectValueNode data
Data repository )
{
// TODO implement logic here by manually reading values from local state data
} @linkВ настоящее время мы поддерживаем импорт элементов только из указанных подграфов.
Пространство имен и переименование элементов в настоящее время не поддерживаются. Подробности смотрите в выпуске.
Если у вас есть конкретный вопрос о библиотеке или коде, начните обсуждение на форумах сообщества Apollo или начните разговор на нашем сервере Discord.
Для начала создайте форк репо и создайте новую ветку. Затем вы можете собрать библиотеку локально, запустив
# install dependencies
dotnet restore
# build project
dotnet build
# run tests
dotnet testБолее подробную информацию смотрите на CONTRIBUTING.md.
После того как вы создадите местный филиал, просмотрите наши открытые вопросы, чтобы узнать, куда вы можете внести свой вклад.
Дополнительную информацию о том, как связаться с командой по вопросам безопасности, можно найти в нашей Политике безопасности.