Archived student lesson

Add LikeBundle and LikeFeed Mutations

Part of End to End React with Prisma 2

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

  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

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:

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
}
{
  "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:

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

then, issue the following variables along with the request:

{
  "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.