Experiment 4
Create Expt 4 folder.
Inside it create 2 folder 1. Graphql and 2. Models
Open folder in VS and run following commands
1. Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
2. npm init
3. npm install cors dotenv express express-graphql graphql mongoose
Create files in the following hierarchy and paste the contents
Run - node [Link]
Open : [Link]
models/[Link]
const mongoose = require('mongoose');
const TaskSchema = new [Link]({
title: { type: String, required: true, trim: true },
description: { type: String, default: '' },
status: {
type: String,
enum: ['TODO', 'IN_PROGRESS', 'DONE'],
default: 'TODO'
},
dueDate: { type: Date },
}, { timestamps: true });
[Link] = [Link]('Task', TaskSchema);
graphql/[Link]
// graphql/[Link]
const {
GraphQLObjectType,
GraphQLString,
GraphQLID,
GraphQLSchema,
GraphQLList,
GraphQLNonNull,
GraphQLEnumType,
GraphQLInputObjectType,
GraphQLBoolean,
} = require('graphql');
const Task = require('../models/Task');
// Task GraphQL Type
const TaskType = new GraphQLObjectType({
name: 'Task',
fields: () => ({
id: { type: GraphQLID },
title: { type: GraphQLString },
description: { type: GraphQLString },
status: { type: GraphQLString },
dueDate: { type: GraphQLString }, // ISO date string
createdAt: { type: GraphQLString },
updatedAt: { type: GraphQLString }
})
});
// Input type for creating/updating
const TaskInput = new GraphQLInputObjectType({
name: 'TaskInput',
fields: {
title: { type: new GraphQLNonNull(GraphQLString) },
description: { type: GraphQLString },
status: { type: GraphQLString },
dueDate: { type: GraphQLString }
}
});
// Root Query
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
task: {
type: TaskType,
args: { id: { type: GraphQLID } },
resolve: async (_, { id }) => {
return await [Link](id);
}
},
tasks: {
type: new GraphQLList(TaskType),
args: {
status: { type: GraphQLString }, // optional filter
search: { type: GraphQLString } // search in title/description
},
resolve: async (_, { status, search }) => {
const filter = {};
if (status) [Link] = status;
if (search) {
filter.$or = [
{ title: { $regex: search, $options: 'i' } },
{ description: { $regex: search, $options: 'i' } }
];
}
return await [Link](filter).sort({ createdAt: -1 });
}
}
}
});
// Mutations
const Mutation = new GraphQLObjectType({
name: 'Mutation',
fields: {
createTask: {
type: TaskType,
args: {
input: { type: new GraphQLNonNull(TaskInput) }
},
resolve: async (_, { input }) => {
const task = new Task({
title: [Link],
description: [Link] || '',
status: [Link] || 'TODO',
dueDate: [Link] ? new Date([Link]) : undefined
});
return await [Link]();
}
},
updateTask: {
type: TaskType,
args: {
id: { type: new GraphQLNonNull(GraphQLID) },
input: { type: new GraphQLNonNull(TaskInput) }
},
resolve: async (_, { id, input }) => {
const updated = await [Link](
id,
{
$set: {
title: [Link],
description: [Link] || '',
status: [Link] || 'TODO',
dueDate: [Link] ? new Date([Link]) : undefined
}
},
{ new: true, runValidators: true }
);
return updated;
}
},
patchTaskStatus: {
// small mutation to only change status
type: TaskType,
args: {
id: { type: new GraphQLNonNull(GraphQLID) },
status: { type: new GraphQLNonNull(GraphQLString) }
},
resolve: async (_, { id, status }) => {
const valid = ['TODO','IN_PROGRESS','DONE'];
if () throw new Error('Invalid status');
return await [Link](id, { status }, { new: true });
}
},
deleteTask: {
type: GraphQLBoolean,
args: { id: { type: new GraphQLNonNull(GraphQLID) } },
resolve: async (_, { id }) => {
const res = await [Link](id);
return !!res;
}
}
}
});
[Link] = new GraphQLSchema({
query: RootQuery,
mutation: Mutation
});
[Link]
// [Link]
require('dotenv').config();
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const { graphqlHTTP } = require('express-graphql');
const schema = require('./graphql/schema');
const app = express();
[Link](cors());
[Link]([Link]());
const PORT = [Link] || 4000;
const MONGODB_URI = [Link].MONGODB_URI || 'mongodb://localhost:27017/taskdb';
// Connect to MongoDB
[Link](MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => [Link]('✅ Connected to MongoDB'))
.catch(err => {
[Link]('❌ MongoDB connection error:', err);
[Link](1);
});
// GraphQL endpoint
[Link]('/graphql', graphqlHTTP({
schema,
graphiql: true // enable GraphiQL in dev
}));
[Link]('/', (_, res) => [Link]('Task Manager GraphQL API is running. Visit /graphql'));
// Start server
[Link](PORT, () => {
[Link](`🚀 Server ready at [Link]
});
To Run: node [Link]
Open : [Link]
GraphQL Operations: Paste it , only one query at time and click Run button
Create Task:
mutation {
createTask(input: {
title: "Finish GraphQL API",
description: "Write server, schema and resolvers",
status: "IN_PROGRESS",
dueDate: "2025-09-30T[Link].000Z"
}) {
id
title
status
dueDate
createdAt
}
}
List tasks:
query {
tasks {
id
title
status
description
dueDate
createdAt
}
}
Get single task:
query {
task(id: "PUT_TASK_ID_HERE") {
id
title
status
}
}
Update task (full replace of fields in TaskInput):
mutation {
updateTask(id: "PUT_ID", input:{
title:"Updated title",
description:"Updated desc",
status:"DONE",
dueDate:"2025-10-01T[Link].000Z"
}) {
id
title
status
updatedAt
}
}
Patch status (quick status update):
mutation {
patchTaskStatus(id:"PUT_ID", status:"DONE") {
id
title
status
}
}
Delete task:
mutation {
deleteTask(id: "PUT_ID")
}
Task for students:
Include additional attributes:
1. priority – (LOW, MEDIUM, HIGH, CRITICAL)
2. tags – array of strings (e.g., ["work", "urgent"])
3. category – string (e.g., "Bug", "Feature", "Improvement")
4. estimatedHours – number (e.g., 5.5)
5. actualHours – number (e.g., 6.0)
6. progress – percentage number (0–100)
7. attachments – array of file URLs
8. createdBy – user ID or name
9. assignedTo – user ID or name
10. reviewer – user ID or name (for approvals)
11. team – string or array (e.g., "Backend Team")
12. createdAt – auto timestamp (already in schema, but keep it)
13. updatedAt – auto timestamp (already in schema)
14. completedAt – timestamp when task is marked DONE
15. isRecurring – boolean (true if repeating task)
16. recurrencePattern – string (e.g., "DAILY", "WEEKLY")
17. dependencies – array of task IDs that must be finished first
18. subTasks – array of subtask IDs
19. comments – array of comment objects { user, text, date }
20. historyLog – array of updates with { field, oldValue, newValue, updatedBy,
updatedAt }