Archived student lesson
Add Update mutations
Part of End to End React with Prisma 2
Objective: Make mutations which will allow us to update feeds and bundles.
Now that we can create feeds/bundles and search for them to our hearts content, we now need to support updating them. We will do this with 2 new mutations: updateFeed and updateBundle.
utils/api/resolvers.ts
import { verifyOwnership } from './verifyOwnership'
const resolvers = {
// other definitions
Mutation: {
// many other mutations
updateFeed: async (
parent,
{ data: { id, ...feedUpdate } },
{ prisma, user }
) => {
const feed = await prisma.feed.findOne({
where: { id },
include: { author: true },
})
await verifyOwnership(feed, user)
return prisma.feed.update({ where: { id }, data: { ...feedUpdate } })
},
updateBundle: async (
parent,
{ data: { id, ...bundleUpdate } },
{ prisma, user }
) => {
const bundle = await prisma.bundle.findOne({
where: { id },
include: { author: true },
})
await verifyOwnership(bundle, user)
return prisma.bundle.update({ where: { id }, data: { ...bundleUpdate } })
},
},
}
How these work is first we will look up the feed or bundle. We then will call this function verifyOwnership which will check whether the item’s user matches the current user. We only want a user to be able to mess around with their own items so in the event that someone made a nefarious API call to the backend where they tried to modify someone else’s item, we will kick them out of the mutation before any changes are made.
Create the following function which does the checking- note the throw new Error is what actually will kick us out of this resolver in the event that the users don’t match.
utils/api/verifyOwnership.ts
export const verifyOwnership = (item, user) => {
const { author } = item
if (author.auth0 !== user.auth0) {
throw new Error('Access denied, user does not own this item.')
}
}
Turning to the type definitions now, we will add the updateFeed and updateBundle to the mutations section and create a set of types centered around the FeedUpdateInput and BundleUpdateInput. Since these types have tags and feeds nested inside the update, we will also need to create types for those to allow us to create new tags/feeds, connect to already existing ones and disconnect from ones we don’t want associated with that particular item anymore.
utils/api/typeDefs.ts
input FeedUpdateInput {
id: String
url: String
name: String
tags: NestedFeedTagUpdateInput
}
input NestedFeedTagUpdateInput {
create: [FeedTagCreateInput]
connect: [FeedTagWhereUniqueInput]
disconnect: [FeedTagWhereUniqueInput]
}
input BundleUpdateInput {
id: String
name: String
description: String
tags: NestedBundleTagUpdateInput
feeds: NestedBundleFeedUpdateInput
}
input NestedBundleTagUpdateInput {
create: [BundleTagCreateInput]
connect: [BundleTagWhereUniqueInput]
disconnect: [BundleTagWhereUniqueInput]
}
input NestedBundleFeedUpdateInput {
create: [FeedCreateInput]
connect: [FeedWhereUniqueInput]
disconnect: [FeedWhereUniqueInput]
}
# other definitions
type Mutation {
# many other mutations
updateBundle(data: BundleUpdateInput): Bundle
updateFeed(data: FeedUpdateInput): Feed
}
We can verify that the updateBundle mutation works by running this mutation:
mutation updateBundleMutation($data: BundleUpdateInput) {
updateBundle(data: $data) {
...BundleFragment
feeds {
...FeedFragment
bundles {
...BundleFragment
}
}
}
}
fragment FeedFragment on Feed {
id
name
url
likes {
...AuthorFragment
}
tags {
...FeedTagFragment
}
author {
...AuthorFragment
}
}
fragment BundleFragment on Bundle {
id
name
description
tags {
...BundleTagFragment
}
author {
...AuthorFragment
}
likes {
...AuthorFragment
}
}
fragment AuthorFragment on User {
id
auth0
picture
nickname
}
fragment BundleTagFragment on BundleTag {
id
name
}
fragment FeedTagFragment on FeedTag {
id
name
}
with the following parameters:
{
"data": {
"id": "10",
"name": "Updated Bundle Title"
}
}
We should see that the name of the bundle has now been updated. You can also run this on the updateFeed mutation and confirm that it updates there too.