Consuming GraphQL from a Frontend

intermediate
12 min

Consuming GraphQL from a Frontend

A GraphQL server is only half the story. This lesson covers the client side: how requests actually travel over HTTP, when plain fetch is enough, and what a dedicated client like Apollo brings, using React as the example UI layer.

GraphQL over HTTP Is Just POST

There is no magic transport. A GraphQL request is an HTTP POST with a JSON body containing query, optional variables, and optional operationName:

js
const res = await fetch("http://localhost:4000/", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ query: `query GetPost($id: ID!) { post(id: $id) { title author { name } } }`, variables: { id: "1" }, }), }); const { data, errors } = await res.json();

Two things to remember: the HTTP status is usually 200 even when errors is present, so always inspect the errors array; and auth is plain HTTP, typically an Authorization: Bearer header.

When Plain fetch Is Enough

For scripts, server-to-server calls, or an app with two queries, fetch is genuinely fine. Wrap it once:

js
async function gql(query, variables) { const res = await fetch(ENDPOINT, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ query, variables }), }); const { data, errors } = await res.json(); if (errors?.length) throw new Error(errors[0].message); return data; }

What fetch does not give you: caching, request deduplication, loading/error state management, and automatic UI updates after mutations. That is where client libraries earn their bundle size.

Apollo Client with React

bash
npm install @apollo/client graphql
jsx
import { ApolloClient, InMemoryCache, ApolloProvider, gql, useQuery } from "@apollo/client"; const client = new ApolloClient({ uri: "http://localhost:4000/", cache: new InMemoryCache() }); const GET_USERS = gql` query GetUsers { users { id name posts { id title } } } `; function UserList() { const { loading, error, data } = useQuery(GET_USERS); if (loading) return <p>Loading...</p>; if (error) return <p>Error: {error.message}</p>; return ( <ul> {data.users.map((u) => ( <li key={u.id}>{u.name} ({u.posts.length} posts)</li> ))} </ul> ); } export default function App() { return <ApolloProvider client={client}><UserList /></ApolloProvider>; }

useQuery handles the request lifecycle and subscribes the component to the cache: if another part of the app updates a user, this list re-renders automatically.

The Normalized Cache

InMemoryCache flattens responses into records keyed by __typename:id. A mutation that returns { id, name } for a user updates every query result containing that user, with no manual refetching. This is why lesson 8 insisted on selecting id in every fragment, and why mutations should return the entities they touch.

jsx
const [addPost] = useMutation(CREATE_POST); await addPost({ variables: { title: "Hi", authorId: "1" } });

Alternatives Worth Knowing

  • urql: lighter than Apollo, excellent defaults, extensible via exchanges.
  • Relay: Facebook’s client; strictest and most scalable, requires fragment colocation and a compiler.
  • graphql-request: a tiny typed wrapper when you only need fetch-plus-ergonomics.
  • TanStack Query + graphql-request: great when you want cache control without GraphQL-specific normalization.

Pair any of them with GraphQL Code Generator to derive TypeScript types from your operations; it eliminates an entire class of runtime bugs.

Key Takeaways

  • GraphQL over HTTP is a POST with query and variables; check the errors array, not the status code.
  • Plain fetch suits scripts and tiny apps; client libraries add caching, dedup, and state handling.
  • Apollo’s normalized cache keys objects by __typename:id and auto-updates every subscribed component.
  • Consider urql, Relay, or graphql-request depending on scale, and add codegen for end-to-end types.

Next lesson: Pagination, Errors and the N+1 Problem, the topics that separate demos from production APIs.

Consuming GraphQL from a Frontend - GraphQL | CodeYourCraft | CodeYourCraft