Adding GraphQL to Your Skill List

REST APIs have served the web well, but they come with a predictable set of frustrations: endpoints that return too much data, multiple round trips to assemble a view, and versioning headaches as clients evolve. GraphQL addresses all three. Understanding it—even if you’re primarily a frontend developer—opens up a new way of thinking about data fetching.

What GraphQL Is

GraphQL is a query language for APIs and a runtime for executing those queries. It was developed at Facebook to serve their mobile clients, which needed efficient, flexible data access over constrained networks.

The key idea: the client defines the shape of the response. The server exposes a schema that describes what’s available, and the client queries exactly what it needs.

The Schema

A GraphQL server is built around a strongly-typed schema written in SDL (Schema Definition Language):

type Author {
  id: ID!
  name: String!
  bio: String
  posts: [Post!]!
}

type Post {
  id: ID!
  title: String!
  body: String!
  publishedAt: String!
  author: Author!
}

type Query {
  posts: [Post!]!
  post(id: ID!): Post
  author(id: ID!): Author
}

The ! means non-nullable. [Post!]! means the field always returns a non-null list of non-null posts.

Queries

A query is a read operation. The client specifies exactly which fields it wants:

query {
  posts {
    title
    publishedAt
    author {
      name
    }
  }
}

The response mirrors the query shape:

{
  "data": {
    "posts": [
      {
        "title": "Introduction to GraphQL",
        "publishedAt": "2020-10-01",
        "author": { "name": "Peter Tumulty" }
      }
    ]
  }
}

Notice the bio field from Author isn’t in the response—because the client didn’t ask for it. This is the over-fetching fix.

Variables

Hard-coded values in queries are impractical. Variables make queries reusable:

query GetPost($id: ID!) {
  post(id: $id) {
    title
    body
    author {
      name
    }
  }
}

Send variables alongside the query:

{ "id": "abc123" }

Mutations

Mutations are write operations—create, update, delete:

mutation CreatePost($title: String!, $body: String!) {
  createPost(title: $title, body: $body) {
    id
    title
  }
}

The response lets you refetch relevant data in the same round trip.

Fetching Without a Library

You don’t need Apollo or urql to use GraphQL. It’s just HTTP POST with JSON:

async function fetchGraphQL(query, variables = {}) {
  const response = await fetch("https://api.example.com/graphql", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${TOKEN}`,
    },
    body: JSON.stringify({ query, variables }),
  });
  return response.json();
}

For simple use cases, this is all you need.

Resolvers

On the server side, each field in the schema has a resolver function—a function that returns the field’s data. If you’re building a GraphQL server (with Apollo Server, for example), your resolvers connect schema fields to your database or other services.

const resolvers = {
  Query: {
    posts: () => db.posts.findAll(),
    post: (_, { id }) => db.posts.findById(id),
  },
  Post: {
    author: (post) => db.authors.findById(post.authorId),
  },
};

When GraphQL Shines

GraphQL is especially valuable when:

  • Multiple clients need different shapes — a mobile app needs less data than a web dashboard
  • The data graph is deeply nested — GraphQL collapses multiple REST round trips into one query
  • Rapid frontend iteration — frontend developers can evolve their queries without backend changes

For a simple CRUD API with a single client, REST is often simpler. GraphQL’s value compounds as complexity grows.

Adding GraphQL to your skill set means you can work comfortably with APIs like GitHub, Shopify, and Contentful, build efficient data layers for React apps, and understand the design tradeoffs between REST and graph-based APIs.