Skip to content

Commit

Permalink
Update most Apollo Server examples to Apollo Server 3
Browse files Browse the repository at this point in the history
Previously, most of the examples used Apollo Server 2. As a maintainer of Apollo
Server, we frequently found that users would start with one of these examples,
try to upgrade to Apollo Server 3, and get confused when it didn't work. Apollo
Server 3 has a more explicit lifecycle that requires awaiting a `start` method
on startup, and users often put this in the wrong place.  The
`api-routes-graphql` package did use Apollo Server 3 and did call `start`, but
only awaits it when the first request comes in rather than at the top level.

Additionally, all the examples use `apollo-server-micro`. While this package is
technically a maintained part of the Apollo Server project, it is not as fully
featured or battle-tested as the most popular package,
`apollo-server-express`. For example, it doesn't have the same default CORS
behavior has the other Apollo Server framework integrations, and doesn't have a
way to drain servers gracefully on shutdown. (Future Apollo Server features may
target `apollo-server-express` before other integrations as well.) Because
Next.js can easily use Express middleware with just a few lines of integration
code (documented at
https://nextjs.org/docs/api-routes/api-middlewares#connectexpress-middleware-support),
Next.js users would be best served by using the most mainstream ApolloServer
implementation rather than the least maintained one.

So this PR:
- Changes all examples from using `apollo-server-micro` v2 to
  `apollo-server-express` v3
- Uses top level await (enabled in next.config.js) for proper startup handling
- Upgrades other packages like `graphql` and `@graphql-tools/schema`, and
  installs them where relevant
- Removes special CORS handling from `examples/api-routes-graphql` because
  `apollo-server-express` has better CORS defaults. (If the default is not good
  enough for this example, pass a `cors` option to `getMiddleware` instead of
  doing CORS manually. The value of the `cors` option is equivalent to the
  argument to the npm `cors` package's middleware.)

This leaves the `with-apollo-neo4j-graphql` example alone, as I could not get it
to work properly before or after upgrading Apollo Server.
  • Loading branch information
glasser committed Oct 20, 2021
1 parent 6f3dc01 commit 3488f39
Show file tree
Hide file tree
Showing 20 changed files with 164 additions and 51 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AuthenticationError, UserInputError } from 'apollo-server-micro'
import { AuthenticationError, UserInputError } from 'apollo-server-express'
import { createUser, findUser, validatePassword } from '../lib/user'
import { setLoginSession, getLoginSession } from '../lib/auth'
import { removeTokenCookie } from '../lib/auth-cookies'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { makeExecutableSchema } from 'graphql-tools'
import { makeExecutableSchema } from '@graphql-tools/schema'
import { typeDefs } from './type-defs'
import { resolvers } from './resolvers'

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
webpack: (config, options) => {
config.experiments = {
topLevelAwait: true,
}
return config
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
},
"dependencies": {
"@apollo/client": "^3.0.2",
"@graphql-tools/schema": "^8.3.0",
"@hapi/iron": "6.0.0",
"apollo-server-micro": "^2.14.2",
"apollo-server-express": "^3.4.0",
"cookie": "^0.4.1",
"deepmerge": "4.2.2",
"graphql": "^14.0.2",
"express": "^4.17.1",
"graphql": "^15.6.1",
"next": "latest",
"prop-types": "^15.6.2",
"react": "^17.0.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
import { ApolloServer } from 'apollo-server-micro'
import { ApolloServer } from 'apollo-server-express'
import { schema } from '../../apollo/schema'

function runMiddleware(req, res, fn) {
return new Promise((resolve, reject) => {
fn(req, res, (result) => {
if (result instanceof Error) {
return reject(result)
}

return resolve(result)
})
})
}

const apolloServer = new ApolloServer({
schema,
context(ctx) {
return ctx
},
})
await apolloServer.start()
const apolloMiddleware = apolloServer.getMiddleware({
path: '/api/graphql',
})

export const config = {
api: {
bodyParser: false,
},
}

export default apolloServer.createHandler({ path: '/api/graphql' })
export default async function handler(req, res) {
await runMiddleware(req, res, apolloMiddleware)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { makeExecutableSchema } from 'graphql-tools'
import { makeExecutableSchema } from '@graphql-tools/schema'
import { typeDefs } from './type-defs'
import { resolvers } from './resolvers'

Expand Down
8 changes: 8 additions & 0 deletions examples/api-routes-apollo-server-and-client/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
webpack: (config, options) => {
config.experiments = {
topLevelAwait: true,
}
return config
},
}
6 changes: 4 additions & 2 deletions examples/api-routes-apollo-server-and-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
},
"dependencies": {
"@apollo/client": "^3.0.2",
"apollo-server-micro": "^2.14.2",
"graphql": "^14.0.2",
"@graphql-tools/schema": "^8.3.0",
"apollo-server-express": "^3.4.0",
"express": "^4.17.1",
"graphql": "^15.6.1",
"next": "latest",
"prop-types": "^15.6.2",
"react": "^17.0.2",
Expand Down
22 changes: 20 additions & 2 deletions examples/api-routes-apollo-server-and-client/pages/api/graphql.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import { ApolloServer } from 'apollo-server-micro'
import { ApolloServer } from 'apollo-server-express'
import { schema } from '../../apollo/schema'

function runMiddleware(req, res, fn) {
return new Promise((resolve, reject) => {
fn(req, res, (result) => {
if (result instanceof Error) {
return reject(result)
}

return resolve(result)
})
})
}

const apolloServer = new ApolloServer({ schema })
await apolloServer.start()
const apolloMiddleware = apolloServer.getMiddleware({
path: '/api/graphql',
})

export const config = {
api: {
bodyParser: false,
},
}

export default apolloServer.createHandler({ path: '/api/graphql' })
export default async function handler(req, res) {
await runMiddleware(req, res, apolloMiddleware)
}
8 changes: 8 additions & 0 deletions examples/api-routes-apollo-server/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
webpack: (config, options) => {
config.experiments = {
topLevelAwait: true,
}
return config
},
}
6 changes: 4 additions & 2 deletions examples/api-routes-apollo-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
"start": "next start"
},
"dependencies": {
"apollo-server-micro": "2.13.1",
"graphql": "15.0.0",
"@graphql-tools/schema": "^8.3.0",
"apollo-server-express": "^3.4.0",
"express": "^4.17.1",
"graphql": "^15.6.1",
"next": "latest",
"react": "^17.0.2",
"react-dom": "^17.0.2"
Expand Down
27 changes: 23 additions & 4 deletions examples/api-routes-apollo-server/pages/api/graphql.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ApolloServer, gql, makeExecutableSchema } from 'apollo-server-micro'
import { ApolloServer, gql } from 'apollo-server-express'
import { makeExecutableSchema } from '@graphql-tools/schema'

const typeDefs = gql`
type Query {
Expand Down Expand Up @@ -28,12 +29,30 @@ const resolvers = {

export const schema = makeExecutableSchema({ typeDefs, resolvers })

function runMiddleware(req, res, fn) {
return new Promise((resolve, reject) => {
fn(req, res, (result) => {
if (result instanceof Error) {
return reject(result)
}

return resolve(result)
})
})
}

const apolloServer = new ApolloServer({ typeDefs, resolvers })
await apolloServer.start()
const apolloMiddleware = apolloServer.getMiddleware({
path: '/api/graphql',
})

export const config = {
api: {
bodyParser: false,
},
}

export default new ApolloServer({ schema }).createHandler({
path: '/api/graphql',
})
export default async function handler(req, res) {
await runMiddleware(req, res, apolloMiddleware)
}
2 changes: 1 addition & 1 deletion examples/api-routes-graphql/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# API routes with GraphQL server

Next.js ships with [API routes](https://github.com/vercel/next.js#api-routes), which provide an easy solution to build your own `API`. This example shows their usage alongside [apollo-server-micro](https://github.com/apollographql/apollo-server/tree/main/packages/apollo-server-micro) to provide simple GraphQL server consumed by Next.js app.
Next.js ships with [API routes](https://github.com/vercel/next.js#api-routes), which provide an easy solution to build your own `API`. This example shows their usage alongside [apollo-server-express](https://github.com/apollographql/apollo-server/tree/main/packages/apollo-server-express) to provide simple GraphQL server consumed by Next.js app.

## Preview

Expand Down
8 changes: 8 additions & 0 deletions examples/api-routes-graphql/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
webpack: (config, options) => {
config.experiments = {
topLevelAwait: true,
}
return config
},
}
6 changes: 3 additions & 3 deletions examples/api-routes-graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
"start": "next start"
},
"dependencies": {
"apollo-server-micro": "^3.0.1",
"graphql": "^15.5.1",
"micro": "^9.3.4",
"apollo-server-express": "^3.4.0",
"express": "^4.17.1",
"graphql": "^15.6.1",
"next": "latest",
"react": "^17.0.2",
"react-dom": "^17.0.2",
Expand Down
39 changes: 18 additions & 21 deletions examples/api-routes-graphql/pages/api/graphql.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ApolloServer, gql } from 'apollo-server-micro'
import { ApolloServer, gql } from 'apollo-server-express'

const typeDefs = gql`
type Query {
Expand All @@ -17,29 +17,26 @@ const resolvers = {
},
}

const apolloServer = new ApolloServer({ typeDefs, resolvers })
function runMiddleware(req, res, fn) {
return new Promise((resolve, reject) => {
fn(req, res, (result) => {
if (result instanceof Error) {
return reject(result)
}

const startServer = apolloServer.start()
return resolve(result)
})
})
}

export default async function handler(req, res) {
res.setHeader('Access-Control-Allow-Credentials', 'true')
res.setHeader(
'Access-Control-Allow-Origin',
'https://studio.apollographql.com'
)
res.setHeader(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
)
if (req.method === 'OPTIONS') {
res.end()
return false
}
const apolloServer = new ApolloServer({ typeDefs, resolvers })
await apolloServer.start()
const apolloMiddleware = apolloServer.getMiddleware({
path: '/api/graphql',
})

await startServer
await apolloServer.createHandler({
path: '/api/graphql',
})(req, res)
export default async function handler(req, res) {
await runMiddleware(req, res, apolloMiddleware)
}

export const config = {
Expand Down
4 changes: 4 additions & 0 deletions examples/with-typescript-graphql/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ module.exports = {
use: 'yaml-loader',
})

config.experiments = {
topLevelAwait: true,
}

return config
},
}
13 changes: 7 additions & 6 deletions examples/with-typescript-graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
},
"dependencies": {
"@apollo/client": "^3.1.3",
"@graphql-tools/load-files": "6.0.18",
"@graphql-tools/merge": "6.0.18",
"@graphql-tools/schema": "6.0.18",
"apollo-server-micro": "^2.16.1",
"graphql": "15.3.0",
"@graphql-tools/load-files": "^6.5.1",
"@graphql-tools/merge": "^8.2.0",
"@graphql-tools/schema": "^8.3.0",
"apollo-server-express": "^3.4.0",
"express": "^4.17.1",
"graphql": "^15.6.1",
"next": "latest",
"react": "^17.0.2",
"react-dom": "^17.0.2"
Expand All @@ -31,7 +32,7 @@
"@types/react-test-renderer": "^17.0.1",
"babel-jest": "26.3.0",
"graphql-let": "0.x",
"graphql-tag": "2.11.0",
"graphql-tag": "^2.12.5",
"jest": "26.4.0",
"react-test-renderer": "^17.0.1",
"typescript": "^3.9.7",
Expand Down
22 changes: 20 additions & 2 deletions examples/with-typescript-graphql/pages/api/graphql.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import { ApolloServer } from 'apollo-server-micro'
import { ApolloServer } from 'apollo-server-express'
import { schema } from '../../lib/schema'

function runMiddleware(req, res, fn) {
return new Promise((resolve, reject) => {
fn(req, res, (result) => {
if (result instanceof Error) {
return reject(result)
}

return resolve(result)
})
})
}

const apolloServer = new ApolloServer({ schema })
await apolloServer.start()
const apolloMiddleware = apolloServer.getMiddleware({
path: '/api/graphql',
})

export const config = {
api: {
bodyParser: false,
},
}

export default apolloServer.createHandler({ path: '/api/graphql' })
export default async function handler(req, res) {
await runMiddleware(req, res, apolloMiddleware)
}
2 changes: 1 addition & 1 deletion examples/with-typescript-graphql/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es5",
"target": "es2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
Expand Down

0 comments on commit 3488f39

Please sign in to comment.