apollo-server-express GraphQL + TypeScript + esm
Apollo released Apollo Server 3 in July 2021 with the goal of offering more flexibility and a leaner code-base to build new features.
The core package for the server is apollo-server. If you want to integrate Apollo into an existing Express application or wish to use more advanced features, you’ll need apollo-server-express.
The documentation is user-friendly but does not provide a turn-key solution to get you started.
Apollo Server Express needs to start asynchronously which caused some problems.
In this article, I’ll show you the steps to create a simple Apollo Server with TypeScript, nodemon, ts-node and ESM (ES Modules).
Skeleton
Create a new project with npm
(you’ll need Node.js 12 or later).
I use Linux, so the code in my blog post works for Unix. If you’re a Windows user, you’ll probably need to adjust some of the commands.
mkdir apollo-3-ts && cd apollo-3-ts
npm init -y
Install dependencies:
npm i apollo-server-express apollo-server-core express graphql
npm i --save-dev typescript nodemon ts-node tsc-watch @types/node @types/express
Setup TypeScript:
npx tsc --init
The above command creates a new file called tsconfig.json
. Adjust the following parts in the file:
{
"module": "ES2020",
"moduleResolution": "Node",
"outDir": "./dist"
}
Compiled files (from TypeScript to JavaScript) will land in the dist folder.
Add these lines to package.json
to enable ECMAScript modules and allow imports from your compiled TypeScript files:
{
"type": "module",
"exports": "./dist/index.js"
}
Now, we will add a script for the development server into package.json
:
{
"scripts": {
"watch": "nodemon --watch './**/*.{ts,graphql}' --exec 'node --experimental-specifier-resolution=node --loader ts-node/esm' src/index.ts",
"dev": "tsc-watch --onSuccess \"npm run watch\""
}
}
You can find more details in the links at the end of the article.
Apollo Server Setup
Create a new folder called src
with a file index.ts
.
mkdir src && touch src/index.ts
You should now have a file structure like this:
apollo-3-ts <- folder name
├── node_modules
├── package.json
├── package-lock.json
├── src
│ └── index.ts
└── tsconfig.json
Copy the next code snippet into src/index.ts
. The code is from the documentation with a fix to promisify the http listener with TypeScript.
import { ApolloServer, gql } from 'apollo-server-express'
import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core'
import express from 'express'
import http from 'http'
const typeDefs = gql`
type Query {
hello: String
}
`
const resolvers = {
Query: {
hello() {
return 'world'
},
},
}
async function listen(port: number) {
const app = express()
const httpServer = http.createServer(app)
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
})
await server.start()
server.applyMiddleware({ app })
return new Promise((resolve, reject) => {
httpServer.listen(port).once('listening', resolve).once('error', reject)
})
}
async function main() {
try {
await listen(4000)
console.log('🚀 Server is ready at http://localhost:4000/graphql')
} catch (err) {
console.error('💀 Error starting the node server', err)
}
}
void main()
The code bootstraps the Apollo server with a minimal “Hello, world” resolver to get you started.
Now you can fire off the server from the command line:
npm run dev
You should be able to reach the GraphQL endpoint in your browser under http://localhost:4000/graphql
and Apollo Studio should pop up.
Thoughts
It was tricky to find out how to get the documentation example to work as it needs a JavaScript promise to listen to the server.
Luckily, GitHub had the solution. I only needed to know what to look for.