Get Started
Scaffold a tiny GraphQL server with Apollo Server, define a schema, write resolvers, and query it from a client.
GraphQL — getting started
EXAMPLE
# ===== Server (Apollo Server, Node) =====
mkdir gql-demo && cd gql-demo
npm init -y
npm install @apollo/server graphql
# server.mjs
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
const typeDefs = \`
type Book {
id: ID!
title: String!
author: String!
}
type Query {
books: [Book!]!
book(id: ID!): Book
}
type Mutation {
addBook(title: String!, author: String!): Book!
}
\`;
const data = [
{ id: '1', title: 'The Pragmatic Programmer', author: 'Hunt & Thomas' },
];
const resolvers = {
Query: {
books: () => data,
book: (_, { id }) => data.find(b => b.id === id),
},
Mutation: {
addBook: (_, { title, author }) => {
const b = { id: String(data.length + 1), title, author };
data.push(b);
return b;
},
},
};
const server = new ApolloServer({ typeDefs, resolvers });
const { url } = await startStandaloneServer(server, { listen: { port: 4000 } });
console.log('Ready at', url);
# Run:
node server.mjs
# Visit http://localhost:4000 — Apollo Studio sandbox loads.
# ===== A query =====
# In the sandbox:
query {
books { id title author }
book(id: "1") { title }
}
# A mutation:
mutation {
addBook(title: "Refactoring", author: "Fowler") { id title }
}
# ===== Client (urql) =====
npm install @urql/core graphql
// client.mjs
import { Client, cacheExchange, fetchExchange } from '@urql/core';
const client = new Client({ url: 'http://localhost:4000', exchanges: [cacheExchange, fetchExchange] });
const r = await client.query('{ books { id title } }', {}).toPromise();
console.log(r.data.books);
# ===== With variables =====
const VARS = \`query Get($id: ID!) { book(id: $id) { title author } }\`;
const r2 = await client.query(VARS, { id: '1' }).toPromise();
# ===== Where to go next =====
# - Schema-first design (organise typeDefs in .graphql files)
# - DataLoader for batching DB lookups (N+1)
# - Code generation (graphql-codegen) for typed clients
# - Authn / authz in context
# - Persisted queries on public APIs
# ===== Patterns to internalise =====
# - Start with a tiny schema; iterate
# - Resolver gets (parent, args, context, info) — use args for arguments
# - Apollo Studio for instant docs / playground
# - Use context for auth + datasource handles
# ===== Pitfalls =====
# - One mega-Query type with everything attached
# - Returning bare Promise<Mongoose> -> serialises private fields
# - No query depth limit on a public API
# - Throwing strings instead of GraphQLError (loses error shape)
Why it matters
A working GraphQL server is 30 lines of code. typeDefs + resolvers + ApolloServer + sandbox. Hook up a client, learn variables + selection sets, then layer DataLoader and codegen as the schema grows. That is the on-ramp.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
npm init -y npm install graphql graphql-yoga # Then write a schema + resolvers; ship.Try it Yourself »
Discussion
Loading…