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 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

    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

    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:

    graphql

    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:

    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.