Task Manager App using Express, React and GraphQL.
The Task Manager app tool is designed to simplify task management with CRUD operation: creation, deletion, and modification of tasks. Users can easily generate new tasks, remove completed ones, and update task details. In this step-by-step tutorial, you will learn the process of building a Basic Task Manager App with Express, React and GraphQL.
Preview of final output: Let us have a look at how the final application will look like.
Prerequisites
Approach to create Task Manager App:
- Creating a Task Manager application involves using React for the front end and Express with GraphQL for the back end.
- The front end is built with React, a JavaScript library for building user interfaces, and utilizes Apollo Client for state management.
- Apollo Client is employed for handling data fetching and mutations through GraphQL queries in the front end.
- Communication between the front end and back end occurs via Express, a Node.js framework, with express-graphql middleware managing GraphQL queries.
- The backend defines a GraphQL schema with queries and mutations specifically designed for tasks.
- Task management is handled in memory on the server side, utilizing GraphQL's capabilities for querying, creating, updating, and deleting tasks.
- Apollo Client's useQuery and useMutation hooks facilitate interaction between the frontend and backend, fetching tasks and updating the UI dynamically.
- The application follows a client-server architecture, where React interacts with Express through GraphQL for CRUD operations on tasks.
Steps to create Application and install dependencies
Step 1: Create a new directory for your project and navigate it to the terminal using the following commands
mkdir task-manager-app
cd task-manager-app
Step 2: Create a new React app using Create React App.
npx create-react-app client
cd client
Step 3: Install the required dependencies.
npm install @apollo/client graphql
Project Structure:

The updated dependencies in package.json file will look like :
Frontend Dependencies:
"dependencies":{
"react":"18.2.0",
"@apollo/client": "3.8.8",
"@apollo/react-hooks": "4.0.0",
"react-dom": "18.2.0",
"graphql": "16.8.11"
}
Backend Dependencies
"dependencies": {
"express": "4.18.2",
"express-graphql": "0.12.0",
"graphql": "15.8.0",
"cors": "2.8.5",
"apollo-server-express": "3.13.0"
}
Example: Add the following code in client/src/App.js
/*App.css*/
body {
font-family: "Roboto", sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
.container {
width: 80%;
padding: 20px;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 8px;
}
h1 {
font-family: "Open Sans", sans-serif;
color: #037f07;
margin-bottom: 10px;
text-align: center;
}
h3 {
font-family: "Arial", sans-serif;
color: #333;
margin-bottom: 20px;
text-align: center;
font-size: 20px;
}
form {
margin-bottom: 20px;
}
input {
padding: 10px;
margin-right: 10px;
width: 200px;
}
button {
padding: 10px 16px;
background-color: #4caf50;
color: white;
border: none;
cursor: pointer;
}
ul {
list-style-type: none;
padding: 0;
}
li {
margin-bottom: 20px;
padding: 20px;
border: 1px solid #ddd;
background-color: #f9f9f9;
border-radius: 8px;
display: flex;
justify-content: space-between;
align-items: center;
}
button.delete {
background-color: #e74c3c;
}
button.update {
background-color: #3498db;
margin-right: 5px;
}
//App.js
import React, { useState } from "react";
import {
useQuery,
useMutation,
gql,
ApolloProvider,
ApolloClient,
InMemoryCache,
} from "@apollo/client";
import "./App.css";
const GET_TASKS = gql`
query {
tasks {
id
title
description
}
}
`;
const CREATE_TASK = gql`
mutation CreateTask($title: String!, $description: String!) {
createTask(title: $title, description: $description) {
id
title
description
}
}
`;
const DELETE_TASK = gql`
mutation DeleteTask($id: ID!) {
deleteTask(id: $id)
}
`;
const UPDATE_TASK = gql`
mutation UpdateTask($id: ID!, $title: String, $description: String) {
updateTask(id: $id, title: $title, description: $description) {
id
title
description
}
}
`;
function App() {
const { loading, error, data } = useQuery(GET_TASKS);
const [createTask] = useMutation(CREATE_TASK);
const [deleteTask] = useMutation(DELETE_TASK);
const [updateTask] = useMutation(UPDATE_TASK);
const [newTask, setNewTask] = useState({ title: "", description: "" });
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
const handleCreateTask = () => {
createTask({
variables: newTask,
refetchQueries: [{ query: GET_TASKS }],
});
setNewTask({ title: "", description: "" });
};
const handleDeleteTask = (id) => {
deleteTask({
variables: { id },
refetchQueries: [{ query: GET_TASKS }],
});
};
const handleUpdateTask = (id, title, description) => {
updateTask({
variables: { id, title, description },
refetchQueries: [{ query: GET_TASKS }],
});
};
return (
<div>
<h1>GeeksforGeeks</h1>
<h3>Task Manager</h3>
<div>
<h2>Create Task</h2>
<input
type="text"
placeholder="Title"
value={newTask.title}
onChange={(e) =>
setNewTask({ ...newTask, title: e.target.value })
}
/>
<input
type="text"
placeholder="Description"
value={newTask.description}
onChange={(e) =>
setNewTask({ ...newTask, description: e.target.value })
}
/>
<button onClick={handleCreateTask}>Create</button>
</div>
<div>
<h2>Tasks</h2>
<ul>
{data.tasks.map((task) => (
<li key={task.id}>
{task.title} - {task.description}
<button onClick={() => handleDeleteTask(task.id)}>
Delete
</button>
<button
onClick={() => {
const updatedTitle = prompt(
"Enter new title:",
task.title
);
const updatedDescription = prompt(
"Enter new description:",
task.description
);
handleUpdateTask(
task.id,
updatedTitle,
updatedDescription
);
}}
>
Update
</button>
</li>
))}
</ul>
</div>
</div>
);
}
const client = new ApolloClient({
uri: "http://localhost:3001/graphql",
cache: new InMemoryCache(),
});
function ApolloApp() {
return (
<ApolloProvider client={client}>
<App />
</ApolloProvider>
);
}
export default ApolloApp;
Now the Frontend of the app is ready and we are moving forward to the backand of the app.
Step 4: In the main project directory, create a new file named server.js for the Express server.
npm init -y
touch server.js
Step 5: Install the required dependencies for Express and GraphQL using below command :
npm install express express-graphql graphql cors
Example: Now, copy and paste the following code into server.js:
//server.js
const express = require("express");
const { graphqlHTTP } = require("express-graphql");
const { buildSchema } = require("graphql");
const cors = require("cors");
let tasks = [];
const schema = buildSchema(`
type Task {
id: ID!
title: String!
description: String!
}
type Query {
tasks: [Task]
}
type Mutation {
createTask(title: String!, description: String!): Task
deleteTask(id: ID!): Boolean
updateTask(id: ID!, title: String, description: String): Task
}
`);
const root = {
tasks: () => tasks,
createTask: ({ title, description }) => {
const newTask = { id: tasks.length + 1, title, description };
tasks.push(newTask);
return newTask;
},
deleteTask: ({ id }) => {
tasks = tasks.filter((task) => task.id !== parseInt(id));
return true;
},
updateTask: ({ id, title, description }) => {
const taskIndex = tasks.findIndex((task) => task.id === parseInt(id));
if (taskIndex !== -1) {
tasks[taskIndex] = { ...tasks[taskIndex], title, description };
return tasks[taskIndex];
}
return null;
},
};
const app = express();
app.use(cors());
app.use("/graphql", graphqlHTTP({ schema, rootValue: root, graphiql: true }));
const port = 3001;
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}/graphql`);
});
Step 6: Run and Test the App
Backend:
node server.js
Frontend:
cd client
npm start