GraphQL on Express

A Single Typed Endpoint — When REST Falls Short

GraphQL on Express

GraphQL lets clients request exactly the fields they need. Apollo and graphql-yoga are the standard Express integrations.

4 min read Level 3/5 #express#graphql#api
What you'll learn
  • Stand up a GraphQL endpoint on Express
  • Define a schema + resolvers
  • Decide REST vs GraphQL

GraphQL is an alternative to REST. One endpoint (/graphql), one typed schema, clients pick exactly which fields they want.

Pros

  • One round-trip, exactly the fields you need
  • Strong typing front-to-back
  • Fewer over-fetches and under-fetches
  • Great DX with code generators (graphql-codegen)

Cons

  • Caching at the HTTP layer is harder (one URL = same cache key)
  • Complexity for trivial APIs
  • N+1 query patterns need explicit prevention (DataLoader)

Setup with graphql-yoga

npm install graphql graphql-yoga
import { createYoga, createSchema } from "graphql-yoga";

const yoga = createYoga({
  schema: createSchema({
    typeDefs: /* GraphQL */ `
      type User {
        id:    ID!
        email: String!
        name:  String!
      }

      type Query {
        user(id: ID!): User
        users: [User!]!
      }

      type Mutation {
        createUser(email: String!, name: String!): User!
      }
    `,
    resolvers: {
      Query: {
        user:  (_, { id }, { db })  => db.users.findById(id),
        users: (_, __, { db })       => db.users.findMany(),
      },
      Mutation: {
        createUser: (_, args, { db }) => db.users.create(args),
      },
    },
  }),
  context: ({ request }) => ({
    db,
    user: request.user,   // attach via Express middleware
  }),
});

app.use("/graphql", yoga);

Yoga handles HTTP, parsing, errors, and serves a built-in GraphiQL explorer at /graphql.

Use From a Client

const res = await fetch("/graphql", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({
    query: `query GetUser($id: ID!) {
      user(id: $id) { id email name }
    }`,
    variables: { id: "42" },
  }),
});
const { data } = await res.json();

N+1 — Use DataLoader

The classic GraphQL trap: resolving 100 posts triggers 100 separate author queries.

npm install dataloader

DataLoader batches and caches per-request. Wrap each “by ID” loader, and 100 author lookups become one SELECT ... WHERE id IN (...).

REST vs GraphQL

Pick REST when…Pick GraphQL when…
Resources map 1:1 to URLsOne UI needs deeply nested data
HTTP caching mattersFrontend wants flexibility
Many simple endpointsYou have many client types (web + mobile + …)
Public API for the worldInternal API, you control both ends

For a typical Express app, REST first is the right call. Add GraphQL when REST’s shape genuinely hurts.

Caching →