HotChocolate.ApolloFederation
prend désormais entièrement en charge Federation v2. Afin de simplifier les intégrations dans l'écosystème HC, nous avons décidé d'abandonner ce package en faveur de la prise en charge d'un seul package intégré complet.Avertissement En raison d'une modification radicale de l'API publique, nous ne pouvons pas prendre en charge les versions plus récentes de
HotChocolate
tant que leur API de remplacement (actuellement en cours de travail) n'est pas terminée. Nous ne pouvons prendre en charge que les versions v13.5.x
et v13.6.x
Apollo Federation est une architecture puissante et ouverte qui vous aide à créer un supergraphe unifié combinant plusieurs API GraphQL. ApolloGraphQL.HotChocolate.Federation
fournit la prise en charge d'Apollo Federation pour la création de sous-graphes dans l'écosystème HotChocolate
. Les sous-graphes individuels peuvent être exécutés indépendamment les uns des autres, mais peuvent également spécifier des relations avec les autres sous-graphes à l'aide de directives fédérées. Voir la documentation de la Fédération Apollo pour plus de détails.
Le package ApolloGraphQL.HotChocolate.Federation
est publié sur Nuget. Mettez à jour votre fichier .csproj
avec les références de package suivantes
< ItemGroup > < PackageReference Include = " HotChocolate.AspNetCore " Version = " 13.6.0 " /> < PackageReference Include = " ApolloGraphQL.HotChocolate.Federation " Version = " $LatestVersion " /> ItemGroup >
Après avoir installé les packages nécessaires, vous devez enregistrer Apollo Federation auprès de votre service GraphQL.
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( )
// register your types and services
;
var app = builder . Build ( ) ;
app . MapGraphQL ( ) ;
app . Run ( ) ;
Si vous souhaitez adhérer au schéma Federation v1, vous devez plutôt utiliser l'extension
.AddApolloFederation()
.
Reportez-vous à la documentation HotChocolate
pour des informations détaillées sur la façon de créer des schémas GraphQL et de configurer votre serveur.
Apollo Federation exige que les sous-graphes fournissent des métadonnées supplémentaires pour les rendre conscients des supergraphes. Les entités sont des objets GraphQL qui peuvent être identifiés de manière unique dans le supergraphe par les @key
s spécifiés. Puisque les entités peuvent être étendues par différents sous-graphes, nous avons besoin d'un point d'entrée supplémentaire pour accéder aux entités, c'est-à-dire que les sous-graphes doivent implémenter des résolveurs de référence pour les entités qu'ils prennent en charge.
Consultez la documentation Apollo pour plus de détails sur la Fédération.
Toutes les directives fédérées sont fournies sous forme d'attributs pouvant être appliqués directement sur les classes/champs/méthodes.
[ 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 ) ;
}
Cela générera le type suivant
type Product @key ( fields : " id " ) {
id : ID !
name : String !
description : String
}
Directives de la Fédération v1
Extends
applicables sur les objets, voir la documentation @extends
External
applicable sur les champs, voir @external
Key
applicable sur les objets, voir la documentation @key
Provides
applicable sur les champs, voir la documentation @provides
Requires
applicable sur les champs, voir la documentation @requires
Directives de la Fédération v2 (inclut toutes les directives v1)
ApolloTag
applicable sur le schéma, voir la documentation @tag
ApolloAuthenticated
(depuis la v2.5) applicable sur l'énumération, le champ, l'interface et l'objet, documentation @authenticated
ComposeDirective
(depuis la v2.1) applicable sur le schéma, voir la documentation @composeDirective
Contact
applicable sur le schéma, voir utilisation @contact
Inaccessible
applicable sur toutes les définitions de types, voir la documentation @inaccessible
InterfaceObject
(depuis la v2.3) applicable sur les objets, voir la documentation @interfaceObject
KeyInterface
applicable sur les interfaces, voir la documentation @key
de l'interface d'entitéLink
applicable sur le schéma, voir la documentation @link
RequiresScopes
(depuis la v2.5) applicable sur l'énumération, le champ, l'interface et l'objet, documentation @requiresScopes
Shareable
applicable sur le schéma, voir la documentation @shareable
Résolution d'entité
Map
applicable aux paramètres de la méthode de résolution d'entité, vous permet de mapper un argument complexe à une valeur de représentation plus simple, par exemple [Map("foo.bar")] string bar
ReferenceResolver
applicable sur les méthodes statiques publiques au sein d'une classe d'entité pour indiquer le résolveur d'entitéAlternativement, si vous avez besoin d'un contrôle plus granulaire, vous pouvez utiliser l'approche code d'abord et renseigner manuellement les informations de fédération sur le descripteur de type GraphQL sous-jacent. Toutes les directives fédérées exposent les méthodes correspondantes sur le descripteur applicable.
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 ) ;
}
Cela générera le type suivant
type Product @key ( fields : " id " ) {
id : ID !
name : String !
description : String
}
Directives de la Fédération v1
ExtendsType
applicable sur les objets, voir la documentation @extends
External
applicable sur les champs, voir @external
Key(fieldset)
applicable sur les objets, voir la documentation @key
Provides(fieldset)
applicable sur les champs, voir la documentation @provides
Requires(fieldset)
applicable sur les champs, voir la documentation @requires
Directives de la Fédération v2 (inclut toutes les directives v1)
ApolloTag
applicable sur toutes les définitions de types, voir la documentation @tag
ApolloAuthenticated
(depuis la v2.5) applicable sur l'énumération, le champ, l'interface et l'objet, documentation @authenticated
ComposeDirective(name)
(depuis la v2.1) applicable sur le schéma, voir la documentation @composeDirective
Contact(name, url?, description?)
applicable sur le schéma, voir utilisation @contact
Inaccessible
applicable sur toutes les définitions de types, voir la documentation @inaccessible
InterfaceObject
(depuis la v2.3) applicable sur les objets, voir la documentation @interfaceObject
Key(fieldset)
applicable sur les objets, voir la documentation @key
Link(url, [import]?)
applicable sur le schéma, voir la documentation @link
NonResolvableKey(fieldset)
applicable sur les objets, voir la documentation @key
non résolubleRequiresScopes(scopes)
(depuis la v2.5) applicable sur l'énumération, le champ, l'interface et l'objet, documentation @requiresScopes
Shareable
applicable sur les champs et les objets, voir la documentation @shareable
Résolution d'entité
ResolveReferenceWith
pour pouvoir résoudre les entités Consultez la documentation HotChocolate pour plus de détails sur la prise en charge du serveur pour l'interface de ligne de commande. Afin de générer un schéma au moment de la construction, vous devez ajouter une dépendance supplémentaire sur le package HotChocolate.AspNetCore.CommandLine
et configurer votre serveur pour lui permettre de RunWithGraphQLCommands
.
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( )
// register your types and services
;
var app = builder . Build ( ) ;
app . MapGraphQL ( ) ;
app . RunWithGraphQLCommands ( args ) ;
Vous pouvez ensuite générer votre schéma en exécutant
dotnet run -- schema export --output schema.graphql
Par défaut, ApolloGraphQL.HotChocolate.Federation
générera un schéma en utilisant la dernière version de Fédération prise en charge. Si vous souhaitez choisir d'utiliser des versions plus anciennes, vous pouvez le faire en spécifiant la version lors de la configuration de l'extension AddApolloFederationV2
.
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( FederationVersion . FEDERATION_23 )
// register your types and services
;
Vous pouvez également fournir FederatedSchema
personnalisé qui cible une version spécifique de la Fédération.
public class CustomSchema : FederatedSchema
{
public CustomSchema ( ) : base ( FederationVersion . FEDERATION_23 ) {
}
}
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( new CustomSchema ( ) )
// register your types and services
;
Si vous souhaitez personnaliser votre schéma en appliquant certaines directives, vous pouvez également fournir FederatedSchema
personnalisé qui peut être annoté avec des attributs étendant 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
;
Vous pouvez également spécifier une action de configuration de schéma personnalisée lors de la création d'un sous-graphe fédéré.
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( schemaConfiguration : s =>
{
// apply your directive here
} )
// register your types and services
;
@key
non résoluble Vos sous-graphiques peuvent utiliser une entité comme type de retour de champ sans contribuer à aucun champ à cette entité. Puisque nous avons toujours besoin d'une définition de type pour générer un schéma valide, nous pouvons définir un objet stub avec [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
Par défaut, le schéma Supergraph exclut toutes les directives personnalisées. @composeDirective
est utilisé pour spécifier les directives personnalisées qui doivent être conservées dans le schéma Supergraph.
ApolloGraphQL.HotChocolate.Federation
fournit une classe FederatedSchema
commune qui applique automatiquement la définition @link
d'Apollo Federation v2. Lorsque vous appliquez des directives de schéma personnalisées, vous devez étendre cette classe et ajouter les attributs/directives requis.
Lors de l'application @composedDirective
vous devez également @link
votre spécification. Votre schéma personnalisé doit ensuite être transmis à l'extension 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
;
Vous pouvez également appliquer @composedDirective
en l'appliquant directement sur un schéma cible à l'aide de l'action de configuration
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 prend en charge les interfaces d'entité , une extension puissante des interfaces GraphQL qui vous permet d'étendre les fonctionnalités d'une interface à travers le supergraphe sans avoir à implémenter (ou même à connaître) tous ses types d'implémentation.
Dans un sous-graphe définissant l'interface, nous devons appliquer @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 ; }
}
Nous pouvons ensuite étendre l'interface dans un autre sous-graphe en en faisant un type, en appliquant @interfaceObject
et la même directive @key
. Cela vous permet d'ajouter de nouveaux champs à chaque entité qui implémente votre interface (par exemple, en ajoutant un champ Reviews
à toutes les implémentations Product
).
[ Key ( " id " ) ]
[ InterfaceObject ]
public class Product
{
[ ID ]
public string Id { get ; set ; }
public List < string > Reviews { get ; set ; }
}
La directive @requiresScopes
est utilisée pour indiquer que l'élément cible n'est accessible qu'aux utilisateurs de supergraph authentifiés avec les étendues JWT appropriées. Reportez-vous à l'article sur le routeur Apollo pour plus de détails.
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 ) ) ;
}
Cela générera le schéma suivant
type Query {
product ( id : ID ! ): Product @requiresScopes ( scopes : [ [ " scope1, scope2 " , " scope3 " ], [ " scope4 " ] ])
}
Vous pouvez utiliser la directive @contact
pour ajouter les informations de contact de votre équipe à un schéma de sous-graphe. Ces informations sont affichées dans Studio, ce qui permet aux autres équipes de savoir qui contacter pour obtenir de l'aide concernant le sous-graphique. Voir la documentation pour plus de détails.
Nous devons appliquer l'attribut [Contact]
sur un schéma. Vous pouvez soit appliquer l'attribut [Contact]
sur un schéma personnalisé et transmettre votre schéma personnalisé à l'extension 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
;
ou appliquez la directive @contact
directement sur un schéma en fournissant une action de configuration de schéma personnalisée
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
utilise automatiquement par défaut le nom du type Query
. Lorsque vous utilisez des types d’opérations Query
racine personnalisés, vous devez configurer explicitement le schéma avec ces valeurs personnalisées.
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 ( ) ;
La migration de HotChocolate.Federation
vers ApolloGraphQL.HotChocolate.Federation
est simple. Mettez simplement à jour votre importation de package pour pointer vers un nouveau module
- +
et mettre à jour les importations d'espaces de noms
- using HotChocolate.ApolloFederation;
+ using ApolloGraphQL.HotChocolate.Federation;
Bien que nous ayons essayé de rendre le processus de migration aussi transparent que possible, nous avons dû apporter quelques modifications à la bibliothèque. En raison de la dépendance à l'égard de certaines API internes, nous avons dû apporter les modifications majeures suivantes à la bibliothèque :
[Key]
est désormais applicable uniquement sur les classes et vous ne pouvez plus l'appliquer sur des champs individuels[ReferenceResolver]
est désormais applicable uniquement aux méthodes statiques publiques au sein d'une entité , il n'est plus applicable aux classes Les [EntityResolver]
peuvent automatiquement mapper la représentation d'entité aux valeurs @key
/ @requires
prises en charge. Les champs scalaires @key
sont automatiquement mappés et nous pouvons utiliser l'attribut [Map]
pour mapper automatiquement les valeurs scalaires à partir d'ensembles de sélection complexes.
Actuellement, nous ne prenons pas en charge le mappage automatique des valeurs de liste et d'objet.
Pour contourner ce problème, vous devez analyser manuellement l'objet de représentation dans votre implémentation.
[ ReferenceResolver ]
public static Foo GetByFooBar (
[ LocalState ] ObjectValueNode data
Data repository )
{
// TODO implement logic here by manually reading values from local state data
}
@link
limitéeActuellement, nous prenons uniquement en charge l'importation d'éléments à partir des sous-graphes référencés.
L'espacement des noms et le renommage des éléments ne sont actuellement pas pris en charge. Voir le problème pour plus de détails.
Si vous avez une question spécifique sur la bibliothèque ou le code, veuillez démarrer une discussion sur les forums de la communauté Apollo ou démarrer une conversation sur notre serveur Discord.
Pour commencer, veuillez créer le dépôt et extraire une nouvelle branche. Vous pouvez ensuite créer la bibliothèque localement en exécutant
# install dependencies
dotnet restore
# build project
dotnet build
# run tests
dotnet test
Voir plus d’informations dans CONTRIBUTING.md.
Après avoir créé votre succursale locale, jetez un œil à nos problèmes ouverts pour voir où vous pouvez contribuer.
Pour plus d'informations sur la façon de contacter l'équipe pour des problèmes de sécurité, consultez notre politique de sécurité.
Cette bibliothèque est sous licence The MIT License (MIT).