diff --git a/src/core/blueprint/operators/apollo_federation.rs b/src/core/blueprint/operators/apollo_federation.rs index 740a96ccde..f63a9ded64 100644 --- a/src/core/blueprint/operators/apollo_federation.rs +++ b/src/core/blueprint/operators/apollo_federation.rs @@ -1,7 +1,9 @@ use std::collections::HashMap; use std::fmt::Write; -use async_graphql::parser::types::{SchemaDefinition, ServiceDocument, TypeSystemDefinition}; +use async_graphql::parser::types::{ + SchemaDefinition, ServiceDocument, TypeDefinition, TypeSystemDefinition, +}; use super::{compile_call, compile_expr, compile_graphql, compile_grpc, compile_http, compile_js}; use crate::core::blueprint::FieldDefinition; @@ -13,6 +15,22 @@ use crate::core::try_fold::TryFold; use crate::core::valid::{Valid, Validator}; use crate::core::{config, Type}; +// ref: https://www.apollographql.com/docs/federation/federated-schemas/federated-directives +const FEDERATION_DIRECTIVES: &[&str] = &[ + "link", + "key", + "extends", + "external", + "provides", + "requires", + "tag", + "shareable", + "inaccessible", + "override", + "composeDirective", + "interfaceObject", +]; + pub struct CompileEntityResolver<'a> { config_module: &'a ConfigModule, entity_resolver: &'a EntityResolver, @@ -96,7 +114,7 @@ pub fn compile_service(config: &ConfigModule) -> Valid { fn filter_conflicting_directives(sd: ServiceDocument) -> ServiceDocument { fn filter_directive(directive_name: &str) -> bool { - directive_name == "link" + FEDERATION_DIRECTIVES.iter().any(|d| *d == directive_name) } fn filter_map(def: TypeSystemDefinition) -> Option { @@ -120,7 +138,16 @@ fn filter_conflicting_directives(sd: ServiceDocument) -> ServiceDocument { None } } - ty => Some(ty), + TypeSystemDefinition::Type(ty) => Some(TypeSystemDefinition::Type(ty.map(|ty| { + TypeDefinition { + directives: ty + .directives + .into_iter() + .filter(|d| filter_directive(d.node.name.node.as_str())) + .collect(), + ..ty + } + }))), } } diff --git a/tests/core/snapshots/apollo-federation-entities-batch.md_1.snap b/tests/core/snapshots/apollo-federation-entities-batch.md_1.snap index d7280273fa..388cc5ae49 100644 --- a/tests/core/snapshots/apollo-federation-entities-batch.md_1.snap +++ b/tests/core/snapshots/apollo-federation-entities-batch.md_1.snap @@ -10,7 +10,7 @@ expression: response "body": { "data": { "_service": { - "sdl": "schema {\n query: Query\n}\n\nscalar _Any\n\nunion _Entity = Post | User\n\ntype Post @graphQL(args: [{key: \"id\", value: \"{{.value.id}}\"}], baseURL: \"http://upstream/graphql\", batch: true, name: \"post\") @key(fields: \"id\") {\n id: Int!\n title: String!\n}\n\ntype Query {\n \"\"\"\n Apollo federation Query._entities resolver\n \"\"\"\n _entities(representations: [_Any!]!): [_Entity]!\n \"\"\"\n Apollo federation Query._service resolver\n \"\"\"\n _service: _Service!\n user(id: Int!): User @http(path: \"/users/{{.args.id}}\")\n}\n\ntype User @http(batchKey: [\"id\"], path: \"/users\", query: [{key: \"id\", value: \"{{.value.id}}\"}]) @key(fields: \"id\") {\n id: Int!\n name: String!\n}\n\ntype _Service {\n sdl: String\n}\nextend schema @link(\n\turl: \"https://specs.apollo.dev/federation/v2.3\",\n\timport: [\"@key\", \"@tag\", \"@shareable\", \"@inaccessible\", \"@override\", \"@external\", \"@provides\", \"@requires\", \"@composeDirective\", \"@interfaceObject\"]\n)\n" + "sdl": "schema {\n query: Query\n}\n\nscalar _Any\n\nunion _Entity = Post | User\n\ntype Post @key(fields: \"id\") {\n id: Int!\n title: String!\n}\n\ntype Query {\n \"\"\"\n Apollo federation Query._entities resolver\n \"\"\"\n _entities(representations: [_Any!]!): [_Entity]!\n \"\"\"\n Apollo federation Query._service resolver\n \"\"\"\n _service: _Service!\n user(id: Int!): User @http(path: \"/users/{{.args.id}}\")\n}\n\ntype User @key(fields: \"id\") {\n id: Int!\n name: String!\n}\n\ntype _Service {\n sdl: String\n}\nextend schema @link(\n\turl: \"https://specs.apollo.dev/federation/v2.3\",\n\timport: [\"@key\", \"@tag\", \"@shareable\", \"@inaccessible\", \"@override\", \"@external\", \"@provides\", \"@requires\", \"@composeDirective\", \"@interfaceObject\"]\n)\n" } } } diff --git a/tests/core/snapshots/apollo-federation-entities.md_1.snap b/tests/core/snapshots/apollo-federation-entities.md_1.snap index 621969f71a..2c7a688cb3 100644 --- a/tests/core/snapshots/apollo-federation-entities.md_1.snap +++ b/tests/core/snapshots/apollo-federation-entities.md_1.snap @@ -10,7 +10,7 @@ expression: response "body": { "data": { "_service": { - "sdl": "schema @link(src: \"./posts.graphql\", type: Config) {\n query: Query\n}\n\nscalar _Any\n\nunion _Entity = Post | User\n\ntype Post @expr(body: {id: \"{{.value.id}}\", title: \"post-title-{{.value.id}}\"}) @key(fields: \"id\") {\n id: Int!\n title: String!\n}\n\ntype Query {\n \"\"\"\n Apollo federation Query._entities resolver\n \"\"\"\n _entities(representations: [_Any!]!): [_Entity]!\n \"\"\"\n Apollo federation Query._service resolver\n \"\"\"\n _service: _Service!\n user(id: Int!): User @http(path: \"/users/{{.args.id}}\")\n}\n\ntype User @call(steps: [{query: \"user\", args: {id: \"{{.value.id}}\"}}]) @key(fields: \"id\") {\n id: Int!\n name: String!\n}\n\ntype _Service {\n sdl: String\n}\nextend schema @link(\n\turl: \"https://specs.apollo.dev/federation/v2.3\",\n\timport: [\"@key\", \"@tag\", \"@shareable\", \"@inaccessible\", \"@override\", \"@external\", \"@provides\", \"@requires\", \"@composeDirective\", \"@interfaceObject\"]\n)\n" + "sdl": "schema @link(src: \"./posts.graphql\", type: Config) {\n query: Query\n}\n\nscalar _Any\n\nunion _Entity = Post | User\n\ntype Post @key(fields: \"id\") {\n id: Int!\n title: String!\n}\n\ntype Query {\n \"\"\"\n Apollo federation Query._entities resolver\n \"\"\"\n _entities(representations: [_Any!]!): [_Entity]!\n \"\"\"\n Apollo federation Query._service resolver\n \"\"\"\n _service: _Service!\n user(id: Int!): User @http(path: \"/users/{{.args.id}}\")\n}\n\ntype User @key(fields: \"id\") {\n id: Int!\n name: String!\n}\n\ntype _Service {\n sdl: String\n}\nextend schema @link(\n\turl: \"https://specs.apollo.dev/federation/v2.3\",\n\timport: [\"@key\", \"@tag\", \"@shareable\", \"@inaccessible\", \"@override\", \"@external\", \"@provides\", \"@requires\", \"@composeDirective\", \"@interfaceObject\"]\n)\n" } } }