Skip to content

Commit

Permalink
Merge pull request #1444 from advantitge/fix/federation-resolvetype
Browse files Browse the repository at this point in the history
fix(federation): override federated resolveType for interfaces
  • Loading branch information
kamilmysliwiec authored Mar 22, 2021
2 parents 9877e94 + 41ad53a commit c9bde25
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 8 deletions.
2 changes: 1 addition & 1 deletion lib/federation/graphql-federation.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export class GraphQLFederationFactory {
// Bail if inconsistent with original schema
if (
!autoGeneratedType ||
!(autoGeneratedType instanceof GraphQLUnionType) ||
!(autoGeneratedType instanceof GraphQLUnionType || autoGeneratedType instanceof GraphQLInterfaceType) ||
!autoGeneratedType.resolveType
) {
return typeInFederatedSchema;
Expand Down
22 changes: 16 additions & 6 deletions lib/schema-builder/factories/interface-definition.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,15 @@ export class InterfaceDefinitionFactory {
return () => {
let fields: GraphQLFieldConfigMap<any, any> = {};
metadata.properties.forEach((field) => {
const type = this.outputTypeFactory.create(
field.name,
field.typeFn(),
options,
field.options,
);
fields[field.schemaName] = {
description: field.description,
type: this.outputTypeFactory.create(
field.name,
field.typeFn(),
options,
field.options,
),
type,
args: this.argsFactory.create(field.methodArgs, options),
resolve: (root: object) => {
const value = root[field.name];
Expand All @@ -127,6 +128,15 @@ export class InterfaceDefinitionFactory {
: value;
},
deprecationReason: field.deprecationReason,
/**
* AST node has to be manually created in order to define directives
* (more on this topic here: https://github.com/graphql/graphql-js/issues/1343)
*/
astNode: this.astDefinitionNodeFactory.createFieldNode(
field.name,
type,
field.directives,
),
extensions: {
complexity: field.complexity,
...field.extensions,
Expand Down
2 changes: 2 additions & 0 deletions tests/code-first-federation/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { GraphQLFederationModule } from '../../lib';
import { UserModule } from './user/user.module';
import { PostModule } from './post/post.module';
import { User } from './user/user.entity';
import { RecipeModule } from './recipe/recipe.module';

@Module({
imports: [
UserModule,
PostModule,
RecipeModule,
GraphQLFederationModule.forRoot({
debug: false,
autoSchemaFile: true,
Expand Down
10 changes: 10 additions & 0 deletions tests/code-first-federation/recipe/irecipe.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Query, Resolver } from '../../../lib';
import { IRecipe } from './recipe';

@Resolver((of) => IRecipe)
export class IRecipeResolver {
@Query((returns) => IRecipe)
public recipe() {
return { id: '1', title: 'Recipe', description: 'Interface description' }
}
}
7 changes: 7 additions & 0 deletions tests/code-first-federation/recipe/recipe.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Module } from '@nestjs/common';
import { IRecipeResolver } from './irecipe.resolver';

@Module({
providers: [IRecipeResolver],
})
export class RecipeModule {}
33 changes: 33 additions & 0 deletions tests/code-first-federation/recipe/recipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {
Directive,
Field,
ID,
InterfaceType,
ObjectType,
} from '../../../lib';

@InterfaceType()
export abstract class Base {
@Field((type) => ID)
id: string;
}

@InterfaceType({
resolveType: (value) => {
return Recipe;
},
})
export abstract class IRecipe extends Base {
@Field()
title: string;

@Field()
@Directive('@external')
externalField: string;
}

@ObjectType({ implements: IRecipe })
export class Recipe extends IRecipe {
@Field()
description: string;
}
26 changes: 25 additions & 1 deletion tests/e2e/code-first-federation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe('Code-first - Federation', () => {
expect(response.data).toEqual({
_service: {
sdl:
'"""Search result description"""\nunion FederationSearchResultUnion = Post | User\n\ntype Post @key(fields: "id") {\n id: ID!\n title: String!\n authorId: Int!\n}\n\ntype Query {\n findPost(id: Float!): Post!\n getPosts: [Post!]!\n search: [FederationSearchResultUnion!]! @deprecated(reason: "test")\n}\n\ntype User @extends @key(fields: "id") {\n id: ID! @external\n posts: [Post!]!\n}\n',
'"""Search result description"""\nunion FederationSearchResultUnion = Post | User\n\ninterface IRecipe {\n id: ID!\n title: String!\n externalField: String! @external\n}\n\ntype Post @key(fields: "id") {\n id: ID!\n title: String!\n authorId: Int!\n}\n\ntype Query {\n findPost(id: Float!): Post!\n getPosts: [Post!]!\n search: [FederationSearchResultUnion!]! @deprecated(reason: "test")\n recipe: IRecipe!\n}\n\ntype Recipe implements IRecipe {\n id: ID!\n title: String!\n externalField: String! @external\n description: String!\n}\n\ntype User @extends @key(fields: "id") {\n id: ID! @external\n posts: [Post!]!\n}\n',
},
});
});
Expand Down Expand Up @@ -67,6 +67,30 @@ describe('Code-first - Federation', () => {
});
});

it(`should return query result`, async () => {
const response = await apolloClient.query({
query: gql`
{
recipe {
id
title
... on Recipe {
description
}
}
}
`,
});
expect(response.data).toEqual({
recipe:
{
id: '1',
title: 'Recipe',
description: 'Interface description',
},
});
});

afterEach(async () => {
await app.close();
});
Expand Down

0 comments on commit c9bde25

Please sign in to comment.