Мы можем создать простой сервер GraphQL с помощью Express. Для этого нам понадобятся пакеты express-graphql и graphql.

В этой статье мы рассмотрим, как создавать мутации и типы ввода с помощью Express и GraphQL.

Мутации и типы ввода

Чтобы создать мутации, мы создаем схему, которая имеет тип Mutation, а не Query.

Затем достаточно просто сделать конечную точку API частью верхнего уровня Mutation типа вместо типа Query.

И мутации, и запросы могут обрабатываться корневыми преобразователями.

Затем мы можем создать сервер GraphQL, который принимает как запросы, так и мутации следующим образом:

const express = require('express');
const graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');
const crypto = require('crypto');
const schema = buildSchema(`
  input TodoInput {
    text: String    
  }
  type Todo {
    id: ID!
    text: String    
  }
  type Query {
    getTodo(id: ID!): Todo
  }
  type Mutation {
    createTodo(input: TodoInput): Todo
    updateTodo(id: ID!, input: TodoInput): Todo
  }
`);
class Todo {
  constructor(id, { text }) {
    this.id = id;
    this.text = text;
  }
}
let todos = {};
const root = {
  getTodo: ({ id }) => {
    if (!todos[id]) {
      throw new Error('Todo not found.');
    }
    return new Todo(id, todos[id]);
  },
  createTodo: ({ input }) => {
    const id = crypto.randomBytes(10).toString('hex');
    todos[id] = input;
    return new Todo(id, input);
  },
  updateTodo: ({ id, input }) => {
    if (!todos[id]) {
      throw new Error('Todo not found');
    }
    todos[id] = input;
    return new Todo(id, input);
  },
};
const app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));
app.listen(3000, () => console.log('server started'));

В приведенном выше коде мы определили наши типы, написав:

const schema = buildSchema(`
  input TodoInput {
    text: String    
  }
  type Todo {
    id: ID!
    text: String    
  }
  type Query {
    getTodo(id: ID!): Todo
  }
  type Mutation {
    createTodo(input: TodoInput): Todo
    updateTodo(id: ID!, input: TodoInput): Todo
  }
`);

Мы создали тип ввода TodoInput и тип Todo. Затем мы создали тип Query с членом getTodo, чтобы мы могли получать наши задачи.

Затем в нашем Mutation мы добавили участников createTodo и updateTodo, чтобы мы могли добавлять и обновлять задачи.

Затем мы создаем наш Todo класс, чтобы мы могли хранить данные задачи:

class Todo {
  constructor(id, { text }) {
    this.id = id;
    this.text = text;
  }
}

Далее у нас есть корневой резолвер:

const root = {
  getTodo: ({ id }) => {
    if (!todos[id]) {
      throw new Error('Todo not found.');
    }
    return new Todo(id, todos[id]);
  },
  createTodo: ({ input }) => {
    const id = crypto.randomBytes(10).toString('hex');
    todos[id] = input;
    return new Todo(id, input);
  },
  updateTodo: ({ id, input }) => {
    if (!todos[id]) {
      throw new Error('Todo not found');
    }
    todos[id] = input;
    return new Todo(id, input);
  },
};

Он добавляет функции с теми же функциями, которые мы указали в нашей схеме, чтобы мы могли что-то делать при выполнении некоторых запросов.

В этом примере getTodo мы вернем задачу с заданным id. Будет возвращено найденное задание. В противном случае мы выдаем ошибку.

В createTodo мы получаем input из запроса, а затем добавляем запись задачи в наш объект todos, который является нашей фальшивой базой данных для хранения задач. Сохраненное задание будет возвращено.

Затем у нас есть функция updateTodo для обновления задачи на id. Все, что имеет данный id, будет заменено содержимым input. Сохраненное задание будет возвращено. Мы выдаем ошибку, если задача с заданным id не найдена.

Затем, когда мы перейдем на страницу /graphql, мы можем ввести следующее в окно GraphiQL:

mutation {
  createTodo(input: {text: "eat"}) {
    id
    text
  }
}

Тогда получаем что-то вроде:

{
  "data": {
    "createTodo": {
      "id": "c141d1fda69e8d9084bd",
      "text": "eat"
    }
  }
}

как ответ.

Если мы сделаем запрос на обновление todo следующим образом:

mutation {
  updateTodo(id: "e99ce10750c93793a23d", input: {text: "eat"}) {
    id
    text
  }
}

Получаем что-то вроде:

{
  "data": {
    "updateTodo": {
      "id": "e99ce10750c93793a23d",
      "text": "eat"
    }
  }
}

назад в качестве ответа.

Если задача не найдена, получаем:

{
  "errors": [
    {
      "message": "Todo not found",
      "locations": [
        {
          "line": 9,
          "column": 3
        }
      ],
      "path": [
        "updateTodo"
      ]
    }
  ],
  "data": {
    "updateTodo": null
  }
}

как ответ.

Мы можем сделать getTodo запрос следующим образом:

query {
  getTodo(id: "e99ce10750c93793a23d"){
    id
    text
  }
}

Тогда получаем:

{
  "data": {
    "getTodo": {
      "id": "e99ce10750c93793a23d",
      "text": "eat"
    }
  }
}

как ответ.

Заключение

Мы можем создавать мутации так же, как и с запросами.

Чтобы принять операции мутации на нашем сервере GraphQL, мы создаем наши типы для хранения наших данных, а затем мы создаем наши мутации, заполняя тип Mutation нашими членами.

Затем мы можем использовать функцию buildSchema для построения только что указанной схемы.

Затем в нашем корневом редукторе мы создаем функции с именами, которые мы указали в определениях типов.

Наконец, мы можем делать запросы к нашему серверу для запуска мутаций.

Примечание от JavaScript In Plain English:

Мы всегда заинтересованы в продвижении качественного контента. Если у вас есть статья, которую вы хотите отправить в JavaScript In Plain English, отправьте нам электронное письмо по адресу [email protected] с вашим именем пользователя Medium, и мы добавим вас в качестве автора.