Have you ever wondered how to build a full-stack app using GraphQL instead of REST? In this tutorial, we’ll walk through how to create a simple ToDo app using React and GraphQL with Apollo.
🎯 By the end, you’ll have a working app where you can view, add, and toggle tasks — powered by a GraphQL API.
Step 1: Set Up the GraphQL Server (Backend)
mkdir graphql-server
cd graphql-server
npm init -y
npm install apollo-server graphql
Create index.js for the backend
const { ApolloServer, gql } = require('apollo-server');
const typeDefs = gql`
type Todo {
id: ID!
title: String!
completed: Boolean!
}
type Query {
todos: [Todo]
}
type Mutation {
addTodo(title: String!): Todo
toggleTodo(id: ID!): Todo
}
`;
let todos = [
{ id: "1", title: "Learn GraphQL", completed: false },
{ id: "2", title: "Build a ToDo App", completed: false },
];
const resolvers = {
Query: {
todos: () => todos,
},
Mutation: {
addTodo: (_, { title }) => {
const newTodo = { id: Date.now().toString(), title, completed: false };
todos.push(newTodo);
return newTodo;
},
toggleTodo: (_, { id }) => {
const todo = todos.find(t => t.id === id);
todo.completed = !todo.completed;
return todo;
},
},
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
Step 2: Set Up the React App (Frontend)
npx create-react-app graphql-todo
cd graphql-todo
npm install @apollo/client graphql
in src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:4000',
cache: new InMemoryCache(),
});
ReactDOM.render(
,
document.getElementById('root')
);
in src/App.js
import React, { useState } from 'react';
import { useQuery, useMutation, gql } from '@apollo/client';
const GET_TODOS = gql`
query {
todos {
id
title
completed
}
}
`;
const ADD_TODO = gql`
mutation($title: String!) {
addTodo(title: $title) {
id
title
completed
}
}
`;
const TOGGLE_TODO = gql`
mutation($id: ID!) {
toggleTodo(id: $id) {
id
completed
}
}
`;
function App() {
const { data, loading } = useQuery(GET_TODOS);
const [addTodo] = useMutation(ADD_TODO, {
refetchQueries: [{ query: GET_TODOS }],
});
const [toggleTodo] = useMutation(TOGGLE_TODO);
const [input, setInput] = useState('');
if (loading) return Loading...;
const handleAdd = () => {
if (input.trim()) {
addTodo({ variables: { title: input } });
setInput('');
}
};
return (
📝 GraphQL ToDo List
setInput(e.target.value)} placeholder="New task" />
Add
{data.todos.map(todo => (
toggleTodo({ variables: { id: todo.id } })}>
{todo.title}
))}
);
}
export default App;
Step 3 : Start the app
in backend
node index.js
in frontend
npm start
🚀 You Did It!
You now have a working React app powered by GraphQL. You can:
- View todos
- Add a new task
- Toggle them done/undone
What's Next?
- Add delete functionality
- Store data in MongoDB or PostgreSQL
- Deploy to Vercel or Netlify