HotChocolate.ApolloFederation
ahora es totalmente compatible con Federation v2. Para simplificar las integraciones en el ecosistema HC, decidimos desaprobar este paquete y admitir un único paquete integrado con todas las funciones.Advertencia Debido a un cambio importante en la API pública, no podemos admitir versiones más nuevas de
HotChocolate
hasta que se complete la API de reemplazo (actualmente en proceso). Solo podemos admitir las versiones13.5.x
y13.6.x
Apollo Federation es una arquitectura abierta y poderosa que le ayuda a crear un supergrafo unificado que combina múltiples API GraphQL. ApolloGraphQL.HotChocolate.Federation
proporciona soporte de Apollo Federation para crear subgrafos en el ecosistema HotChocolate
. Los subgrafos individuales se pueden ejecutar independientemente unos de otros, pero también pueden especificar relaciones con los otros subgrafos mediante directivas federadas. Consulte la documentación de Apollo Federation para obtener más detalles.
El paquete ApolloGraphQL.HotChocolate.Federation
se publica en Nuget. Actualice su archivo .csproj
con las siguientes referencias de paquetes
< ItemGroup > < PackageReference Include = " HotChocolate.AspNetCore " Version = " 13.6.0 " /> < PackageReference Include = " ApolloGraphQL.HotChocolate.Federation " Version = " $LatestVersion " /> ItemGroup >
Después de instalar los paquetes necesarios, debe registrar Apollo Federation con su servicio GraphQL.
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( )
// register your types and services
;
var app = builder . Build ( ) ;
app . MapGraphQL ( ) ;
app . Run ( ) ;
Si desea suscribirse al esquema Federation v1, debe utilizar la extensión
.AddApolloFederation()
en su lugar.
Consulte la documentación HotChocolate
para obtener información detallada sobre cómo crear esquemas GraphQL y configurar su servidor.
Apollo Federation requiere que los subgrafos proporcionen algunos metadatos adicionales para que sean conscientes de los supergrafos. Las entidades son objetos GraphQL que se pueden identificar de forma única en el supergrafo mediante las @key
especificadas. Dado que las entidades pueden ampliarse con varios subgrafos, necesitamos un punto de entrada adicional para acceder a las entidades, es decir, los subgrafos deben implementar solucionadores de referencia para las entidades que admiten.
Consulte la documentación de Apollo para obtener detalles adicionales de la Federación.
Todas las directivas federadas se proporcionan como atributos que se pueden aplicar directamente en clases/campos/métodos.
[ 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 ) ;
}
Esto generará el siguiente tipo
type Product @key ( fields : " id " ) {
id : ID !
name : String !
description : String
}
Directivas de la Federación v1
Extends
aplicable a objetos, consulte la documentación @extends
External
aplicable en campos, consulte la documentación @external
Key
aplicable a objetos, consulte la documentación @key
Provides
campos aplicables; consulte la documentación @provides
Requires
aplicable en los campos, consulte la documentación @requires
Directivas de federación v2 (incluye todas las directivas v1)
ApolloTag
aplicable en el esquema, consulte la documentación @tag
ApolloAuthenticated
(desde v2.5) aplicable en enumeración, campo, interfaz y objeto, documentación @authenticated
ComposeDirective
(desde v2.1) aplicable en el esquema, consulte la documentación de @composeDirective
Contact
aplicable en el esquema, consulte el uso @contact
Inaccessible
aplicable a todas las definiciones de tipo, consulte la documentación de @inaccessible
InterfaceObject
(desde v2.3) aplicable a objetos, consulte la documentación de @interfaceObject
KeyInterface
aplicable en interfaces, consulte la documentación de la interfaz de entidad @key
Link
aplicable al esquema, consulte la documentación @link
RequiresScopes
(desde v2.5) aplicable en enumeración, campo, interfaz y objeto, documentación @requiresScopes
Shareable
aplicable en el esquema, consulte la documentación @shareable
Resolución de entidad
Map
aplicable a los parámetros del método de resolución de entidades, le permite asignar argumentos complejos a un valor de representación más simple, por ejemplo, [Map("foo.bar")] string bar
ReferenceResolver
aplicable a métodos estáticos públicos dentro de una clase de entidad para indicar la resolución de entidadesAlternativamente, si necesita un control más granular, puede utilizar el método de código primero y completar manualmente la información de federación en el descriptor de tipo GraphQL subyacente. Todas las directivas federadas exponen los métodos correspondientes en el descriptor aplicable.
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 ) ;
}
Esto generará el siguiente tipo
type Product @key ( fields : " id " ) {
id : ID !
name : String !
description : String
}
Directivas de la Federación v1
ExtendsType
aplicable a objetos, consulte la documentación @extends
External
aplicable en campos, consulte la documentación @external
Key(fieldset)
aplicable a objetos, consulte la documentación @key
Provides(fieldset)
aplicable a los campos; consulte la documentación @provides
Requires(fieldset)
aplicable a los campos, consulte la documentación @requires
Directivas de federación v2 (incluye todas las directivas v1)
ApolloTag
aplicable a todas las definiciones de tipo, consulte la documentación @tag
ApolloAuthenticated
(desde v2.5) aplicable en enumeración, campo, interfaz y objeto, documentación @authenticated
ComposeDirective(name)
(desde v2.1) aplicable en el esquema, consulte la documentación @composeDirective
Contact(name, url?, description?)
aplicable en el esquema, consulte el uso @contact
Inaccessible
aplicable a todas las definiciones de tipo, consulte la documentación de @inaccessible
InterfaceObject
(desde v2.3) aplicable a objetos, consulte la documentación de @interfaceObject
Key(fieldset)
aplicable a objetos, consulte la documentación @key
Link(url, [import]?)
aplicable en el esquema, consulte la documentación @link
NonResolvableKey(fieldset)
aplicable a objetos; consulte la documentación @key
no resolubleRequiresScopes(scopes)
(desde v2.5) aplicable en enumeración, campo, interfaz y objeto, documentación @requiresScopes
Shareable
y se aplica a campos y objetos; consulte la documentación @shareable
Resolución de entidad
ResolveReferenceWith
para poder resolver las entidades Consulte la documentación de HotChocolate para obtener detalles sobre la compatibilidad del servidor con la interfaz de línea de comandos. Para generar un esquema en el momento de la compilación, debe agregar una dependencia adicional en el paquete HotChocolate.AspNetCore.CommandLine
y configurar su servidor para permitirle RunWithGraphQLCommands
.
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( )
// register your types and services
;
var app = builder . Build ( ) ;
app . MapGraphQL ( ) ;
app . RunWithGraphQLCommands ( args ) ;
Luego puede generar su esquema ejecutando
dotnet run -- schema export --output schema.graphql
De forma predeterminada, ApolloGraphQL.HotChocolate.Federation
generará un esquema utilizando la última versión compatible de Federation. Si desea optar por utilizar versiones anteriores, puede hacerlo especificando la versión al configurar la extensión AddApolloFederationV2
.
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( FederationVersion . FEDERATION_23 )
// register your types and services
;
Alternativamente, también puede proporcionar FederatedSchema
personalizado que se dirija a una versión específica de la Federación.
public class CustomSchema : FederatedSchema
{
public CustomSchema ( ) : base ( FederationVersion . FEDERATION_23 ) {
}
}
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( new CustomSchema ( ) )
// register your types and services
;
Si desea personalizar su esquema aplicando algunas directivas, también puede proporcionar FederatedSchema
personalizado que se puede anotar con atributos que extiendan 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
;
Alternativamente, también puede especificar una acción de configuración de esquema personalizada al crear un subgrafo federado.
var builder = WebApplication . CreateBuilder ( args ) ;
builder . Services
. AddGraphQLServer ( )
. AddApolloFederationV2 ( schemaConfiguration : s =>
{
// apply your directive here
} )
// register your types and services
;
@key
no resoluble Sus subgrafos pueden usar una entidad como tipo de retorno de un campo sin contribuir ningún campo a esa entidad. Dado que todavía necesitamos una definición de tipo para generar un esquema válido, podemos definir un objeto stub con [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
De forma predeterminada, el esquema Supergraph excluye todas las directivas personalizadas. @composeDirective
se utiliza para especificar directivas personalizadas que deben conservarse en el esquema de Supergraph.
ApolloGraphQL.HotChocolate.Federation
proporciona una clase FederatedSchema
común que aplica automáticamente la definición @link
de Apollo Federation v2. Al aplicar directivas de esquema personalizadas, debe ampliar esta clase y agregar los atributos/directivas necesarios.
Al aplicar @composedDirective
también necesita @link
a su especificación. Luego, su esquema personalizado debe pasarse a la extensión 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
;
Alternativamente, puede aplicar @composedDirective
aplicándolo directamente en un esquema de destino mediante la acción de configuración.
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 admite interfaces de entidad , una poderosa extensión de las interfaces GraphQL que le permite extender la funcionalidad de una interfaz a través del supergraph sin tener que implementar (o incluso conocer) todos sus tipos de implementación.
En un subgrafo que define la interfaz necesitamos aplicar @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 ; }
}
Luego podemos extender la interfaz en otro subgrafo convirtiéndola en un tipo, aplicando @interfaceObject
y la misma directiva @key
. Esto le permite agregar nuevos campos a cada entidad que implemente su interfaz (por ejemplo, agregar el campo Reviews
a todas las implementaciones Product
).
[ Key ( " id " ) ]
[ InterfaceObject ]
public class Product
{
[ ID ]
public string Id { get ; set ; }
public List < string > Reviews { get ; set ; }
}
La directiva @requiresScopes
se utiliza para indicar que el elemento de destino solo es accesible para los usuarios de supergraph autenticados con los alcances JWT apropiados. Consulte el artículo del enrutador Apollo para obtener detalles adicionales.
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 ) ) ;
}
Esto generará el siguiente esquema.
type Query {
product ( id : ID ! ): Product @requiresScopes ( scopes : [ [ " scope1, scope2 " , " scope3 " ], [ " scope4 " ] ])
}
Puede utilizar la directiva @contact
para agregar la información de contacto de su equipo a un esquema de subgrafo. Esta información se muestra en Studio, lo que ayuda a otros equipos a saber a quién contactar para obtener ayuda con el subgrafo. Consulte la documentación para obtener más detalles.
Necesitamos aplicar el atributo [Contact]
en un esquema. Puede aplicar el atributo [Contact]
en un esquema personalizado y pasar su esquema personalizado a la extensión 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
;
o aplique la directiva @contact
directamente en un esquema proporcionando una acción de configuración de esquema personalizada
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
utiliza automáticamente de forma predeterminada el nombre del tipo Query
. Cuando utilice tipos de operaciones Query
raíz personalizados, debe configurar explícitamente el esquema con esos valores personalizados.
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 ( ) ;
Migrar de HotChocolate.Federation
a ApolloGraphQL.HotChocolate.Federation
es fácil. Simplemente actualice la importación de su paquete para que apunte a un nuevo módulo
- +
y actualizar las importaciones de espacios de nombres
- using HotChocolate.ApolloFederation;
+ using ApolloGraphQL.HotChocolate.Federation;
Si bien intentamos que el proceso de migración fuera lo más fluido posible, tuvimos que realizar algunos ajustes en la biblioteca. Debido a la dependencia de algunas de las API internas, tuvimos que realizar los siguientes cambios importantes en la biblioteca:
[Key]
ahora se aplica solo en clases y ya no puedes aplicarla en campos individuales[ReferenceResolver]
ahora es aplicable solo en métodos estáticos públicos dentro de una entidad , ya no es aplicable en clases [EntityResolver]
puede asignar automáticamente la representación de la entidad a los valores @key
/ @requires
admitidos. Los campos @key
de escalares se asignan automáticamente y podemos usar el atributo [Map]
para asignar automáticamente valores escalares de conjuntos de selección complejos.
Actualmente no admitimos la asignación automática de valores de Lista y Objeto.
Como solución alternativa, debe analizar manualmente el objeto de representación en su implementación.
[ ReferenceResolver ]
public static Foo GetByFooBar (
[ LocalState ] ObjectValueNode data
Data repository )
{
// TODO implement logic here by manually reading values from local state data
}
@link
limitadoActualmente solo admitimos la importación de elementos de los subgrafos a los que se hace referencia.
Actualmente no se admiten espacios de nombres ni cambios de nombre de elementos. Consulte el problema para obtener más detalles.
Si tiene una pregunta específica sobre la biblioteca o el código, inicie una discusión en los foros de la comunidad de Apollo o inicie una conversación en nuestro servidor de Discord.
Para comenzar, bifurque el repositorio y consulte una nueva sucursal. Luego puede construir la biblioteca localmente ejecutando
# install dependencies
dotnet restore
# build project
dotnet build
# run tests
dotnet test
Ver más información en CONTRIBUTING.md.
Una vez que haya configurado su sucursal local, eche un vistazo a nuestros problemas abiertos para ver dónde puede contribuir.
Para obtener más información sobre cómo comunicarse con el equipo por cuestiones de seguridad, consulte nuestra Política de seguridad.
Esta biblioteca tiene la licencia MIT License (MIT).