Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type parameters for context function separately from the context it produces #2350

Merged
merged 5 commits into from Feb 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
@@ -1,6 +1,7 @@
# Changelog

### vNEXT
- Fix typing for ContextFunction incorrectly requiring the context object the function produces to match the parameters of the function [PR #2350](https://github.com/apollographql/apollo-server/pull/2350)

### v2.4.3

Expand Down
14 changes: 7 additions & 7 deletions packages/apollo-server-core/src/types.ts
Expand Up @@ -29,10 +29,10 @@ export { GraphQLSchemaModule };

export { KeyValueCache } from 'apollo-server-caching';

export type Context<T = any> = T;
export type ContextFunction<T = any> = (
context: Context<T>,
) => Context<T> | Promise<Context<T>>;
export type Context<T = object> = T;
export type ContextFunction<FunctionParams = any, ProducedContext = object> = (
context: FunctionParams,
) => Context<ProducedContext> | Promise<Context<ProducedContext>>;

// A plugin can return an interface that matches `ApolloServerPlugin`, or a
// factory function that returns `ApolloServerPlugin`.
Expand All @@ -50,7 +50,7 @@ export interface SubscriptionServerOptions {
}

type BaseConfig = Pick<
GraphQLOptions<Context<any>>,
GraphQLOptions<Context>,
| 'formatError'
| 'debug'
| 'rootValue'
Expand All @@ -71,11 +71,11 @@ export interface Config extends BaseConfig {
resolvers?: IResolvers;
schema?: GraphQLSchema;
schemaDirectives?: Record<string, typeof SchemaDirectiveVisitor>;
context?: Context<any> | ContextFunction<any>;
context?: Context | ContextFunction;
introspection?: boolean;
mocks?: boolean | IMocks;
mockEntireSchema?: boolean;
engine?: boolean | EngineReportingOptions<Context<any>>;
engine?: boolean | EngineReportingOptions<Context>;
extensions?: Array<() => GraphQLExtension>;
cacheControl?: CacheControlExtensionOptions | boolean;
plugins?: PluginDefinition[];
Expand Down
2 changes: 1 addition & 1 deletion packages/apollo-server-express/src/ApolloServer.ts
Expand Up @@ -77,7 +77,7 @@ interface ExpressContext {

export interface ApolloServerExpressConfig extends Config {
cors?: CorsOptions | boolean;
context?: ContextFunction<ExpressContext> | Context<ExpressContext>;
context?: ContextFunction<ExpressContext, Context> | Context;
}

export class ApolloServer extends ApolloServerBase {
Expand Down
45 changes: 45 additions & 0 deletions packages/apollo-server/src/__tests__/index.test.ts
Expand Up @@ -24,6 +24,51 @@ describe('apollo-server', () => {
it('accepts typeDefs and mocks', () => {
expect(() => new ApolloServer({ typeDefs, mocks: true })).not.toThrow;
});

describe('context field', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests are a super welcome addition. Though I suspect we should put most of these in apollo-server-integration-testsuite to make sure they are exercised on each of the integration flavors (e.g. hapi, express, etc.), possibly alongside the existing constructor tests:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, I think this can be a follow-up PR. ^

describe('as a function', () => {
it('can accept and return `req`', () => {
expect(
new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => ({ req }),
}),
).not.toThrow;
});

it('can accept nothing and return an empty object', () => {
expect(
new ApolloServer({
typeDefs,
resolvers,
context: () => ({}),
}),
).not.toThrow;
});
});
});
describe('as an object', () => {
it('can be an empty object', () => {
expect(
new ApolloServer({
typeDefs,
resolvers,
context: {},
}),
).not.toThrow;
});

it('can contain arbitrary values', () => {
expect(
new ApolloServer({
typeDefs,
resolvers,
context: { value: 'arbitrary' },
}),
).not.toThrow;
});
});
});

describe('without registerServer', () => {
Expand Down