Рубрики
Без рубрики

Mocking GraphQL с GraphQL-Tools

Как поднять API GraphQL с помощью реалистичных ценностей моей последней статьи, я взял оригинал APOLLO PARTPAD POSTPAD и авторов API и сломал его в домены и компоненты. Я хотел проиллюстрировать, как можно организовать большой проект GraphQL с помощью GraphQL-Tools. Теперь я бы хотел

Автор оригинала: Jeff M Lowery.

Как поднять API GraphQL с реалистичными ценностями

В моя последняя статья Я взял оригинал Apollo Launchpad Посты и авторы API и сломал его на домены и компоненты. Я хотел проиллюстрировать, как можно организовать большой проект GraphQL, используя graphql-tools Отказ

Теперь я хотел бы API, чтобы вернуть данные Mock, когда я его запрашиваю. Как?

Оригинальный источник

В исходном примере Apollo LaunchPad мы использовали статические структуры данных и простые сопоставления резользеров для обеспечения вывода запросов.

Например, учитывая этот запрос:

# Welcome to GraphiQL

query PostsForAuthor {
  author(id: 1) {
    firstName
    posts {
      title
      votes
    }
  }
}

Вывод будет:

{
  "data": {
    "author": {
      "firstName": "Tom",
      "posts": [
        {
          "title": "Introduction to GraphQL",
          "votes": 2
        }
      ]
    }
  }
}

Объект Resolvers имеет функции, которые заботятся о сопоставлении авторов к постам и Visa-Versa. Это не по-настоящему издевательство, хотя.

Проблема в том, что тем больше отношения и более сложные субъекты становятся, тем больше кодекс должен идти в резольветеры. Затем необходимо предоставить больше данных.

Когда дело доходит до тестирования, тесты могут иногда раскрывать проблемы в данных или в резольвестах. Вы действительно хотите фокус-тестирование самого API.

Используя издевательства

Существует три модуля Node.js, которые делают издевание API быстро и легко. Первое является частью graphql-tools модуль. Используя этот модуль, начальный шаг должен требовать или импортировать метод AddmockFunctionStoschema из модуля в корне schema.js файл:

import {
    makeExecutableSchema,
    addMockFunctionsToSchema
} from 'graphql-tools';

Затем, после создания исполняемого файла Схема Призывая CreateExecutableschema , Вы добавляете свои издевательства так:

    addMockFunctionsToSchema({
        schema: executableSchema,
    })

Вот полный список корня schema.js :

// This example demonstrates a simple server with some relational data: Posts and Authors. You can get the posts for a particular author,
// and vice-versa Read the complete docs for graphql-tools here: http://dev.apollodata.com/tools/graphql-tools/generate-schema.html

import {
    makeExecutableSchema,
    addMockFunctionsToSchema
} from 'graphql-tools';

import {
    schema as authorpostsSchema,
    resolvers as authorpostsResolvers
} from './authorposts';

import {
    schema as myLittleTypoSchema,
    resolvers as myLittleTypeResolvers
} from './myLittleDomain';

import {
    merge
} from 'lodash';

const baseSchema = [
    `
    type Query {
        domain: String
    }
    type Mutation {
        domain: String
    }
    schema {
        query: Query,
        mutation: Mutation
    }`
]

// Put schema together into one array of schema strings and one map of resolvers, like makeExecutableSchema expects
const schema = [...baseSchema, ...authorpostsSchema, ...myLittleTypoSchema]

const options = {
    typeDefs: schema,
    resolvers: merge(authorpostsResolvers, myLittleTypeResolvers)
}

const executableSchema = makeExecutableSchema(options);

addMockFunctionsToSchema({
    schema: executableSchema
})

export default executableSchema;

Так что же вывод? Выполнение одного и того же запроса, что и доходности:

{
  "data": {
    "author": {
      "firstName": "Hello World",
      "posts": [
        {
          "title": "Hello World",
          "votes": -70
        },
        {
          "title": "Hello World",
          "votes": -77
        }
      ]
    }
  }
}

Ну, это глупо. Каждая строка «Hello World», голоса негативны, и всегда будут именно два поста на авторе. Мы исправим это, но сначала …

Зачем использовать издевательства?

Макеты часто используются в модульных тестах, чтобы отделить функциональность, протестируемую от зависимостей, на которых опираются эти функции. Вы хотите проверить функцию (устройство), а не целый комплекс функций.

На этой ранней стадии разработки издевательства служат другой целью: тестировать тесты. В базовом тесте вы хотите сначала убедиться, что тест вызывает API правильно, и что возвращаемые результаты имеют ожидаемую структуру, свойства и типы. Я думаю, что крутые дети называют эту «форму».

Это предлагает более ограниченное тестирование, чем запрошенная структура данных, поскольку эталонная семантика не применяется. ID бессмысленно. Тем не менее, издевательства предлагают что-то, чтобы структурировать ваши тесты вокруг

Реалистичные издевательства

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

Вот список желаний для значений MOCK для отображения:

  1. Имя автора должно быть первым именем
  2. Почты должны быть переменными Lorem Ipsum Текст ограниченной длины
  3. голоса должны быть положительными или ноль
  4. Количество постов следует варьироваться от 1 до 7

Во-первых, что создать папку под названием Макеты Отказ Далее мы добавим index.js Файл к этой папке с методами издевательства. Наконец, пользовательские издевательства будут добавлены к сгенерированной исполняемой схеме.

Случайные Библиотека может генерировать значения по типу данных ( String, ID, INT, ... ) или по имени свойства. Кроме того, объект Mocklist GraphQL-Tools будет использоваться для изменения количества элементов в списке – в этом случае Сообщения Отказ Итак, начнем.

Импорт как повседневный, так и высмеист в /mocks/index.js :

import casual from 'casual';
import {
    MockList
} from 'graphql-tools';

Теперь позвольте создать экспорт по умолчанию со следующими свойствами:

export default {
    Int: () => casual.integer(0),
    
    Author: () => ({
        firstName: casual.first_name,
        posts: () => new MockList([1, 7])
    }),
    
    Post: () => ({
        title: casual.title
    })
}

Int Декларация заботится обо всех целочисленных типах, появляющихся в нашей схеме, и она обеспечит, чтобы Post.votes будет положительным или ноль.

Далее Aper.firstname будет разумное имя. Маклист используется для обеспечения того, чтобы количество сообщений, связанных с каждым автором, будет от 1 до 7 лет, наконец, случайные будут генерировать Lorem Ipsum Название для каждого Пост Отказ

Теперь сгенерированный выход варьируется каждый раз, когда запрос выполняется. И это выглядит доверительно:

{
  "data": {
    "author": {
      "firstName": "Eldon",
      "posts": [
        {
          "title": "Voluptatum quae laudantium",
          "votes": 581
        },
        {
          "title": "Vero quos",
          "votes": 85
        },
        {
          "title": "Doloribus labore corrupti",
          "votes": 771
        },
        {
          "title": "Qui nulla qui",
          "votes": 285
        }
      ]
    }
  }
}

Генерация пользовательских значений

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

Иногда, хотя есть ценности, которые должны соответствовать стандартному формату. Я хотел бы представить еще один модуль: Randexp Отказ

Randexp позволяет создавать значения, соответствующие выражению RegexP, которое вы его предоставите. Например, номера ISBN имеют формат:

/Isbn- \ d- \ d {3} – \ d {5} – \ d/

Теперь я могу добавить книги в схему, добавлять книги к автору и генерировать ISBN и заголовок для каждого Книга :

// book.js
export default `
  type Book {
    ISBN: String
    title: String
}

mocks.js:

import casual from 'casual';
import RandExp from 'randexp';
import {
    MockList
} from 'graphql-tools';
import {
    startCase
} from 'lodash';

export default {
    Int: () => casual.integer(0),
    
Author: () => ({
        firstName: casual.first_name,
        posts: () => new MockList([1, 7]),
        books: () => new MockList([0, 5])
    }),
    
Post: () => ({
        title: casual.title
    }),
    
Book: () => ({
        ISBN: new RandExp(/ISBN-\d-\d{3}-\d{5}-\d/)
            .gen(),
        title: startCase(casual.title)
    })
}

И вот новый запрос:

query PostsForAuthor {
  author(id: 1) {
    firstName
    posts {
      title
      votes
    }
    books {
      title
      ISBN
    }
  }
}

Образец ответа:

{
  "data": {
    "author": {
      "firstName": "Rosemarie",
      "posts": [
        {
          "title": "Et ipsum quo",
          "votes": 248
        },
        {
          "title": "Deleniti nihil",
          "votes": 789
        },
        {
          "title": "Aut aut reprehenderit",
          "votes": 220
        },
        {
          "title": "Nesciunt debitis mollitia",
          "votes": 181
        }
      ],
      "books": [
        {
          "title": "Consequatur Veniam Voluptas",
          "ISBN": "ISBN-0-843-74186-9"
        },
        {
          "title": "Totam Et Iusto",
          "ISBN": "ISBN-6-532-70557-3"
        },
        {
          "title": "Voluptatem Est Sunt",
          "ISBN": "ISBN-2-323-13918-2"
        }
      ]
    }
  }
}

Так что это основы издевательства с использованием GraphQL-инструментов, а также пару других полезных модулей.

Примечание : Я использую фрагменты на протяжении всего этого поста. Если вы хотите следовать в более широком контексте, образец кода – здесь Отказ

Полный источник находится на Github для вашего прочтения.

Дайте мне руку, если вы нашли эту статью информативную.