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.


    10. Add LikeBundle and LikeFeed Mutations

    Objective: Create mutations to allow us to like bundles and feeds.

    Now that we have a way to create feeds and bundles, let's figure out how we can like them. This will show up on the UI as a heart button that when we click it, it will turn red and the like count will increment by one. Similarly, clicking it again will unlike the item and decrease the like count by one. We'll represent this by adding a new field called likes on our feed and bundle objects. Liking something will call the prisma connect function to connect the user's object to that feed or bundle. Unliking something will call the prisma disconnect function.

    Let's start by adding the typeDefs. Modify the typeDefs to add likeBundle and likeFeed to the mutations section.

    utils/api/typeDefs.ts

    ts

    type Feed {
    id: String
    name: String
    url: String
    author: User
    tags: [FeedTag]
    bundles: [Bundle]
    likes: [User]
    }
    type Bundle {
    id: String
    name: String
    description: String
    author: User
    tags: [BundleTag]
    feeds: [Feed]
    likes: [User]
    }
    type User {
    id: String
    auth0: String
    nickname: String
    picture: String
    bundles: [Bundle]
    feeds: [Feed]
    feedLikes: [Feed]
    bundleLikes: [Bundle]
    }
    # more defs below...
    input LikeBundleInput {
    bundleId: String
    likeState: Boolean
    }
    input LikeFeedInput {
    feedId: String
    likeState: Boolean
    }
    # more definitions below
    type Mutation {
    clearAll: String
    createFeed(data: FeedCreateInput): Feed
    createBundle(data: BundleCreateInput): Bundle
    likeBundle(data: LikeBundleInput): Bundle
    likeFeed(data: LikeFeedInput): Feed
    }

    The two mutations will take the id of the bundle or feed that we want to like and a likeState boolean which is the desired state that it should be- that is if we want to like an item, we pass a likeState: true and if we want to unlike something we pass a likeState: false. Having this flexibility to both like and unlike something with the same mutation allows us to make the most out of our mutations.

    Turning to our resolvers, we first call createFieldResolver for the two new likes fields that we added to the Feed and Bundle models. Then, we can create our two likeBundle and likeFeed resolvers. These will specify a connect state which allows us to either connect or disconnect the current user to the bundle or feed specified with either feedId or bundleId. Since the item already exists, we will be calling update rather than create or findOne/findMany that we've used before. The update function still takes the data block that we've used in the create but it also has a new where block that allows us to specify the id of the item that we are trying to update.

    utils/api/resolvers.ts

    ts

    const resolvers = {
    Feed: {
    ...createFieldResolver('feed', 'author'),
    ...createFieldResolver('feed', 'bundles'),
    ...createFieldResolver('feed', 'likes'),
    ...createFieldResolver('feed', 'tags'),
    },
    Bundle: {
    ...createFieldResolver('bundle', 'author'),
    ...createFieldResolver('bundle', 'feeds'),
    ...createFieldResolver('bundle', 'likes'),
    ...createFieldResolver('bundle', 'tags'),
    },
    // more resolvers above
    likeBundle: (parent, { data }, { prisma, user }) => {
    const { bundleId, likeState } = data
    const connectState = likeState ? 'connect' : 'disconnect'
    return prisma.bundle.update({
    where: { id: bundleId },
    data: { likes: { [connectState]: { id: user.id } } },
    })
    },
    likeFeed: (parent, { data }, { prisma, user }) => {
    const { feedId, likeState } = data
    const connectState = likeState ? 'connect' : 'disconnect'
    return prisma.feed.update({
    where: { id: feedId },
    data: { likes: { [connectState]: { id: user.id } } },
    })
    },
    // more resolvers below
    }

    Let's now make sure the mutations work. Let's first try liking the bundle that we created:

    graphql

    mutation likeBundleMutation($data: LikeBundleInput) {
    likeBundle(data: $data) {
    ...BundleFragment
    feeds {
    ...FeedFragment
    }
    }
    }
    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
    }

    json

    {
    "data": {
    "bundleId": "10",
    "likeState": true
    }
    }

    Make sure that the bundleId equals the id that you used when you created your bundle. If you forget, you can always run a bundles query and see what Ids come back and then like one of those. What you should see in the return is a field called likes that has an array with a single user which is the one that we are hard-coding.

    From the mutation we just sent above, leave the fragments but swap likeBundleMutation for this likeFeedMutation:

    graphql

    mutation likeFeedMutation($data: LikeFeedInput) {
    likeFeed(data: $data) {
    ...FeedFragment
    bundles {
    ...BundleFragment
    }
    }
    }

    then, issue the following variables along with the request:

    json

    {
    "data": {
    "feedId": "1",
    "likeState": true
    }
    }

    We should also see that this request comes back successfully and that this feed now has 1 like on it.