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

Restore "batteries-include" ApolloServer (v4) #6420

Merged
merged 31 commits into from
May 12, 2022

Conversation

trevor-scheer
Copy link
Member

@trevor-scheer trevor-scheer commented May 10, 2022

This PR (re) introduces the "batteries-included" version of ApolloServer. This server manages an express instance internally, meaning it is explicitly not configurable. This is intended to be a nice getting started experience, but more complicated use cases should "eject" to the expressMiddleware (i.e. serving various paths, installing other middlewares, etc.)

The usage is as follows:

import { ApolloServer, standaloneServer } from "@apollo/server";

interface MyContext {
  token: string;
}

const apolloServerInstance = new ApolloServer<MyContext>({
  typeDefs,
  resolvers,
});
const { url } = await standaloneServer(apolloServerInstance, {
  context: async (req, _res) => ({
    token: await getTokenForRequest(req),
  }),
}).listen({ port: 4000 });

console.log(`ApolloServer listening at: ${url}`);

standaloneServer returns an ApolloServerStandalone instance. The intention is to await the call to listen() on this class. The listen() method accepts the same arguments that http.Server's listen() method does (in the options form only).

Additionally, this PR introduces a new public function on the ApolloServer class, addPlugin. This function can be used to add plugins to ApolloServer (only in its initialized state). This enables us to use the drain http server plugin with the approach we've taken since the ApolloServer instance (and its plugins) are instantiated before the httpServer is, which the drain plugin needs a reference to. This API enables other "standalone server" authors to do the same if they choose.

Fixes #6085

@codesandbox-ci
Copy link

codesandbox-ci bot commented May 10, 2022

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 4558722:

Sandbox Source
Apollo Server Typescript Configuration
Apollo Server Configuration

Copy link
Member

@glasser glasser left a comment

Choose a reason for hiding this comment

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

looking great

packages/server/src/types.ts Outdated Show resolved Hide resolved
packages/server/src/standalone/index.ts Outdated Show resolved Hide resolved
packages/server/src/standalone/index.ts Outdated Show resolved Hide resolved
packages/server/src/standalone/index.ts Outdated Show resolved Hide resolved
packages/server/src/standalone/index.ts Outdated Show resolved Hide resolved
packages/server/src/standalone/index.ts Outdated Show resolved Hide resolved
@trevor-scheer trevor-scheer marked this pull request as ready for review May 11, 2022 23:17
Copy link
Member

@glasser glasser left a comment

Choose a reason for hiding this comment

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

At first I was surprised that the zillion tests that show "post to /graphql" don't break but I guess it's because we ignore the path. I think maybe a follow-up PR could replace all the /graphql with / in the tests?

const standaloneServerInstance = standaloneServer(server, opts);
await standaloneServerInstance.listen({ port: 0 });

return { server, httpServer: standaloneServerInstance['httpServer'] };
Copy link
Member

Choose a reason for hiding this comment

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

It might make sense to update the integration test's API to take an URL instead of an http.Server (are there any uses of the httpServer that can't be replaced by an URL? supertest can). That way we could support integrations that somehow don't literally use an http.Server (maybe some serverless things might work that way?) as long as they can serve at an URL. I think this could be a follow-up PR though!

@glasser
Copy link
Member

glasser commented May 11, 2022

Not quite sure why the sample code is showing that try/catch though (which logs the last line even on error) rather than just

import { ApolloServer, standaloneServer } from "@apollo/server";

interface MyContext {
  token: string;
}

const apolloServerInstance = new ApolloServer<MyContext>({ typeDefs, resolvers });
const { url } = await standaloneServer(apolloServerInstance, {
  context: async (req, _res) => ({ token: await getTokenForRequest(req) }),
}).listen({ port: 4000 });
console.log(`ApolloServer listening at: ${url}`);

(also the example doesn't work due to having non-base context but no context function)

@trevor-scheer
Copy link
Member Author

Updated example to remove try/catch, but we agreed sync the context is actually fine. Will follow up in a separate PR with those changes!

@trevor-scheer trevor-scheer merged commit ec08efe into version-4 May 12, 2022
@trevor-scheer trevor-scheer deleted the trevor/standalone branch May 12, 2022 18:49
@trevor-scheer
Copy link
Member Author

At first I was surprised that the zillion tests that show "post to /graphql" don't break but I guess it's because we ignore the path. I think maybe a follow-up PR could replace all the /graphql with / in the tests?

Resolved in #6425

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 20, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants