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
HotChocolatetant 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.xet 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 >
<!-- 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 >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 @extendsExternal applicable sur les champs, voir @externalKey applicable sur les objets, voir la documentation @keyProvides applicable sur les champs, voir la documentation @providesRequires applicable sur les champs, voir la documentation @requiresDirectives de la Fédération v2 (inclut toutes les directives v1)
ApolloTag applicable sur le schéma, voir la documentation @tagApolloAuthenticated (depuis la v2.5) applicable sur l'énumération, le champ, l'interface et l'objet, documentation @authenticatedComposeDirective (depuis la v2.1) applicable sur le schéma, voir la documentation @composeDirectiveContact applicable sur le schéma, voir utilisation @contactInaccessible applicable sur toutes les définitions de types, voir la documentation @inaccessibleInterfaceObject (depuis la v2.3) applicable sur les objets, voir la documentation @interfaceObjectKeyInterface applicable sur les interfaces, voir la documentation @key de l'interface d'entitéLink applicable sur le schéma, voir la documentation @linkRequiresScopes (depuis la v2.5) applicable sur l'énumération, le champ, l'interface et l'objet, documentation @requiresScopesShareable applicable sur le schéma, voir la documentation @shareableRé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 barReferenceResolver 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 @extendsExternal applicable sur les champs, voir @externalKey(fieldset) applicable sur les objets, voir la documentation @keyProvides(fieldset) applicable sur les champs, voir la documentation @providesRequires(fieldset) applicable sur les champs, voir la documentation @requiresDirectives de la Fédération v2 (inclut toutes les directives v1)
ApolloTag applicable sur toutes les définitions de types, voir la documentation @tagApolloAuthenticated (depuis la v2.5) applicable sur l'énumération, le champ, l'interface et l'objet, documentation @authenticatedComposeDirective(name) (depuis la v2.1) applicable sur le schéma, voir la documentation @composeDirectiveContact(name, url?, description?) applicable sur le schéma, voir utilisation @contactInaccessible applicable sur toutes les définitions de types, voir la documentation @inaccessibleInterfaceObject (depuis la v2.3) applicable sur les objets, voir la documentation @interfaceObjectKey(fieldset) applicable sur les objets, voir la documentation @keyLink(url, [import]?) applicable sur le schéma, voir la documentation @linkNonResolvableKey(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 @requiresScopesShareable applicable sur les champs et les objets, voir la documentation @shareableRé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
; @interfaceObjectApollo 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
<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>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 testVoir 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é.