⚙️ Backend

GraphQL API Development

Last updated: 2025-09-25 02:29:54

GraphQL Query Language

GraphQL provides a more efficient, powerful and flexible alternative to REST APIs.

GraphQL Schema Definition

const { gql } = require('apollo-server-express');

// Schema definition
const typeDefs = gql`
  type User {
    id: ID!
    name: String!
    email: String!
    posts: [Post!]!
    createdAt: String!
  }
  
  type Post {
    id: ID!
    title: String!
    content: String!
    author: User!
    comments: [Comment!]!
    publishedAt: String
  }
  
  type Comment {
    id: ID!
    content: String!
    author: User!
    post: Post!
  }
  
  type Query {
    users: [User!]!
    user(id: ID!): User
    posts: [Post!]!
    post(id: ID!): Post
  }
  
  type Mutation {
    createUser(input: CreateUserInput!): User!
    createPost(input: CreatePostInput!): Post!
    updatePost(id: ID!, input: UpdatePostInput!): Post!
    deletePost(id: ID!): Boolean!
  }
  
  input CreateUserInput {
    name: String!
    email: String!
  }
  
  input CreatePostInput {
    title: String!
    content: String!
    authorId: ID!
  }
  
  input UpdatePostInput {
    title: String
    content: String
  }
`;

Resolvers Implementation

// Resolvers
const resolvers = {
  Query: {
    users: async () => {
      return await User.findAll();
    },
    
    user: async (parent, { id }) => {
      return await User.findByPk(id);
    },
    
    posts: async (parent, args, context) => {
      // Apply filtering, pagination, etc.
      const { limit = 10, offset = 0, authorId } = args;
      const where = authorId ? { authorId } : {};
      
      return await Post.findAll({
        where,
        limit,
        offset,
        order: [['createdAt', 'DESC']]
      });
    },
    
    post: async (parent, { id }) => {
      return await Post.findByPk(id);
    }
  },
  
  Mutation: {
    createUser: async (parent, { input }) => {
      const { name, email } = input;
      
      // Validation
      if (!email.includes('@')) {
        throw new Error('Invalid email format');
      }
      
      return await User.create({ name, email });
    },
    
    createPost: async (parent, { input }, context) => {
      // Check authentication
      if (!context.user) {
        throw new Error('Authentication required');
      }
      
      const { title, content, authorId } = input;
      return await Post.create({ title, content, authorId });
    },
    
    updatePost: async (parent, { id, input }, context) => {
      const post = await Post.findByPk(id);
      if (!post) {
        throw new Error('Post not found');
      }
      
      // Authorization check
      if (post.authorId !== context.user.id && !context.user.isAdmin) {
        throw new Error('Not authorized to update this post');
      }
      
      await post.update(input);
      return post;
    },
    
    deletePost: async (parent, { id }, context) => {
      const post = await Post.findByPk(id);
      if (!post) {
        throw new Error('Post not found');
      }
      
      await post.destroy();
      return true;
    }
  },
  
  // Nested resolvers
  User: {
    posts: async (parent) => {
      return await Post.findAll({ where: { authorId: parent.id } });
    }
  },
  
  Post: {
    author: async (parent) => {
      return await User.findByPk(parent.authorId);
    },
    
    comments: async (parent) => {
      return await Comment.findAll({ where: { postId: parent.id } });
    }
  },
  
  Comment: {
    author: async (parent) => {
      return await User.findByPk(parent.authorId);
    },
    
    post: async (parent) => {
      return await Post.findByPk(parent.postId);
    }
  }
};

Client-Side GraphQL Queries

// Apollo Client setup
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';

const client = new ApolloClient({
  uri: 'http://localhost:4000/graphql',
  cache: new InMemoryCache()
});

// Queries
const GET_USERS = gql`
  query GetUsers {
    users {
      id
      name
      email
      posts {
        id
        title
      }
    }
  }
`;

const GET_POST = gql`
  query GetPost($id: ID!) {
    post(id: $id) {
      id
      title
      content
      author {
        name
        email
      }
      comments {
        id
        content
        author {
          name
        }
      }
    }
  }
`;

// Mutations
const CREATE_POST = gql`
  mutation CreatePost($input: CreatePostInput!) {
    createPost(input: $input) {
      id
      title
      content
      author {
        name
      }
    }
  }
`;

// Using in React components
import { useQuery, useMutation } from '@apollo/client';

function PostList() {
  const { loading, error, data } = useQuery(GET_USERS);
  const [createPost] = useMutation(CREATE_POST);
  
  if (loading) return 

Loading...

; if (error) return

Error: {error.message}

; const handleCreatePost = async (postData) => { try { await createPost({ variables: { input: postData }, refetchQueries: [{ query: GET_USERS }] }); } catch (error) { console.error('Error creating post:', error); } }; return (
{data.users.map(user => (

{user.name}

{user.posts.map(post => (

{post.title}

))}
))}
); }