In this section, we will cover the fundamentals of GraphQL schemas. Understanding schemas is crucial as they define the structure of your GraphQL API, including the types of data you can query and the operations you can perform.

What is a GraphQL Schema?

A GraphQL schema is a central piece of a GraphQL server. It defines:

  • Types: The shape of the data.
  • Queries: The read operations.
  • Mutations: The write operations.
  • Subscriptions: Real-time updates (optional).

Key Components of a GraphQL Schema

  1. Types: Define the structure of the data.
  2. Queries: Define how to read data.
  3. Mutations: Define how to modify data.
  4. Resolvers: Functions that resolve the data for each field.

Defining a Simple Schema

Let's start with a basic example. Suppose we have a simple application that manages users.

Step 1: Define Types

type User {
  id: ID!
  name: String!
  email: String!
}
  • ID!: A non-nullable unique identifier.
  • String!: A non-nullable string.

Step 2: Define Queries

type Query {
  users: [User!]!
  user(id: ID!): User
}
  • users: Returns a list of users.
  • user(id: ID!): Returns a single user by ID.

Step 3: Define Mutations

type Mutation {
  createUser(name: String!, email: String!): User!
  updateUser(id: ID!, name: String, email: String): User
  deleteUser(id: ID!): User
}
  • createUser: Creates a new user.
  • updateUser: Updates an existing user.
  • deleteUser: Deletes a user.

Step 4: Combine into a Schema

schema {
  query: Query
  mutation: Mutation
}

Example Schema

Here is the complete schema for our user management example:

type User {
  id: ID!
  name: String!
  email: String!
}

type Query {
  users: [User!]!
  user(id: ID!): User
}

type Mutation {
  createUser(name: String!, email: String!): User!
  updateUser(id: ID!, name: String, email: String): User
  deleteUser(id: ID!): User
}

schema {
  query: Query
  mutation: Mutation
}

Practical Example

Let's implement this schema in a GraphQL server using Node.js and the graphql package.

Step 1: Install Dependencies

npm install graphql express express-graphql

Step 2: Create the Server

const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');

// Define the schema
const schema = buildSchema(`
  type User {
    id: ID!
    name: String!
    email: String!
  }

  type Query {
    users: [User!]!
    user(id: ID!): User
  }

  type Mutation {
    createUser(name: String!, email: String!): User!
    updateUser(id: ID!, name: String, email: String): User
    deleteUser(id: ID!): User
  }

  schema {
    query: Query
    mutation: Mutation
  }
`);

// Sample data
let users = [
  { id: '1', name: 'John Doe', email: '[email protected]' },
  { id: '2', name: 'Jane Doe', email: '[email protected]' },
];

// Define the resolvers
const root = {
  users: () => users,
  user: ({ id }) => users.find(user => user.id === id),
  createUser: ({ name, email }) => {
    const newUser = { id: String(users.length + 1), name, email };
    users.push(newUser);
    return newUser;
  },
  updateUser: ({ id, name, email }) => {
    const user = users.find(user => user.id === id);
    if (!user) return null;
    if (name) user.name = name;
    if (email) user.email = email;
    return user;
  },
  deleteUser: ({ id }) => {
    const userIndex = users.findIndex(user => user.id === id);
    if (userIndex === -1) return null;
    const [deletedUser] = users.splice(userIndex, 1);
    return deletedUser;
  },
};

// Create an Express server and a GraphQL endpoint
const app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));

app.listen(4000, () => console.log('Server running on http://localhost:4000/graphql'));

Step 3: Test the Server

You can test the server by navigating to http://localhost:4000/graphql and running queries and mutations in the GraphiQL interface.

Exercises

Exercise 1: Add a New Field to the User Type

Add a new field age of type Int to the User type and update the schema accordingly.

Solution:

type User {
  id: ID!
  name: String!
  email: String!
  age: Int
}

type Query {
  users: [User!]!
  user(id: ID!): User
}

type Mutation {
  createUser(name: String!, email: String!, age: Int): User!
  updateUser(id: ID!, name: String, email: String, age: Int): User
  deleteUser(id: ID!): User
}

schema {
  query: Query
  mutation: Mutation
}

Exercise 2: Implement a Resolver for the New Field

Update the resolvers to handle the new age field.

Solution:

const root = {
  users: () => users,
  user: ({ id }) => users.find(user => user.id === id),
  createUser: ({ name, email, age }) => {
    const newUser = { id: String(users.length + 1), name, email, age };
    users.push(newUser);
    return newUser;
  },
  updateUser: ({ id, name, email, age }) => {
    const user = users.find(user => user.id === id);
    if (!user) return null;
    if (name) user.name = name;
    if (email) user.email = email;
    if (age !== undefined) user.age = age;
    return user;
  },
  deleteUser: ({ id }) => {
    const userIndex = users.findIndex(user => user.id === id);
    if (userIndex === -1) return null;
    const [deletedUser] = users.splice(userIndex, 1);
    return deletedUser;
  },
};

Conclusion

In this section, we covered the basics of GraphQL schemas, including defining types, queries, and mutations. We also implemented a simple GraphQL server to demonstrate these concepts. Understanding schemas is fundamental to working with GraphQL, as they define the structure and capabilities of your API. In the next module, we will dive deeper into core concepts such as queries, mutations, and resolvers.

© Copyright 2024. All rights reserved