0
0
GraphqlHow-ToBeginner · 4 min read

How to Implement a Like System in GraphQL

To implement a like system in GraphQL, define a Like type and add mutations such as likeItem and unlikeItem. Use resolvers to update the database and return the updated like count or status.
📐

Syntax

The like system requires defining types and mutations in the GraphQL schema:

  • type Like: Represents a like with fields like id, userId, and itemId.
  • Mutation: Contains likeItem(itemId: ID!): Like and unlikeItem(itemId: ID!): Boolean to add or remove likes.
  • Query: Optionally, a query like likesCount(itemId: ID!): Int to get the number of likes.
graphql
type Like {
  id: ID!
  userId: ID!
  itemId: ID!
}

type Mutation {
  likeItem(itemId: ID!): Like
  unlikeItem(itemId: ID!): Boolean
}

type Query {
  likesCount(itemId: ID!): Int
}
💻

Example

This example shows a simple GraphQL server setup with a like system using an in-memory store. It demonstrates liking and unliking an item and querying the like count.

javascript
const { ApolloServer, gql } = require('apollo-server');

const typeDefs = gql`
  type Like {
    id: ID!
    userId: ID!
    itemId: ID!
  }

  type Mutation {
    likeItem(itemId: ID!): Like
    unlikeItem(itemId: ID!): Boolean
  }

  type Query {
    likesCount(itemId: ID!): Int
  }
`;

// In-memory likes store
const likes = [];
let likeIdCounter = 1;
const currentUserId = 'user1'; // Simulated logged-in user

const resolvers = {
  Mutation: {
    likeItem: (_, { itemId }) => {
      // Prevent duplicate likes by same user
      if (likes.find(like => like.userId === currentUserId && like.itemId === itemId)) {
        throw new Error('Already liked');
      }
      const newLike = { id: String(likeIdCounter++), userId: currentUserId, itemId };
      likes.push(newLike);
      return newLike;
    },
    unlikeItem: (_, { itemId }) => {
      const index = likes.findIndex(like => like.userId === currentUserId && like.itemId === itemId);
      if (index === -1) return false;
      likes.splice(index, 1);
      return true;
    }
  },
  Query: {
    likesCount: (_, { itemId }) => likes.filter(like => like.itemId === itemId).length
  }
};

const server = new ApolloServer({ typeDefs, resolvers });

server.listen().then(({ url }) => {
  console.log(`Server ready at ${url}`);
});
Output
Server ready at http://localhost:4000/
⚠️

Common Pitfalls

Common mistakes when implementing a like system in GraphQL include:

  • Not preventing duplicate likes from the same user on the same item.
  • Not handling unlike operations properly, which can cause errors or inconsistent data.
  • Failing to authenticate users, allowing anonymous likes.
  • Not updating or returning the current like count after mutations.
javascript
/* Wrong: Allows duplicate likes */
likeItem: (_, { itemId }) => {
  const newLike = { id: String(likeIdCounter++), userId: currentUserId, itemId };
  likes.push(newLike);
  return newLike;
}

/* Right: Checks for existing like before adding */
likeItem: (_, { itemId }) => {
  if (likes.find(like => like.userId === currentUserId && like.itemId === itemId)) {
    throw new Error('Already liked');
  }
  const newLike = { id: String(likeIdCounter++), userId: currentUserId, itemId };
  likes.push(newLike);
  return newLike;
}
📊

Quick Reference

  • Define Like type: Store user and item IDs.
  • Mutations: likeItem to add, unlikeItem to remove likes.
  • Queries: likesCount to get total likes.
  • Resolvers: Check duplicates, authenticate users, update data.

Key Takeaways

Define GraphQL types and mutations clearly for liking and unliking items.
Prevent duplicate likes by the same user on the same item in resolvers.
Always authenticate users to ensure valid like actions.
Return updated like counts or status after mutations for UI updates.
Test your like system to handle edge cases like unliking non-liked items.