Getting Started with GraphQL and React

Introduction If you've worked with traditional REST APIs, you've probably run into some frustrating limitations. Maybe you needed just a user's name and email, but the API sent back their entire profile data. Or perhaps you needed data from multiple endpoints, forcing you to make several requests just to populate a single page. These are exactly the kinds of problems GraphQL was designed to solve. Created by Facebook engineers who faced these same challenges at scale, GraphQL has transformed how modern web applications handle data fetching. In this blog, I'll walk you through the basics of GraphQL by building a simple React app that fetches user info using Apollo Client. What is GraphQL? At its heart, GraphQL is a query language for your API. Think of it as a more precise way to ask your server for exactly what you need. Unlike REST, where the server dictates what data you get from each endpoint. Imagine walking into a restaurant where instead of ordering from a fixed menu, you can tell the chef exactly what ingredients you want in your meal. That's GraphQL—you specify precisely what fields you need, and the server returns just those fields. No more, no less. Why Developers Are Switching to GraphQL But after using it in several projects, I'm convinced it solves real problems: One endpoint to rule them all: Instead of remembering dozens of REST endpoints, you interact with a single GraphQL endpoint for all your data needs. No more data bloat: You ask for exactly what you need. If you only want a user's name, you only get their name—saving bandwidth and improving performance. Self-documenting APIs: GraphQL APIs come with built-in type systems and introspection, so you can discover what queries are possible without leaving your development environment. Developer tools that actually help: The ecosystem includes amazing tools like GraphQL Playground and Apollo DevTools that make debugging and exploring APIs surprisingly pleasant. Setting Up Our Project We'll create a simple app that pulls user data from a public GraphQL API. First, let's set up a React project with vite, which gives us a lightning-fast development experience: npm create vite@latest graphql-demo -- --template react-ts cd graphql-demo npm install Next, we need to install Apollo Client and GraphQL: npm install @apollo/client graphql Apollo Client does much more than just send GraphQL requests—it provides a complete data management solution with intelligent caching, optimistic UI updates, and integration with React's component lifecycle. Finding a GraphQL API to Play With For this tutorial, we'll use GraphQL Zero, a free online GraphQL API that mimics typical data you might encounter in production. It's perfect for learning because it requires no authentication and provides realistic data structures. Here's a sample of what we can query: { user(id: 1) { id name email } } This asks for a user with ID 1, and specifically requests their id, name, and email fields—nothing more. Building Our App with Apollo Client Step 1: Setting Up the Apollo Provider First, we need to configure Apollo Client and wrap our application with the ApolloProvider. This makes the GraphQL client available throughout our component tree: import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App.tsx"; import { ApolloClient, InMemoryCache, ApolloProvider } from "@apollo/client"; // Create our Apollo Client instance const client = new ApolloClient({ uri: "https://graphqlzero.almansi.me/api", // The GraphQL endpoint cache: new InMemoryCache(), // Apollo's caching system }); // Wrap our App with the Apollo Provider ReactDOM.createRoot(document.getElementById("root")!).render( ); The InMemoryCache is one of Apollo's most powerful features. It automatically stores query results and helps avoid unnecessary network requests when you request the same data again. Step 2: Defining Our GraphQL Query Next, let's create a dedicated file for our GraphQL queries. This helps keep our code organized as our application grows: // src/graphql/queries.ts import { gql } from "@apollo/client"; export const GET_USER = gql` query GetUser($id: ID!) { user(id: $id) { id name email } } `; The gql tag parses our GraphQL query string into the format Apollo needs. The $id parameter lets us dynamically specify which user to fetch. Step 3: Using the Query in Our Component Now for the fun part—let's update our App component to fetch and display the user data: // src/App.tsx import { useQuery } from "@apollo/client"; import { GET_USER } from "./graphql/queries"; // TypeScript interface for our user data interface User { id: string; name: string; email: string; } function App() { // The useQuery hook handles the entire request lifecycle co

Apr 6, 2025 - 06:23
 0
Getting Started with GraphQL and React

Introduction

If you've worked with traditional REST APIs, you've probably run into some frustrating limitations. Maybe you needed just a user's name and email, but the API sent back their entire profile data. Or perhaps you needed data from multiple endpoints, forcing you to make several requests just to populate a single page.

These are exactly the kinds of problems GraphQL was designed to solve. Created by Facebook engineers who faced these same challenges at scale, GraphQL has transformed how modern web applications handle data fetching.

In this blog, I'll walk you through the basics of GraphQL by building a simple React app that fetches user info using Apollo Client.

What is GraphQL?

At its heart, GraphQL is a query language for your API. Think of it as a more precise way to ask your server for exactly what you need. Unlike REST, where the server dictates what data you get from each endpoint.

Imagine walking into a restaurant where instead of ordering from a fixed menu, you can tell the chef exactly what ingredients you want in your meal. That's GraphQL—you specify precisely what fields you need, and the server returns just those fields. No more, no less.

Why Developers Are Switching to GraphQL

But after using it in several projects, I'm convinced it solves real problems:

  • One endpoint to rule them all: Instead of remembering dozens of REST endpoints, you interact with a single GraphQL endpoint for all your data needs.

  • No more data bloat: You ask for exactly what you need. If you only want a user's name, you only get their name—saving bandwidth and improving performance.

  • Self-documenting APIs: GraphQL APIs come with built-in type systems and introspection, so you can discover what queries are possible without leaving your development environment.

  • Developer tools that actually help: The ecosystem includes amazing tools like GraphQL Playground and Apollo DevTools that make debugging and exploring APIs surprisingly pleasant.

Setting Up Our Project

We'll create a simple app that pulls user data from a public GraphQL API.

First, let's set up a React project with vite, which gives us a lightning-fast development experience:

npm create vite@latest graphql-demo -- --template react-ts
cd graphql-demo
npm install

Next, we need to install Apollo Client and GraphQL:

npm install @apollo/client graphql

Apollo Client does much more than just send GraphQL requests—it provides a complete data management solution with intelligent caching, optimistic UI updates, and integration with React's component lifecycle.

Finding a GraphQL API to Play With

For this tutorial, we'll use GraphQL Zero, a free online GraphQL API that mimics typical data you might encounter in production. It's perfect for learning because it requires no authentication and provides realistic data structures.

Here's a sample of what we can query:

{
  user(id: 1) {
    id
    name
    email
  }
}

This asks for a user with ID 1, and specifically requests their id, name, and email fields—nothing more.

Building Our App with Apollo Client

Step 1: Setting Up the Apollo Provider

First, we need to configure Apollo Client and wrap our application with the ApolloProvider. This makes the GraphQL client available throughout our component tree:

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import { ApolloClient, InMemoryCache, ApolloProvider } from "@apollo/client";

// Create our Apollo Client instance
const client = new ApolloClient({
  uri: "https://graphqlzero.almansi.me/api", // The GraphQL endpoint
  cache: new InMemoryCache(), // Apollo's caching system
});

// Wrap our App with the Apollo Provider
ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <ApolloProvider client={client}>
      <App />
    ApolloProvider>
  React.StrictMode>
);

The InMemoryCache is one of Apollo's most powerful features. It automatically stores query results and helps avoid unnecessary network requests when you request the same data again.

Step 2: Defining Our GraphQL Query

Next, let's create a dedicated file for our GraphQL queries. This helps keep our code organized as our application grows:

// src/graphql/queries.ts
import { gql } from "@apollo/client";

export const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

The gql tag parses our GraphQL query string into the format Apollo needs. The $id parameter lets us dynamically specify which user to fetch.

Step 3: Using the Query in Our Component

Now for the fun part—let's update our App component to fetch and display the user data:

// src/App.tsx
import { useQuery } from "@apollo/client";
import { GET_USER } from "./graphql/queries";

// TypeScript interface for our user data
interface User {
  id: string;
  name: string;
  email: string;
}

function App() {
  // The useQuery hook handles the entire request lifecycle
  const { loading, error, data } = useQuery<{ user: User }>(GET_USER, {
    variables: { id: 1 }, // Pass our query variables
  });

  // Handle loading state
  if (loading) return <p>Loading...p>;

  // Handle errors
  if (error) return <p>Error fetching user: {error.message}p>;

  const user = data?.user;

  // Handle case where no user was found
  if (!user) return <p>No user found.p>;

  // Render the user data
  return (
    <div style={{ padding: "2rem" }}>
      <h1>