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 > < PackageReference Include = " HotChocolate.AspNetCore " Version = " 13.6.0 " /> < 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
применимые к объектам, см. документацию @extends
External
применим к полям, см. документацию @external
Key
применимый к объектам, см. документацию @key
.Provides
применимость к полям, см. документацию @provides
.Requires
применимо к полям, см. документацию @requires
Директивы Federation v2 (включает все директивы v1)
ApolloTag
применим к схеме, см. документацию @tag
ApolloAuthenticated
(начиная с версии 2.5), применимый к перечислению, полю, интерфейсу и объекту, документация @authenticated
ComposeDirective
(начиная с версии 2.1), применимый к схеме, см. документацию @composeDirective
Contact
применим к схеме, см. использование @contact
Inaccessible
применимо ко всем определениям типов, см. документацию @inaccessible
InterfaceObject
(начиная с версии 2.3), применимый к объектам, см. документацию @interfaceObject
KeyInterface
применим к интерфейсам, см. документацию по интерфейсу объекта @key
Link
применима к схеме, см. документацию @link
.RequiresScopes
(начиная с версии 2.5), применимый к перечислению, полю, интерфейсу и объекту, документация @requiresScopes
Shareable
использование применимо к схеме, см. документацию @shareable
Разрешение объекта
Map
применимая к параметрам метода преобразователя объектов, позволяет сопоставлять сложный аргумент с более простым значением представления, например, [Map("foo.bar")] string bar
ReferenceResolver
применим к общедоступным статическим методам в классе сущностей для указания преобразователя сущностей.В качестве альтернативы, если вам нужен более детальный контроль, вы можете использовать подход «сначала код» и вручную заполнить информацию о федерации в базовом дескрипторе типа 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
применим к объектам, см. документацию @extends
External
применим к полям, см. документацию @external
Key(fieldset)
применимый к объектам, см. документацию @key
Provides(fieldset)
применимый к полям, см. документацию @provides
.Requires(fieldset)
применимый к полям, см. документацию @requires
Директивы Federation v2 (включает все директивы v1)
ApolloTag
применим ко всем определениям типов, см. документацию @tag
ApolloAuthenticated
(начиная с версии 2.5), применимый к перечислению, полю, интерфейсу и объекту, документация @authenticated
ComposeDirective(name)
(начиная с версии 2.1), применимый к схеме, см. документацию @composeDirective
Contact(name, url?, description?)
применимый к схеме, см. использование @contact
Inaccessible
применимо ко всем определениям типов, см. документацию @inaccessible
InterfaceObject
(начиная с версии 2.3), применимый к объектам, см. документацию @interfaceObject
Key(fieldset)
применимый к объектам, см. документацию @key
Link(url, [import]?)
применима к схеме, см. документацию @link
NonResolvableKey(fieldset)
применимый к объектам, см. документацию по неразрешимым @key
RequiresScopes(scopes)
(начиная с версии 2.5), применимые к перечислению, полю, интерфейсу и объекту, документация @requiresScopes
Shareable
применимо к полям и объектам, см. документацию @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
;
@interfaceObject
Apollo 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
проста. Просто обновите импорт пакета, чтобы он указывал на новый модуль.
- +
и обновить импорт пространства имен
- 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.
После того как вы создадите местный филиал, просмотрите наши открытые вопросы, чтобы узнать, куда вы можете внести свой вклад.
Дополнительную информацию о том, как связаться с командой по вопросам безопасности, можно найти в нашей Политике безопасности.
Эта библиотека распространяется под лицензией MIT License (MIT).