【CuteJavaScript】Введение в GraphQL

GraphQL
【CuteJavaScript】Введение в GraphQL

После прочтения «Мстителей IV» я составил вводное руководство по GraphQL, ха-ха, оно действительно ароматное. . .

Добро пожаловать, чтобы следовать за мнойДомашняя страница && личный блог && личная база знаний&& Публичный аккаунт WeChat "Классы самообучения переднего плана"

Прежде всего, попросите Abba Town сделать публикацию! Ха-ха-ха, друзья, которым нужны оригинальные фотографии высокой четкости, могутНажмите на меня, чтобы скачать Abba Invincible.

iron_man

Начнем эту статью:

1. Введение в GraphQL

GraphQLразработано FacebookЯзык запросов для API, выпущенный публично в 2015 году, является заменой REST API.

GraphQLоба APIязык запросовЭто также тот, который удовлетворяет ваш запрос данных.Время выполнения.GraphQLПредоставляет полное и простое для понимания описание данных в вашем API, позволяя клиенту получить именно те данные, которые ему нужны, ибез избыточности, также облегчает развитие API с течением времени и может использоваться для создания мощных инструментов разработчика.

Официальный сайт:graphql.org/
Китайский сайт:graphql.cn/

1. Особенности

  • Запросите данные, которые вы хотите, не больше и не меньше;

Такие как:heroимеютname, age, sexд., вы можете получить только те поля, которые вам нужны.

  • Получите несколько ресурсов всего одним запросом;

типичныйREST APIНесколько URL-адресов должны быть загружены при запросе нескольких ресурсов, иGraphQLПолучите все данные, необходимые вашему приложению, одним запросом. Это также может гарантировать, что использование медленных подключений к мобильной сетиGraphQLприложения также могут работать достаточно быстро.

  • Опишите все возможные типы систем. Простое обслуживание, плавная эволюция в соответствии с требованиями, добавление или скрытие полей;

GraphQLИспользование типов гарантирует, что приложения запрашивают только возможные данные, а также предоставляет четкие вспомогательные сообщения об ошибках. Приложения могут использовать типы без написания кода для разбора вручную.

2. Простой случай

Давайте рассмотрим здесь простой случай и испытаем его.GraphQLМагия (об этом позже).
Мы определяем оператор запроса следующим образом:

query {
    hero
}

Тогда мы получим то, что ищемheroПоле:

{
    "data": {
        "hero": "I'm iron man"
    }
}

Так удобнее пользоваться?

2. Сравнение GraphQL и restful

1. Введение в отдых

Полное имя:Representational State TransferПереход состояния атрибута таблицы.
По сути, это определение uri и получение ресурсов через интерфейс API. Универсальная системная архитектура, не ограниченная языком.

Пример: Голодный интерфейс.
Например: интерфейсrestapi/shopping/v3/restaurants?latitude=13является типичнымrestfulИнтерфейс, определение ресурсов + условия запроса.

2. Сравнение с GraphQL

  • restfulИнтерфейс может возвращать только один ресурс,GraphQLНесколько ресурсов могут быть получены одновременно.

  • restfulИспользуйте разные URL-адреса, чтобы различать ресурсы,GraphQLРазличать ресурсы по типу.

3. Используйте экспресс для создания базового приветственного мира

1. Простой случай

Сначала создайте папкуdemoи инициализироватьpackage.json,Установитьexpress / graphql / express-graphqlПакет зависимостей:

npm init -y
npm install express graphql express-graphql -S

создать новыйhello.js, импортируйте файл:

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

Создаватьschemaдля определения операторов и типов запросов,buildSchema()Параметры, которые должен передать метод:нитьтип, например следующийheroполе запроса, за которым следуетStringТип указывает тип данных, возвращаемый полем:

const schema = buildSchema(`
    type Query {
        hero: String
    }
`)

СоздаватьrootПроцессор, который обрабатывает соответствующий запрос, здесьhelloПроцессор соответствуетschemaсерединаheroОбработка запроса поля, возврат прямо сюдаI'm iron manрезультат:

const root = {
    hero: () => {
        return "I'm iron man"
    }
}

Конечно, в процессоре могут быть и другие сложные операции, которые будут представлены позже.

затем создайте экземплярexpress, и перенаправить маршрут наgraphqlHTTPиметь дело с:

const app = express()
app.use('/graphql', graphqlHTTP({
    schema,
    rootValue: root,
    graphiql: true
}))
app.listen(3000)

graphqlHTTPТри параметра во введении:

  • schema: Определенные операторы запроса и типы
  • rootValue: Процессор, который обрабатывает соответствующий запрос
  • graphiql: открывать ли окно отладки, открывать на стадии разработки, закрывать на стадии производства

Затем запустите проект и выполните его в командной строке.node hello.js, который можно найти здесьgraphiqlСделай отладку, открой адресlocalhost:3000/graphiqlВы можете запросить счастливо.

1

Дополнительно мы можемgraphiqlОткрыть в правой части интерфейсаDocsПросмотрите все поля и описания, которые мы определили.

2

3

Окончательный код:

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

// 构建schema,这里定义查询的语句和类型
const schema = buildSchema(`
    type Query {
        hero: String
    }
`)

// 定义查询所对应的 resolver,也就是查询对应的处理器
const root = {
    hero: () => {
        return "I'm iron man"
    }
}

const app = express()

// 将路由转发给 graphqlHTTP 处理
app.use('/graphql', graphqlHTTP({
    schema: schema,
    rootValue: root,
    graphiql: true
}))

app.listen(3000)

2. Пользовательский тип запроса

В нашем предыдущем запросе мы имеемheroПоле определяется какStringтип, но часто в разработке мы будем сталкиваться с полями с несколькими типами, т.е.Поля также могут ссылаться на типы объектов (Object), напримерuserполе будет иметьname,ageполя etc, в то время какnameтип возвращаемой строки,ageВозвращает числовой тип.

В этот момент мы можем выполнитьподвыбор. Запросы GraphQL могут перемещаться по связанным объектам и их полям, что позволяет клиентам запрашивать большие объемы связанных данных в одном запросе вместо нескольких круговых обходов, как в традиционных архитектурах REST.

Мы можем создать новый тип запроса для определенияuserТип, возвращаемый полем:

const schema = buildSchema(`
    type User {
        # 查询可以有备注!
        name: String
        age: Int
    }
    type Query {
        hero: String
        user: User
    }
`)

В процессоре также добавляем:


const root = {
    hero: () => {
        return "I'm iron man"
    },
    user: () => {
        return {
            name: 'leo',
            age: 18
        }
    }
}

Проблема типа параметра Int/String здесь будет рассмотрена в следующей главе.

В-четвертых, типы параметров и передача параметров

1. Основные типы параметров

String, Int, Float, Booleanа такжеID, эти основные типы параметров можно найти вschemaиспользуется непосредственно в заявлении.

  • Int: 32-битное целое число со знаком.
  • Float: Значение двойной точности с плавающей запятой со знаком.
  • String:UTF‐8последовательность символов.
  • Boolean:trueилиfalse.
  • ID:IDСкалярный тип представляетуникальный идентификатор, обычно используемый для извлечения объекта или в качестве ключа в кэше.IDиспользование типа иStringсериализовать таким же образом, однако определить его какIDсредства иУдобочитаемый тип не требуется.

В качестве альтернативы мы можем использовать[类型]для представления класса массивов, например:

  • [Int]Представляет массив целых чисел;
  • [String]Представляет массив строк;

2. Передача параметров

Использование такое же, как и при передаче параметров JS, формальные параметры определены в круглых скобках, ноПараметр должен определять тип.

использовать!Указывает, что параметр не может быть пустым.

Следующий случай: параметрteamNameдаStringтип, который необходимо передать, при этомnumberпараметры такжеIntТипа, но его передавать не требуется, а конечный вывод тожеStringТипы.

type Query {
    getHero(teamName: String!, number: Int): [String]
}

Следующий случай:

//...省略其他
const schema = buildSchema(`
    type Query {
        getHero(teamName: String!): [String]
    }
`)

const root = {
    getHero: ({teamName}) => {
        // 这里的操作 实际开发中常常用在请求数据库
        const hero = {
            '三国': ['张飞', '刘备', '关羽'],
            '复仇者联盟': ['钢铁侠', '美国队长', '绿巨人']
        }
        return hero[teamName]
    }
}
//...省略其他

В это время мыGraphiQLВведите запрос наМстителистатистика героя.

// 查询
query {
	getHero(teamName:"复仇者联盟")
}

// 结果
{
    "data": {
        "getHero": [
            "钢铁侠",
            "美国队长",
            "绿巨人"
        ]
    }
}

3. Пользовательский тип возврата

В реальной разработке тип данных, который мы возвращаем, может быть объектом, и объект может иметь какIntсвойства типа, есть такжеStringзначение типа и т. д., здесь мы можем использоватьнастраиваемый тип возвратаобрабатывать:

//...省略其他
const schema = buildSchema(`
    type Hero {
        name: String
        age: Int
        doSomething(thing: String): String
    }
    type Query {
        getSuperHero(heroName: String!): Hero
    }
`)
const root = {
    getSuperHero: ({heroName}) => {
        // 这里的操作 实际开发中常常用在请求数据库
        const name = heroName
        const age = 18
        const doSomething = ({thing}) => {
            return `I'm ${name}, I'm ${thing} now`
        }
        return { name, age, doSomething }
    }
}
//...省略其他

указано здесьgetSuperHeroТип возвращаемого значения поляHeroтип, который затем определяется вышеHero.

вHeroтипdoSomethingТакже можно передать указанный параметр типа и указать возвращаемый тип.

Взгляните на вывод ниже:

// 查询
query {
	getSuperHero(heroName:"IronMan") {
        name
        age
        doSomething
	}
}

// 结果
{
    "data": {
        "getSuperHero": {
            "name": "IronMan",
            "age": 46,
            "doSomething": "I'm IronMan, I'm undefined now"
        }
    }
}

Здесь вы также можете датьdoSomethingПередавая параметры, вы получите разные результаты:

// 查询
query {
	getSuperHero(heroName:"IronMan") {
        name
        age
	    doSomething(thing:"watching TV")
	}
}

// 结果
{
    "data": {
        "getSuperHero": {
            "name": "IronMan",
            "age": 46,
            "doSomething": "I'm IronMan, I'm watching TV now"
        }
    }
}

5. Клиент GraphQL

В этом разделе мы узнаем, как получить доступ в клиентеgraphqlИнтерфейс.

1. Внутренний интерфейс определения

Сначала мы завершаем разработку интерфейса на бэкенде, который похож на предыдущий, но требует еще одного шага, используяexpressОткройте папку извне, чтобы пользователи могли получить доступ к статическим файлам ресурсов:

Используйте код из предыдущего раздела прямо здесь~

// index.js  开发 graphql 接口
//...省略其他
const schema = buildSchema(`
    type Hero {
        name: String
        age: Int
        doSomething(thing: String): String
    }
    type Query {
        getSuperHero(heroName: String!): Hero
    }
`)
const root = {
    getSuperHero: ({heroName}) => {
        // 这里的操作 实际开发中常常用在请求数据库
        const name = heroName
        const age = 46
        const doSomething = ({thing}) => {
            return `I'm ${name}, I'm ${thing} now`
        }
        return { name, age, doSomething }
    }
}
const app = express()
app.use('/graphql', graphqlHTTP({
    schema, rootValue: root, graphiql: true
}))
// 公开文件夹 使用户访问静态资源
app.use(express.static('public'))
app.listen(3000)

Таким образом, мы предоставляем интерфейсной странице функцию, которая может обращаться к статическим ресурсам.

Здесь также необходимо создатьpublicпапку, а в папку добавитьindex.htmlфайл, структура каталогов на данный момент:

|-node_modules
|-public
|---index.html
|-index.js
|-package.json

2. Запрос страницы интерфейса

тогда дайindex.htmlДобавьте привязки кнопок и событий:

переменная здесьqueryЯвляетсяТип строкиопределить состояние запроса, в состоянииGetSuperHeroпараметры в , вам нужно использовать$символы для идентификации и в фактическом запросеgetSuperHero, тип параметра задается как параметр.

затем определите переменнуюvariables, указав значение свойства, за которым следуетfetchОбратиться с просьбой:

<button onclick="getData()">获取数据</button>
<script>
function getData(){
    const query = `
        query GetSuperHero($heroName: String, $thing: String){
            getSuperHero(heroName: $heroName){
                name
                    age
                    doSomething(thing: $thing)
            }
        }
    `
    // 如果不需要其他参数 至少要传一个参数 否则会报错
    // const query = `
    //     query GetSuperHero($heroName: String){
    //         getSuperHero(heroName: $heroName){
    //              name
    //         }
    //     }
    // `    
    const variables = {heroName: '钢铁侠', thing: 'watching TV'}

    fetch('./graphql', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        },
        body: JSON.stringify({
            query, variables
        })
    })
    .then(res => res.json())
    .then(json => {
        console.log(json)
    })
}
</script>

Когда мы закончим писать, нажмитеполучить данныеНа консоль будут выведены следующие данные:

{
    "data":{
        "getSuperHero":{
            "name":"钢铁侠",
            "age":46,
            "doSomething": "I'm 钢铁侠, I'm watching TV now"
        }
    }
}

3. На заметку

  • в запросеqueryПараметры нужно хорошо сравнивать$Символьные переменные.

проверить предложениеquery GetSuperHero($heroName: String)параметры$heroNameсерединаheroName;
проверить предложениеgetSuperHero(heroName: $heroName)тип$heroNameсерединаheroName;
ПеременнаяvariablesсерединаheroNameАтрибуты;

Три имени должны быть одинаковыми.

  • данные нужны в запросеоперация сериализации.
body: JSON.stringify({ query, variables })

6. Используйте мутации для изменения данных

1. Использование мутаций

Согласно предыдущему исследованию, мы знаем, что для выполнения операции запроса нам нужно использоватьQueryобъявить:

type Query {
    queryHero(heroName: String): String
}

когда мы делаемИзменить операцию, вам нужно использоватьMutation :

type Mutation {
    createHero(heroName: String): String
}

еслиMutationФормальные параметры полей впользовательский тип, то тип должен использоватьinputЯ БЫ:

const schema = buildSchema(`
    # 输入类型 用 input 标识
    input HeroInput {
        name: String
        age: Int
    }
    # 查询类型
    type Hero {
        name: String
        age: Int
    }
    type Mutation {
        createHero(heroName: String): Hero
        updateHero(heroName: String, hero: HeroInput): Hero
    }
`)

Примечание. Здесь вам необходимо определить хотя бы одинQueryиначеGraphiQLЗапрос не будет отображаться:

type Query {
    hero: [Hero]
}

2. Варианты использования мутации

сначала создайтеschema, содержимое — это содержимое, определенное на предыдущем шаге [1. Использование мутации], которое здесь повторяться не будет.
Затем смоделируйте создание локальной базы данныхlocalDb, используемый для имитации хранения добавленных данных супергероя:

const localDb = {}

Следующее заявлениеrootвыполнитьschemaПолевые методы в:

const root = {
    hero() {
        // 这里需要转成数组 因为前面定义了返回值是  [Hero]  类型
        let arr = []
        for(const key in localDb){
            arr.push(localDb[key])
        }
        return arr
    },
    createHero({ input }) {
        // 相当于数据库的添加操作
        localDb[input.name] = input
        return localDb[input.name]
    },
    updateHero({ id, input }) {
        // 相当于数据库的更新操作
        const update = Object.assign({}, localDb[id], input)
        localDb[id] = update
        return update
    }
}

окончательная конфигурацияgraphqlHTTPСпособ и запуск сервера здесь повторяться не будем.

Окончательный код:

//...省略其他
const schema = buildSchema(`
    # 输入类型 用 input 标识
    input HeroInput {
        name: String
        age: Int
    }
    # 查询类型
    type Hero {
        name: String
        age: Int
    }
    type Mutation {
        createHero(input: HeroInput): Hero 
        updateHero(id: ID!, input: HeroInput): Hero
    }
    # 需要至少定义一个 Query 不要GraphiQL会不显示查询
    type Query {
        hero: [Hero]
    }
`)

const localDb = {}

const root = {
    hero() {
        // 这里需要转成数组 因为前面定义了返回值是  [Hero]  类型
        let arr = []
        for(const key in localDb){
            arr.push(localDb[key])
        }
        return arr
    },
    createHero({ input }) {
        // 相当于数据库的添加操作
        localDb[input.name] = input
        return localDb[input.name]
    },
    updateHero({ id, input }) {
        // 相当于数据库的更新操作
        const update = Object.assign({}, localDb[id], input)
        localDb[id] = update
        return update
    }
}
//...省略其他

Теперь мы можем запустить сервер, вGraphiQLПроверьте эффект.

мы используемmutationизcreateHeroПоле добавляет две части данных:

mutation {
    createHero(input: {
        name: "钢铁侠"
        age: 40
    }){
        name
        age
    }
}
mutation {
    createHero(input: {
        name: "美国队长"
        age: 41
    }){
        name
        age
    }
}

затем используйтеqueryизheroПолевой запрос добавил результаты:

query {
    hero {
        name
        age
    }
}

Таким образом, мы получаем результат сложения только что:

{
    "data": {
        "hero": [
            {
                "name": "钢铁侠",
                "age": 40
            },
            {
                "name": "美国队长",
                "age": 41
            }
        ]
  }
}

Затем мы начинаем обновлять данные, используяmutationизupdateHeroполе будетКапитан АмерикаизageИзмените значение на 18:

mutation {
    updateHero(id: "美国队长", input: {
        age: 18
    }){
        age
    }
}

повторное использованиеqueryизheroПоле запроса новых данных, вы найдетеКапитан АмерикаизageЗначение было обновлено до 18:

{
    "data": {
        "hero": [
            {
                "name": "钢铁侠",
                "age": 40
            },
            {
                "name": "美国队长",
                "age": 18
            }
        ]
    }
}

7. Аутентификация и промежуточное ПО

Мы знаем, что интерфейс для изменения данных не может быть свободно доступен всем, поэтому необходимо добавить аутентификацию по разрешениям, чтобы люди с разрешениями могли получить к нему доступ.
существуетexpress, Это легко использоватьпромежуточное ПОЧтобы перехватить запрос, отфильтруйте запрос без разрешения и верните сообщение об ошибке.

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

Это в окончательном коде [Six, использование мутаций для изменения данных], добавление этого промежуточного программного обеспечения:

//... 省略其他
const app = express()
const middleWare = (req, res, next) => {
    // 这里是简单模拟权限
    // 实际开发中 更多的是和后端进行 token 交换来判断权限
    if(req.url.indexOf('/graphql') !== -1 && req.headers.cookie.indexOf('auth') === -1){
        // 向客户端返回一个错误信息
        res.send(JSON.stringify({
            err: '暂无权限'
        }))
        return
    }
    next() // 正常下一步
}
// 注册中间件
app.use(middleWare)

//... 省略其他

Принятие решения о разрешении здесь является простой симуляцией.tokenExchange для определения разрешений (или других форм).
Перезапускаем сервер, открываемhttp://localhost:3000/graphql, обнаружил, что страница выдает ошибку, потому чтоcookiesне содержитauthнить.

Если будет предложено здесьTypeError: Cannot read property 'indexOf' of undefined, вы можете оставить его в покое, потому что браузер неcookiesФактически, предыдущую логику оценки разрешений необходимо оценивать в соответствии с конкретными бизнес-сценариями.

Для удобства тестирования мы в консоли браузера хромapplication, установить вручнуюauthодна из строкcookies, только для пробного использования.

После завершения настройки мы можем войти на страницу в обычном режиме.

Восемь, ConstructingTypes

В предыдущем введении мы собирались создатьschemaоба используютbuildSchemaметод для определения, но мы также можем использовать другой способ определения.
Это конструктор, чтобы научиться использовать здесьgraphql.GraphQLObjectTypeОпределение, он имеет ряд преимуществ и недостатков:

  • преимущество: Уведомления об ошибках стали более интуитивно понятными, структура стала понятнее, а обслуживание стало проще.
  • недостаток: количество кода увеличивается.

1. Определите тип

Здесь определено ранееHeroВведите для преобразования:

const graphql = require('graphql') // 需要引入
const HeroType = new graphql.GraphQLObjectType({
    name: 'Hero',
    fields: {
        name:{ type: graphql.GraphQLString },
        age:{ type: graphql.GraphQLInt },
    }
})

graphql6

Разница между ними заключается в следующем:

разница buildSchema graphql.GraphQLObjectType
Тип параметра нить объект
имя класса следитьtypeпосле символов вотtype Hero в объекте параметраnameатрибут
определение свойства Определяется после типа,пара ключ-значениеформа определено в объекте параметраfieldsВ атрибуте значение является объектом, каждое имя атрибута является именем ключа, а значение также является объектом, гдеtypeСтоимость имуществаgraphqlсвойства в , которые будут добавлены ниже

Пополнить:
fieldsТипы подсвойств в свойствах обычно следующие:

  • graphql.GraphQLString
  • graphql.GraphQLInt
  • graphql.GraphQLBoolean ....

то естьGraphQLДалее следует имя базового типа.

2. Определите запрос

При определении запроса он аналогичен предыдущему.Для понимания можно обратиться к следующей сравнительной диаграмме.Разница здесь в том, что здесь большеresolveметод, этот метод используется для выполнения логики обработки запроса, который фактически является предыдущимrootметод в .

const QueryType = new graphql.GraphQLObjectType({
    name: 'Query',
    fields: {
        // 一个个查询方法
        getSuperHero: {
            type: HeroType,
            args: {
                heroName: { type: graphql.GraphQLString }
            },
            // 方法实现 查询的处理函数
            resolve: function(_, { heroName }){
                const name = heroName
                const age = 18
                return { name, age }
            }
        }
    }
})

graphql8

3. Создайте схему

При создании просто создайте экземпляр и передайте параметры:

// step3 构造 schema
const schema = new graphql.GraphQLSchema({ query: QueryType})

Окончательное использование такое же, как и раньше:

const app = express()

app.use('/graphql', graphqlHTTP({
    schema,
    graphiql: true
}))
app.listen(3000)

9. Борьба с базой данных

Давайте попробуем разработать простой практический проект, используя то, что мы узнали ранее:
пройти черезGraphiQLстраница, чтобыMongodbВставляйте и обновляйте данные в , в основном используйте операции, описанные в главе [6. Изменение данных с помощью мутаций].

1. Создайте и запустите локальную базу данных MongoDB.

Сначала мы можем пойти вофициальный сайт монгодбВыберите соответствующую платформу и версию для загрузки и установки.

Загрузите и установите шаги, вы можете обратиться кзагрузка, установка и настройка mongoDB, я не буду вводить здесь больше~~

После завершения установки мы открываем два терминала и выполняем следующие две строки команд:

// 终端1  启动数据库
mongod --dbpath c:\leo\app\mongodb\data\db

// 终端2  进入数据库命令行操作模式
mongo

2. Подключитесь к базе данных, создайте схему и модель

Сначала мы создаем новый файлdb.js,а такжеnpm install mongooseУстановитьmongoose, а затем напишите следующий код для достиженияПодключиться к базе данных:

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

const DB_PATH = 'mongodb://127.0.0.1:27017/hero_table'
const connect = () => {
    // 连接数据库
    mongoose.connect(DB_PATH)
    // 连接断开
    mongoose.connection.on('disconnected', () => {
        mongoose.connect(DB_PATH)
    })
    // 连接失败
    mongoose.connection.on('error', err => {
        console.error(err)
    })
    // 连接成功
    mongoose.connection.on('connected', async () => {
        console.log('Connected to MongoDB connected', DB_PATH)
    })  
}
connect()

затем создайтеSchemaа такжеModel:

let HeroSchema = new mongoose.Schema({
    name: String,
    age: Number
})
let HeroModel = mongoose.model('hero',HeroSchema, 'hero_table')

3. Объявите оператор запроса

На этом шаге сначала используйте логику работы из главы [6. Использование мутаций для изменения данных], то есть сначала используйтеЗапрос на создание строки, Вместо того, чтобы использоватьGraphQLObjectTypeСоздайте:

const schema = buildSchema(`
    # 输入类型 用 input 标识
    input HeroInput {
        name: String
        age: Int
    }
    # 查询类型
    type Hero {
        name: String
        age: Int
    }
    type Mutation {
        createHero(input: HeroInput): Hero 
        updateHero(hero: String!, input: HeroInput): Hero
    }
    # 需要至少定义一个 Query 不要GraphiQL会不显示查询
    type Query {
        hero: [Hero]
    }
`)

Тут дело немного изменено

4. Реализуйте логику для добавления данных и обновления данных

Чтобы разобраться с логикой добавления данных и обновления данных здесь необходимо модифицировать ранее объявленныйrootСодержание операции:

const root = {
    hero() {
        return new Promise( (resolve, reject) => {
            HeroModel.find((err, res) => {
                if(err) {
                    reject(err)
                    return
                }
                resolve(res)
            })
        })
    },
    createHero({ input }) {
        // 实例化一个Model
        const { name, age } = input
        const params = new HeroModel({ name, age })
        return new Promise( (resolve, reject) => {
            params.save((err, res) => {
                if(err) {
                    reject(err)
                    return
                }
                resolve(res)
            })
        })
    },
    updateHero({ hero, input }) {
        const { age } = input
        return new Promise ((resolve, reject) => {
            HeroModel.update({name: hero}, {age}, (err, res) => {
                if(err) {
                    reject(err)
                    return
                }
                resolve(res)
            })
        })
    }
}

5. Пробный тест

Наконец мыGraphiQLЧтобы протестировать симуляцию на странице, сначала добавьте двух героев, Железного человека и Капитана Америку, и установите ихage / nameАтрибуты:

mutation {
    createHero(input: {
        name: "钢铁侠"
        age: 40
    }){
        name
        age
    }
}
mutation {
    createHero(input: {
        name: "美国队长"
        age: 20
    }){
        name
        age
    }
}

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

graphql10

Тестируемый запрос:

query {
    hero {
        name
        age
    }
}

graphql11

Запрос тоже нормальный.Далее обновите тест и обновите Капитана АмерикуageМодифицировано до 60:

mutation {
    updateHero(hero: "美国队长", input: {
        age: 60
    }){
        age
    }
}

graphql12

На этом мы закончили упражнение.

Суммировать

  • GraphQLэтоЯзык запросов для API, замена REST API.

  • GraphQLВы можете использовать один запрос, чтобы получить все данные, которые вы хотите.

  • Есть два способа создать запрос: использоватьbuildSchemaилиGraphQLObjectType.

  • Для операции запросаQuery, для изменения операцииMutations.

  • тип запросаtype, тип ввода сinput.

фактическиGraphQLОн по-прежнему очень прост и удобен в использовании~~~


Эта статья была впервые опубликована вpingan8787 личный блог, если вам нужно перепечатать, пожалуйста, оставьте свое личное представление