End to End React with Prisma 2
Start at the beginning and work your way through this project. The code for each step as well as the finished project can be found in the Github repository.
12. Add Update mutations
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
ts
import { verifyOwnership } from './verifyOwnership'const resolvers = {// other definitionsMutation: {// many other mutationsupdateFeed: 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
ts
export const verifyOwnership = (item, user) => {const { author } = itemif (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
ts
input FeedUpdateInput {id: Stringurl: Stringname: Stringtags: NestedFeedTagUpdateInput}input NestedFeedTagUpdateInput {create: [FeedTagCreateInput]connect: [FeedTagWhereUniqueInput]disconnect: [FeedTagWhereUniqueInput]}input BundleUpdateInput {id: Stringname: Stringdescription: Stringtags: NestedBundleTagUpdateInputfeeds: NestedBundleFeedUpdateInput}input NestedBundleTagUpdateInput {create: [BundleTagCreateInput]connect: [BundleTagWhereUniqueInput]disconnect: [BundleTagWhereUniqueInput]}input NestedBundleFeedUpdateInput {create: [FeedCreateInput]connect: [FeedWhereUniqueInput]disconnect: [FeedWhereUniqueInput]}# other definitionstype Mutation {# many other mutationsupdateBundle(data: BundleUpdateInput): BundleupdateFeed(data: FeedUpdateInput): Feed}
We can verify that the updateBundle
mutation works by running this mutation:
graphql
mutation updateBundleMutation($data: BundleUpdateInput) {updateBundle(data: $data) {...BundleFragmentfeeds {...FeedFragmentbundles {...BundleFragment}}}}fragment FeedFragment on Feed {idnameurllikes {...AuthorFragment}tags {...FeedTagFragment}author {...AuthorFragment}}fragment BundleFragment on Bundle {idnamedescriptiontags {...BundleTagFragment}author {...AuthorFragment}likes {...AuthorFragment}}fragment AuthorFragment on User {idauth0picturenickname}fragment BundleTagFragment on BundleTag {idname}fragment FeedTagFragment on FeedTag {idname}
with the following parameters:
json
{"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.