The last time was search by id form the task list. This time, I am going to update the list. It's called Mutation
, which is a cool name in the GraphQL community :D
Code
const { ApolloServer, gql } = require('apollo-server');
const typeDefs = gql`
type Task {
id: ID!
name: String!
isActive: Boolean!
createdAt: Int
updatedAt: Int
owner: String
}
type Query {
tasks: [Task]
task(id: ID!): Task
}
# ❶
type Mutation {
addTask(name: String!): [Task]
completeTask(id: ID!): [Task]
deleteTask(id: ID!): [Task]
}
`;
const tasks = [
{ id: 1, name: "Soak in an Onsen", isActive: true },
{ id: 2, name: "Sing Karaoke", isActive: false },
{ id: 3, name: "See cherry blossom", isActive: true },
]
// ❷
const newId = () => { return Math.max(...tasks.map((t) => t.id)) + 1 }
const resolvers = {
Query: {
tasks: () => tasks,
task (parent, args, context, info) {
const { id } = args;
return context.db.find((task) => task.id == id)
}
},
// ❸
Mutation: {
addTask: async (parent, args, context) => {
context.db.push({
id: newId(),
...args,
isActive: true,
createdAt: Math.floor(Date.now()/1000),
updatedAt: Math.floor(Date.now()/1000)
})
return context.db
},
completeTask: async (parent, args, context) => {
const targetTask = context.db.find(t => t.id == args.id)
if (!targetTask) {
throw new Error("No such task")
} else {
const idx = context.db.indexOf(targetTask)
context.db[idx].isActive = !context.db[idx].isActive;
context.db[idx].updatedAt = Math.floor(Date.now()/1000);
return context.db
}
},
deleteTask: async (parent, task, context) => {
const targetTask = context.db.find(t => t.id == task.id)
if (!targetTask) {
throw new Error("No such task")
} else {
const idx = context.db.indexOf(targetTask)
context.db.splice(idx, 1);
return context.db
}
}
}
};
const server = new ApolloServer({
typeDefs,
resolvers,
context: { db: tasks }
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
Updates from last time is as follows:
- Define the
Types
of the Mutationの型. I made all types as[Task]
so that all of them retuns array of tasks. - Function which generates an ID - not a good idea to scan the whole task array ids but it shold be OK for this kinda quick PoC.
Resolver
function which corresponds to theType
of ❶
That's it. I think I'm starting to understand the cycle of adding features. Add Type
frist, then add Resolver
as either inQuery
or Mutaion
section which corresponding to the Type
I repeated that cycle for addTask()
, completeTask()
, deleteTask()
Use the mutations
Now you can do a full range of CRUD processing. Let's make request from your client. The sample requests are:
# Write your query or mutation here
mutation add {
addTask(name: "Buy some milk") {
id
name
}
}
mutation delete {
deleteTask(id: 5) {
id
name
}
}
query list {
tasks {
id
name
isActive
createdAt
updatedAt
owner
}
}
mutation done {
completeTask(id: 4) {
id
name
isActive
}
}
You should be able to resolve these queries with you GraphQL Playground at https://localhost:4000
. Well, that was easier than I thought it would be :D
Next step
Now that we have a complete set of CRUD functions as TODO, next time I would like to modify the this Svelte frontend (REST version) that I wrote before and connect it to the GraphQL backend.