Skip to content

Commit

Permalink
feat(core): Allow lazy evaluation of APIExtensionDefinitions
Browse files Browse the repository at this point in the history
This change allows you to define extensions to the GraphQL APIs in plugins which may rely on runtime execution, e.g. to dynamically build up the DocumentNode data based on some config options.
  • Loading branch information
michaelbromley committed Oct 24, 2019
1 parent c7857d3 commit 69dad0b
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 5 deletions.
20 changes: 20 additions & 0 deletions packages/core/e2e/fixtures/test-plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,26 @@ export class TestShopPluginResolver {
})
export class TestAPIExtensionPlugin {}

@Resolver()
export class TestLazyResolver {
@Query()
lazy() {
return 'sleeping';
}
}

@VendurePlugin({
shopApiExtensions: {
resolvers: () => [TestLazyResolver],
schema: () => gql`
extend type Query {
lazy: String!
}
`,
},
})
export class TestLazyExtensionPlugin {}

@Injectable()
export class NameService {
getNames(): string[] {
Expand Down
11 changes: 11 additions & 0 deletions packages/core/e2e/plugin.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ConfigService } from '../src/config/config.service';
import { TEST_SETUP_TIMEOUT_MS } from './config/test-config';
import {
TestAPIExtensionPlugin,
TestLazyExtensionPlugin,
TestPluginWithAllLifecycleHooks,
TestPluginWithConfigAndBootstrap,
TestPluginWithProvider,
Expand Down Expand Up @@ -41,6 +42,7 @@ describe('Plugins', () => {
TestPluginWithConfigAndBootstrap.setup(bootstrapMockFn),
TestAPIExtensionPlugin,
TestPluginWithProvider,
TestLazyExtensionPlugin,
],
},
);
Expand Down Expand Up @@ -85,6 +87,15 @@ describe('Plugins', () => {
expect(result.baz).toEqual(['quux']);
});

it('allows lazy evaluation of API extension', async () => {
const result = await shopClient.query(gql`
query {
lazy
}
`);
expect(result.lazy).toEqual('sleeping');
});

it('generates ListQueryOptions for api extensions', async () => {
const result = await adminClient.query(gql`
query {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/api/config/configure-graphql-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ async function createGraphQLOptions(
let schema = buildSchema(typeDefs);

getPluginAPIExtensions(configService.plugins, apiType)
.map(e => e.schema)
.map(e => (typeof e.schema === 'function' ? e.schema() : e.schema))
.filter(notNullOrUndefined)
.forEach(documentNode => (schema = extendSchema(schema, documentNode)));
schema = generateListOptions(schema);
Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/plugin/plugin-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,16 @@ export function graphQLResolversFor(
plugin: Type<any> | DynamicModule,
apiType: 'shop' | 'admin',
): Array<Type<any>> {
const apiExtensions =
const apiExtensions: APIExtensionDefinition =
apiType === 'shop'
? reflectMetadata(plugin, PLUGIN_METADATA.SHOP_API_EXTENSIONS)
: reflectMetadata(plugin, PLUGIN_METADATA.ADMIN_API_EXTENSIONS);

return apiExtensions ? apiExtensions.resolvers : [];
return apiExtensions
? typeof apiExtensions.resolvers === 'function'
? apiExtensions.resolvers()
: apiExtensions.resolvers
: [];
}

function reflectMetadata(metatype: Type<any> | DynamicModule, metadataKey: string) {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/plugin/vendure-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ export interface APIExtensionDefinition {
* }`;
* ```
*/
schema?: DocumentNode;
schema?: DocumentNode | (() => DocumentNode);
/**
* @description
* An array of resolvers for the schema extensions. Should be defined as [Nestjs GraphQL resolver](https://docs.nestjs.com/graphql/resolvers-map)
* classes, i.e. using the Nest `\@Resolver()` decorator etc.
*/
resolvers: Array<Type<any>>;
resolvers: Array<Type<any>> | (() => Array<Type<any>>);
}

/**
Expand Down

0 comments on commit 69dad0b

Please sign in to comment.