GraphQL - Краткое руководство

GraphQL - это серверная технология с открытым исходным кодом, разработанная Facebook для оптимизации вызовов RESTful API. Это механизм выполнения и язык запросов данных. В этой главе мы обсудим преимущества использования GraphQL.

Почему GraphQL

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

Ниже приведены преимущества использования языка запросов GraphQL:

Просите то, что хотите - и получите

Отправьте запрос GraphQL в свой API и получите именно то, что вам нужно. Запросы GraphQL всегда возвращают предсказуемые результаты. Приложения, использующие GraphQL, быстрые и стабильные. В отличие от сервисов Restful, эти приложения могут ограничивать данные, которые должны быть получены с сервера.

Следующий пример поможет вам лучше понять это -

Рассмотрим бизнес-объект Student с атрибутами id, firstName, lastName и CollegeName . Предположим, мобильному приложению необходимо получить только firstName и id . Если мы создадим конечную точку REST, например / api / v1 / student , она в конечном итоге получит данные для всех полей для объекта Student. Это означает, что служба RESTful получает избыточные данные. Эту проблему можно решить с помощью GraphQL.

Рассмотрим запрос GraphQL, приведенный ниже -

{
   students {
      id
      firstName
   }
}

Это вернет значения только для полей id и firstname. Запрос не будет получать значения для других атрибутов объекта ученика. Ответ на запрос, проиллюстрированный выше, показан ниже -

{
   "data": {
      "students": [
         {
            "id": "S1001",
            "firstName": "Mohtashim"
         },
         {
            "id": "S1002",
            "firstName": "Kannan"
         }
      ]
   }
}

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

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

Рассмотрим еще один бизнес-объект - Колледж, у которого есть атрибуты: название и местоположение. Студенческий бизнес - объект имеет ассоциативную связь с объектом колледжа. Если бы мы использовали REST API для получения сведений о студентах и ​​их колледже, мы бы сделали два запроса к серверу, например / api / v1 / student и / api / v1 / colleges . Это приведет к недостаточной выборке данных при каждом запросе. Таким образом, мобильные приложения вынуждены совершать несколько обращений к серверу для получения нужных данных.

Однако мобильное приложение может получать сведения об объектах Student и College в одном запросе с помощью GraphQL.

Ниже приведен запрос GraphQL для извлечения данных -

{
   students{
      id
      firstName
      lastName
      college{
         name
         location
      }
   }
}

Результат вышеуказанного запроса содержит именно те поля, которые мы запросили, как показано ниже -

{
   "data": {
      "students": [
         {
            "id": "S1001",
            "firstName": "Mohtashim",
            "lastName": "Mohammad",
            "college": {
               "name": "CUSAT",
               "location": "Kerala"
            }
         },
         
         {
            "id": "S1002",
            "firstName": "Kannan",
            "lastName": "Sudhakaran",
            "college": {
               "name": "AMU",
               "location": "Uttar Pradesh"
            }
         },
         
         {
            "id": "S1003",
            "firstName": "Kiran",
            "lastName": "Panigrahi",
            "college": {
               "name": "AMU",
               "location": "Uttar Pradesh"
            }
         }
      ]
   }
}

Опишите, что возможно с системой типов

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

Пример типов данных Student и College приведен ниже -

type Query {
   students:[Student]
}

type Student {
   id:ID!
   firstName:String
   lastName:String
   fullName:String
   college:College
}

type College {
   id:ID!
   name:String
   location:String
   rating:Float
   students:[Student]
}

Двигайтесь быстрее с помощью мощных инструментов разработчика

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

В этой главе мы узнаем о настройке среды для GraphQL. Чтобы выполнить примеры в этом руководстве, вам понадобится следующее:

  • Компьютер под управлением Linux, macOS или Windows.

  • Веб-браузер, желательно последняя версия Google Chrome.

  • Установлена ​​последняя версия Node.js. Рекомендуется последняя версия LTS.

  • Visual Studio Code с установленным расширением GraphQL для VSCode или любым редактором кода по вашему выбору.

Как создать сервер GraphQL с помощью Nodejs

Мы рассмотрим подробный пошаговый подход к созданию сервера GraphQL с помощью Nodejs, как показано ниже -

Шаг 1. Проверьте версии узла и Npm

После установки NodeJs проверьте версию node и npm, используя следующие команды на терминале:

C:\Users\Admin>node -v
v8.11.3

C:\Users\Admin>npm -v
5.6.0

Шаг 2 - Создайте папку проекта и откройте в VSCode

Корневую папку проекта можно назвать test-app.

Откройте папку с помощью редактора кода Visual Studio, используя приведенные ниже инструкции -

C:\Users\Admin>mkdir test-app
C:\Users\Admin>cd test-app
C:\Users\Admin\test-app>code.

Шаг 3 - Создайте package.json и установите зависимости

Создайте файл package.json, который будет содержать все зависимости серверного приложения GraphQL.

{
   "name": "hello-world-server",
   "private": true,
   "scripts": {
      "start": "nodemon --ignore data/ server.js"
   },
   
   "dependencies": {
      "apollo-server-express": "^1.4.0",
      "body-parser": "^1.18.3",
      "cors": "^2.8.4",
      "express": "^4.16.3",
      "graphql": "^0.13.2",
      "graphql-tools": "^3.1.1"
   },
   
   "devDependencies": {
      "nodemon": "1.17.1"
   }
}

Установите зависимости, используя команду, как показано ниже -

C:\Users\Admin\test-app>npm install

Шаг 4 - Создайте базу данных плоских файлов в папке данных

На этом этапе мы используем плоские файлы для хранения и извлечения данных. Создайте папку data и добавьте два файлаstudents.json и colleges.json.

Ниже приводится colleges.json файл -

[
   {
      "id": "col-101",
      "name": "AMU",
      "location": "Uttar Pradesh",
      "rating":5.0
   },
   
   {
      "id": "col-102",
      "name": "CUSAT",
      "location": "Kerala",
      "rating":4.5
   }
]

Ниже приводится students.json файл -

[
   {
      "id": "S1001",
      "firstName":"Mohtashim",
      "lastName":"Mohammad",
      "email": "[email protected]",
      "password": "pass123",
      "collegeId": "col-102"
   },
   
   {
      "id": "S1002",
      "email": "[email protected]",
      "firstName":"Kannan",
      "lastName":"Sudhakaran",
      "password": "pass123",
      "collegeId": "col-101"
   },
   
   {
      "id": "S1003",
      "email": "[email protected]",
      "firstName":"Kiran",
      "lastName":"Panigrahi",
      "password": "pass123",
      "collegeId": "col-101"
   }
]

Шаг 5 - Создайте уровень доступа к данным

Нам нужно создать хранилище данных, которое загружает содержимое папки данных. В этом случае нам нужны переменные коллекции, студенты и колледжи . Когда приложению нужны данные, оно использует эти переменные коллекции.

Создайте файл db.js с в папке проекта следующим образом:

const { DataStore } = require('notarealdb');

const store = new DataStore('./data');

module.exports = {
   students:store.collection('students'),
   colleges:store.collection('colleges')
};

Шаг 6 - Создайте файл схемы, schema.graphql

Создайте файл схемы в папке текущего проекта и добавьте следующее содержимое -

type Query  {
   test: String
}

Шаг 7 - Создайте файл решателя, resolvers.js

Создайте файл преобразователя в папке текущего проекта и добавьте следующее содержимое -

const Query = {
   test: () => 'Test Success, GraphQL server is up & running !!'
}
module.exports = {Query}

Шаг 8 - Создайте Server.js и настройте GraphQL

Создайте файл сервера и настройте GraphQL следующим образом:

const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const db = require('./db');

const port = process.env.PORT || 9000;
const app = express();

const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})
const resolvers = require('./resolvers')

const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs, resolvers})

app.use(cors(), bodyParser.json());

const  {graphiqlExpress,graphqlExpress} = require('apollo-server-express')
app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))

app.listen(
   port, () => console.info(
      `Server started on port ${port}`
   )
);

Шаг 9 - Запустите приложение и протестируйте с помощью GraphiQL

Проверьте структуру папок тестового приложения проекта следующим образом:

test-app /
   -->package.json
   -->db.js
   -->data
      students.json
      colleges.json
   -->resolvers.js
   -->schema.graphql
   -->server.js

Запустите команду npm start, как показано ниже -

C:\Users\Admin\test-app>npm start

Сервер работает с портом 9000, поэтому мы можем протестировать приложение с помощью инструмента GraphiQL. Откройте браузер и введите URL-адрес http: // localhost: 9000 / graphiql. Введите в редакторе следующий запрос -

{
   Test 
}

Ответ сервера приведен ниже -

{
   "data": {
      "test": "Test Success, GraphQL server is running !!"
   }
}

GraphQL - это спецификация, описывающая поведение сервера GraphQL. Это набор рекомендаций о том, как должны обрабатываться запросы и ответы, такие как поддерживаемые протоколы, формат данных, которые могут быть приняты сервером, формат ответа, возвращаемого сервером, и т. Д. Запрос, сделанный клиентом к GraphQL сервер называется запросом. Еще одна важная концепция GraphQL - агностика транспортного уровня. Его можно использовать с любым доступным сетевым протоколом, таким как TCP, websocket или любым другим протоколом транспортного уровня. Он также нейтрален для баз данных, поэтому вы можете использовать его с реляционными базами данных или базами данных NoSQL.

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

  • Сервер GraphQL с подключенной базой данных
  • Сервер GraphQL, интегрирующий существующие системы
  • Гибридный подход

Сервер GraphQL с подключенной базой данных

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

На приведенной выше диаграмме сервер GraphQL и база данных интегрированы на одном узле. Клиент (настольный / мобильный) взаимодействует с сервером GraphQL через HTTP. Сервер обрабатывает запрос, извлекает данные из базы данных и возвращает их клиенту.

Сервер GraphQL, интегрирующий существующие системы

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

На приведенной выше диаграмме GraphQL API действует как интерфейс между клиентом и существующими системами. Клиентские приложения взаимодействуют с сервером GraphQL, который, в свою очередь, разрешает запрос.

Гибридный подход

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

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

  • Компоненты на стороне сервера
  • Компоненты на стороне клиента

Компоненты на стороне сервера

Сервер GraphQL является основным компонентом на стороне сервера и позволяет анализировать запросы, поступающие от клиентских приложений GraphQL. Apollo Server - это наиболее часто используемая реализация спецификации GraphQL. Другие компоненты серверного программирования включают следующее:

Sr.No. Основные сведения о сервере и описание
1

Schema

Схема GraphQL находится в центре любой реализации сервера GraphQL и описывает функции, доступные клиентам, которые к ней подключаются.

2

Query

Запрос GraphQL - это запрос клиентского приложения для извлечения данных из базы данных или устаревших API.

3

Resolver

Преобразователи предоставляют инструкции по преобразованию операции GraphQL в данные. Они разрешают запрос к данным, определяя функции преобразователя.

Компоненты на стороне клиента

Ниже приведены компоненты на стороне клиента -

Sr.No. Инструмент и описание
1

GraphiQL

Интерфейс на основе браузера для редактирования и тестирования запросов и изменений GraphQL.

2

ApolloClient

Лучший инструмент для создания клиентских приложений GraphQL. Хорошо интегрируется со всеми интерфейсами javascript.

На диаграмме ниже показан Client-Server architecture. Веб-сервер построен на платформе NodeJs и Express. Запрос к серверу Apollo GraphQL осуществляется приложением ReactJS (созданным с использованием клиентской библиотеки Apollo) или приложением браузера GraphiQL. Запрос будет проанализирован и подтвержден по схеме, определенной на сервере. Если схема запроса проходит проверку, будут выполнены связанные функции преобразователя. Сопоставитель будет содержать код для извлечения данных из API или базы данных.

В этой главе мы создадим простой API, который возвращает приветственное сообщение HelloWorld и будет обращаться к нему с помощью GraphiQL.

пример

Этот пример основан на сервере NodeJS, Express и Apollo. Мы научимся соединять все концепции вместе со следующими шагами -

Шаг 1 - Настройка Express

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

Следующим шагом будет создание папки hello-world-serverи перейдите в ту же папку из терминала. Добавьте package.json и дайте имя пакету. Поскольку этот пакет используется только для внутреннего использования, мы можем объявить его частным.

{
   "name":"hello-world-server",
   "private":true
}

Установите зависимости для сервера Express, как показано ниже -

C:\Users\Admin\hello-world-server>npm install express body-parser cors

body-parser - это промежуточный пакет, который помогает Express эффективно обрабатывать запросы HTTP Post. cors - еще один промежуточный пакет, который обрабатывает совместное использование ресурсов из разных источников.

Создать server.js файл в папке проекта и введите в нем следующее -

const bodyParser = require('body-parser')
   const cors = require('cors')
   const express = require('express')
   const port = process.env.PORT|| 9000
   const app = express()
   
   //register middleware
   app.use(bodyParser.json() , cors())
   app.listen(port, () =>  console.log(`server is up and running at ${port}`)

Чтобы проверить, запущен ли сервер Express, выполните следующий код в окне терминала -

C:\Users\Admin\hello-world-server>node server.js

Следующий вывод отображается в консоли сервера. Это показывает, что экспресс-сервер работает на порту 9000.

server is up and running at 9000

Если вы откроете браузер и наберете http://localhost:9000, вы получите следующий экран -

Чтобы остановить сервер, нажмите Ctrl + C.

Шаг 2 - Установите GraphQL и Apollo Server

Теперь, когда Express настроен, следующим шагом будет загрузка следующих зависимостей GraphQL:

  • graphql
  • graphql-tools
  • apollo-server-express@1

Мы будем использовать Apollo server v1.0, так как это стабильная версия. Введите следующие команды для установки этих зависимостей -

C:\Users\Admin\hello-world-server>npm install graphql graphql-tools apollo-server-express@1

Мы можем проверить, успешно ли установлены эти зависимости, проверив package.json файл, который мы создали ранее.

{
   "name": "hello-world-server",
   "private": true,
   
   "dependencies": {
      "apollo-server-express": "^1.4.0",
      "body-parser": "^1.18.3",
      "cors": "^2.8.4",
      "express": "^4.16.3",
      "graphql": "^0.13.2",
      "graphql-tools": "^3.1.1"
   }
}

Шаг 3 - Определите схему

Схема GraphQL определяет, какой тип объекта может быть получен из службы и какие поля у него есть. Схема может быть определена с помощьюGraphQL Schema Definition Language. Теперь добавьте следующий фрагмент кода вserver.js файл -

// Adding Type Definitions
const typeDefinition = `
   type Query  {
      greeting: String
   }

Здесь запрос содержит атрибут приветствия, который возвращает строковое значение.

Шаг 4 - Создайте резольвер

Первым шагом в создании распознавателя является добавление кода для обработки поля запроса приветствия. Это указано вresolver. Структура функции распознавателя должна соответствовать схеме. Добавьте следующий фрагмент кода вserver.js файл.

// Adding resolver
const  resolverObject = {
   Query : {
      greeting: () => 'Hello GraphQL  From TutorialsPoint !!'
   }
}

Второй шаг - связать схему и преобразователь с помощью makeExecutableSchema. Эта функция предопределена в модуле graphql-tools. Добавьте следующий фрагмент кода в server.js файл.

const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs:typeDefinition, resolvers:resolverObject})

Шаг 5 - Определите маршруты для получения данных из приложения ReactJS / GraphiQL

Добавьте следующий фрагмент кода в server.js файл -

const {graphqlExpress, graphiqlExpress} = require('apollo-server-express')

   //create routes for graphql and graphiql
   app.use('/graphql',graphqlExpress({schema}))
   
   app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))

Функция graphqlExpress помогает зарегистрировать маршрутhttp://localhost:9000/graphql. Приложение ReactJS может использовать эту конечную точку для запроса данных. Точно так же функция graphqliExpress помогает зарегистрировать маршрутhttp://localhost:9000/graphiql. Это будет использоваться клиентом браузера GraphiQL для тестирования API.

Полный код server.js приведен ниже -

const bodyParser = require('body-parser')
const cors = require('cors')
const express = require('express')
const port = process.env.PORT||9000
const app = express()

app.use(bodyParser.json() , cors())
const typeDefinition = `
type Query  {
   greeting: String
}`
const  resolverObject = {
   Query : {
      greeting: () => 'Hello GraphQL  From TutorialsPoint !!'
   }
}
const {makeExecutableSchema} = require('graphql-tools')

const schema = makeExecutableSchema({typeDefs:typeDefinition, resolvers:resolverObject})

const {graphqlExpress,graphiqlExpress} = require('apollo-server-express')

app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
app.listen(port, () =>  console.log(`server is up and running ${port}`))

Шаг 6 - Запустите приложение

Выполнить server.js используя Node.js следующим образом -

C:\Users\Admin\hello-world-server>node server.js

Шаг 7 - Протестируйте GraphQL API

Откройте браузер и введите http://localhost:9000/graphiql. На вкладке запроса GraphiQL введите следующее -

{
   greeting
}

Ответ сервера приведен ниже -

{
   "data": {
      "greeting": "Hello GraphQL From TutorialsPoint !!"
   }
}

Следующее изображение иллюстрирует ответ -

Note - Убедитесь, что используется Apollo Server Version 1.0.

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

Sr.No. Типы и описание
1

Scalar

Хранит одно значение

2

Object

Показывает, какой объект можно получить

3

Query

Тип точки входа в другие конкретные типы

4

Mutation

Точка входа для манипулирования данными

5

Enum

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

Скалярный тип

Скалярные типы - это примитивные типы данных, которые могут хранить только одно значение. Скалярные типы по умолчанию, которые предлагает GraphQL:

  • Int - 32-битное целое число со знаком

  • Float - Знаковое значение с плавающей запятой двойной точности

  • String - UTF - последовательность из 8 символов

  • Boolean - Правда или ложь

  • ID - Уникальный идентификатор, часто используемый как уникальный идентификатор для выборки объекта или как ключ для кеша.

Синтаксис для определения скалярного типа следующий:

field: data_type

Приведенный ниже фрагмент определяет поле с именем приветствие, которое возвращает значение String.

greeting: String

Тип объекта

Тип объекта является наиболее распространенным типом, используемым в схеме, и представляет собой группу полей. Каждое поле внутри типа объекта отображается на другой тип, что позволяет использовать вложенные типы. Другими словами, тип объекта состоит из нескольких скалярных типов или типов объектов.

Синтаксис для определения типа объекта приведен ниже -

type object_type_name
{
   field1: data_type
   field2:data_type 
   ....
   fieldn:data_type
}

Вы можете рассмотреть следующий фрагмент кода -

--Define an object type--

type Student {
   stud_id:ID
   firstname: String
   age: Int
   score:Float
}

--Defining a GraphQL schema--  

type Query
{
   stud_details:[Student]
}

В приведенном выше примере определяется объект типа данных Student. Поле stud_details в корневой схеме запроса вернет список объектов Student.

Тип запроса

Запрос GraphQL используется для получения данных. Это похоже на запрос ресурса в API на основе REST. Чтобы не усложнять задачу, тип запроса - это запрос, отправляемый клиентским приложением на сервер GraphQL. GraphQL используетSchema Definition Language (SDL)для определения запроса. Тип запроса - один из многих типов корневого уровня в GraphQL.

Синтаксис для определения запроса приведен ниже -

type Query {
   field1: data_type
   field2:data_type
   field2(param1:data_type,param2:data_type,...paramN:data_type):data_type
}

Пример определения запроса -

type Query  {
   greeting: String
}

Тип мутации

Мутации - это операции, отправляемые на сервер, чтобы create, update или же deleteданные. Они аналогичны командам PUT, POST, PATCH и DELETE для вызова API на основе REST.

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

Синтаксис для определения типа мутации приведен ниже -

type Mutation {
   field1: data_type
   field2(param1:data_type,param2:data_type,...paramN:data_type):data_type 
}

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

type Mutation {
   addStudent(firstName: String, lastName: String): Student
}

Тип перечисления

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

Синтаксис для определения типа Enum -

type enum_name{
   value1
   value2
}

Следующий фрагмент иллюстрирует, как можно определить тип перечисления.

type Days_of_Week{
   SUNDAY
   MONDAY
   TUESDAY
   WEDNESDAY
   THURSDAY
   FRIDAY
   SATURDAY
}

Тип списка

Списки могут использоваться для представления массива значений определенного типа. Списки определяются с помощью модификатора типа [], который охватывает типы объектов, скаляры и перечисления.

Следующий синтаксис может использоваться для определения типа списка -

field:[data_type]

В приведенном ниже примере определяется список задач типа:

type Query {
   todos: [String]
}

Тип, не допускающий NULL

По умолчанию каждый из основных скалярных типов может иметь значение null. Другими словами, эти типы могут либо возвращать значение указанного типа, либо не иметь значения. Чтобы отменить это значение по умолчанию и указать, что поле должно быть определено, к типу можно добавить восклицательный знак (!). Это гарантирует наличие ценности в результатах, возвращаемых запросом.

Следующий синтаксис может использоваться для определения поля, не допускающего значения NULL:

field:data_type!

В приведенном ниже примере stud_id объявлен как обязательное поле.

type Student {
   stud_id:ID!
   firstName:String
   lastName:String
   fullName:String
   college:College
}

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

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

В этой главе мы используем сервер Apollo для выполнения запросов GraphQL. ВmakeExecutableSchema Функция в graphql-tools помогает связать схему и преобразователи.

Синтаксис функции makeExecutableSchema

В makeExecutableSchemaфункция принимает единственный аргумент {} типа Object. Синтаксис для использования этой функции приведен ниже -

import { makeExecutableSchema } from 'graphql-tools';

const jsSchema = makeExecutableSchema({
   typeDefs,
   resolvers, // optional
   logger, // optional
   allowUndefinedInResolve = false, // optional
   resolverValidationOptions = {}, // optional
   directiveResolvers = null, // optional
   schemaDirectives = null,  // optional
   parseOptions = {},  // optional
   inheritResolversFromInterfaces = false  // optional
});

Sr.No. Параметр и описание
1

typeDefs

Это обязательный аргумент. Он представляет запрос GraphQL в виде строки UTF-8.

2

Resolvers

Это необязательный аргумент (по умолчанию пустой объект). У этого есть функции, которые обрабатывают запрос.

3

logger

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

4

parseOptions

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

5

allowUndefinedInResolve

Это верно по умолчанию. Если установлено значение false, функции разрешения выдают ошибки, если они возвращают значение undefined.

6

resolverValidationOptions

Это необязательный аргумент, он принимает объект с логическими свойствами.

7

inheritResolversFromInterfaces

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

Иллюстрация

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

Шаг 1 - Загрузите и установите необходимые зависимости для проекта

Создайте папку с именем schema-app. Измените свой каталог на schema-app из терминала. Затем выполните шаги 3–5, описанные в главе «Настройка среды», чтобы завершить загрузку и установку.

Шаг 2 - Создайте схему

Добавить schema.graphql файл в папке проекта, schema-app и добавьте следующий код -

type Query {
   greeting:String
   students:[Student]
}

type Student {
   id:ID!
   firstName:String
   lastName:String
   password:String
   collegeId:String
}

Корнем схемы будет тип запроса. В запросе есть два поля - приветствие и студенты, которые возвращают строку и список студентов соответственно. Студент объявлен как объектный тип, поскольку он содержит несколько полей. Поле идентификатора объявлено как не допускающее значения NULL.

Шаг 3 - Создайте резолвер

Создать файл resolvers.js в папке проекта и добавьте следующий код -

const db = require('./db')
const Query = {
   greeting:() => {
      return "hello from  TutorialsPoint !!!"
   },
   students:() => db.students.list()
}

module.exports = {Query}

Здесь приветствие и студенты - решатели, которые обрабатывают запрос. students resolver functionвозвращает список студентов из уровня доступа к данным. Чтобы получить доступ к функциям преобразователя вне модуля, объект запроса должен быть экспортирован с использованиемmodule.exports.

Шаг 4 - Запустите приложение

Создайте файл server.js и обратитесь к шагу 8 в главе «Настройка среды». Следующим шагом будет выполнение команды npm start в терминале. Сервер будет работать на 9000 порте. Здесь мы используем GraphiQL в качестве клиента для тестирования приложения. Откройте браузер и введите URL-адрес,http://localhost:9000/graphiql.

Введите в редакторе следующий запрос -

{
   greeting
   students {
      id
      firstName
      lastName
   }
}

Запрос отобразит вывод, как показано ниже -

Note- Мы можем заменить student.json вызовом RESTful API для получения данных учащихся или даже реальной базы данных, такой как MySQL или MongoDB. GraphQL становится тонкой оболочкой исходного уровня приложения для повышения производительности.

Resolver - это набор функций, которые генерируют ответ на запрос GraphQL. Проще говоря, преобразователь действует как обработчик запросов GraphQL. Каждая функция преобразователя в схеме GraphQL принимает четыре позиционных аргумента, как указано ниже:

fieldName:(root, args, context, info) => { result }

Пример функций преобразователя показан ниже -

//resolver function  with no parameters and returning string
greeting:() => {
   return "hello from  TutorialsPoint !!!"
}

//resolver function with no parameters and returning list
students:() => db.students.list()

//resolver function with arguments and returning object
studentById:(root,args,context,info) => {
   return db.students.get(args.id);
}

Ниже приведены позиционные аргументы и их описание -

Sr.No. Аргументы и описание
1

root

Объект, который содержит результат, возвращенный преобразователем в родительском поле.

2

args

Объект с аргументами, переданными в поле запроса.

3

context

Это объект, используемый всеми распознавателями в конкретном запросе.

4

info

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

Формат результата резолвера

Резольверы в GraphQL могут возвращать различные типы значений, как указано ниже -

Sr.No. Аргументы и описание
1

null or undefined

это означает, что объект не может быть найден

2

array

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

3

promise

преобразователи часто выполняют асинхронные действия, такие как выборка из базы данных или серверного API, поэтому они могут возвращать обещания

4

scalar or object

преобразователь также может возвращать другие значения

Иллюстрация

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

Ниже приведен пошаговый процесс создания простого приложения.

Шаг 1 - Загрузите и установите необходимые зависимости для проекта

Создайте папку с именем resolver-app. Измените свой каталог наresolver-appс терминала. Позже выполните шаги с 3 по 5 в главе «Настройка среды».

Шаг 2 - Создайте схему

Добавьте файл schema.graphql в приложение-преобразователь папки проекта и добавьте следующий код -

type Query { 
   greeting:String
   students:[Student]
   studentById(id:ID!):Student 
}

type Student {
   id:ID!
   firstName:String
   lastName:String
   password:String
   collegeId:String
}

Файл схемы показывает, что пользователь может запрашивать приветствие, студенты и studentById . Чтобы получить студентов с определенным идентификатором, мы используемdata type ID!который показывает поле уникального идентификатора, не допускающее значения NULL. Поле студентов возвращает массив студентов, а приветствие возвращает простое строковое значение.

Шаг 3 - Создайте резолвер

Создать файл resolvers.js в папке проекта и добавьте следующий код -

const db = require('./db')
const Query = {
   //resolver function for greeting
   greeting:() => {
      return "hello from  TutorialsPoint !!!"
   },
   
   //resolver function for students returns list
   students:() => db.students.list(),

   //resolver function for studentbyId
   studentById:(root,args,context,info) => {
      //args will contain parameter passed in query
      return db.students.get(args.id);
   }
}
module.exports = {Query}

Здесь studentById принимает три параметра. Как обсуждалось в этой главе, studentId можно получить из args; root будет содержать сам объект Query. Чтобы вернуть конкретного студента, нам нужно вызвать метод get с параметром id в коллекции студентов.

Здесь приветствие, студенты, studentById - это преобразователи, которые обрабатывают запрос.students resolver functionвозвращает список студентов из уровня доступа к данным. Чтобы получить доступ к функциям распознавателя вне модуля, объект Query должен быть экспортирован с помощью module.exports.

Шаг 4 - Запустите приложение

Создайте файл server.js. См. Шаг 8 в главе «Настройка среды». Выполните в терминале команду npm start. Сервер будет работать на 9000 порте. Здесь мы используем GraphiQL в качестве клиента для тестирования приложения.

Откройте браузер и введите URL-адрес, http://localhost:9000/graphiql. Введите в редакторе следующий запрос -

{  
   studentById(id:"S1001") {
      id
      firstName
      lastName
   }
}

Результат для вышеуказанного запроса показан ниже -

{
   "data": {
      "studentById": {
         "id": "S1001",
         "firstName": "Mohtashim",
         "lastName": "Mohammad"
      }
   }
}

Операция GraphQL может быть операцией чтения или записи. Запрос GraphQL используется для чтения или выборки значений, в то время как мутация используется для записи или публикации значений. В любом случае операция представляет собой простую строку, которую сервер GraphQL может анализировать и отвечать данными в определенном формате. Популярным форматом ответа, который обычно используется для мобильных и веб-приложений, является JSON.

Синтаксис для определения запроса следующий:

//syntax 1
query query_name{ someField }

//syntax 2
{ someField }

Ниже приведен пример запроса -

//query with name myQuery
query myQuery{
   greeting
}

// query without any name
{
   greeting
}

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

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

Иллюстрация 1. Запрос модели студента с настраиваемым полем

В этом примере у нас есть набор студентов, хранящихся в файле json. Каждая модель студента имеет такие поля, как firstName, lastName и id, но не fullName. Здесь мы обсудим, как сделать запрос для получения fullName всех студентов. Для этого нам нужно создать поле fullName в обоих преобразователях схем.

Давайте посмотрим, как сделать эту иллюстрацию, используя следующие шаги -

Шаг 1 - Загрузите и установите необходимые зависимости для проекта

Создайте папку с именем query-app. Измените свой каталог наquery-appс терминала. Позже выполните шаги 3–5, описанные в главе «Настройка среды».

Шаг 2 - Создайте схему

Добавить schema.graphql файл в папке проекта query-app и добавьте следующий код -

type Query {
   greeting:String
   students:[Student]
   studentById(id:ID!):Student
}

type Student {
   id:ID!
   firstName:String
   lastName:String
   fullName:String 
}

Обратите внимание, что в поле fullName нет поляstudents.jsonфайл. Однако нам нужно получить полное имя студента с помощью запроса. В этом случае fullName будет настраиваемым полем, недоступным в источнике данных.

Шаг 3 - Создайте резолвер

Создать файл resolvers.js в папке проекта и добавьте следующий код -

const db = require('./db')
const Query = {
   //resolver function for greeting
   greeting:() => {
      return "hello from  TutorialsPoint !!!"
   },
   
   //resolver function for students returns list
   students:() => db.students.list(),

   //resolver function for studentbyId
   studentById:(root,args,context,info) => {
      //args will contain parameter passed in query
      return db.students.get(args.id);
   }
}

//for each single student object returned,resolver is invoked

const Student = {
   fullName:(root,args,context,info) => {
      return root.firstName+":"+root.lastName
   }
}

module.exports = {Query,Student}

Шаг 4 - Запустите приложение

Создать server.jsфайл. См. Шаг 8 в главе «Настройка среды». Выполните в терминале команду  npm start. Сервер будет работать на 9000 порте. Здесь мы используем GraphiQL в качестве клиента для тестирования приложения.

Откройте браузер и введите URL-адрес http://localhost:9000/graphiql. Введите в редакторе следующий запрос -

{
   students{
      id
      fullName
   }
}

Ответ на запрос приведен ниже -

{
   "data": {
      "students": [
         {
            "id": "S1001",
            "fullName": "Mohtashim:Mohammad"
         },
         
         {
            "id": "S1002",
            "fullName": "Kannan:Sudhakaran"
         },
         
         {
            "id": "S1003",
            "fullName": "Kiran:Panigrahi"
         }
      ]
   }
}

Создать server.js и добавьте следующий код -

const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');

const db = require('./db');
const port = 9000;
const app = express();

//loading type definitions from schema file
const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})

//loading resolvers
const resolvers = require('./resolvers')

//binding schema and resolver
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs, resolvers})

//enabling cross domain calls and form post
app.use(cors(), bodyParser.json());

//enabling routes
const  {graphiqlExpress,graphqlExpress} = require('apollo-server-express')
app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))

//registering port
app.listen(port, () => console.info(`Server started on port ${port}`));

Выполните в терминале команду npm start. Сервер будет работать на 9000 порте. Здесь мы используем GraphiQL в качестве клиента для тестирования приложения.

Откройте браузер и введите URL http://localhost:9000/graphiql. Введите в редакторе следующий запрос -

{
   students{
      id
      fullName
   }
}

Ответ на запрос приведен ниже -

{
   "data": {
      "students": [
         {
            "id": "S1001",
            "fullName": "Mohtashim:Mohammad"
         },
         {
            "id": "S1002",
            "fullName": "Kannan:Sudhakaran"
         },
         {
            "id": "S1003",
            "fullName": "Kiran:Panigrahi"
         }
      ]
   }
}

Иллюстрация 2 - Вложенный запрос

Давайте создадим вложенный запрос для получения сведений о студентах и ​​их колледжах. Мы будем работать с той же папкой проекта.

Шаг 1 - Отредактируйте схему

В файле схемы уже есть студенческое поле. Добавим полевой колледж и определим его тип.

type College {
   id:ID!
   name:String
   location:String
   rating:Float
}

type Student {
   id:ID!
   firstName:String
   lastName:String
   fullName:String
   college:College
}

Шаг 2 - Измените resolver.js

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

const Student = {
   fullName:(root,args,context,info) => {
      return root.firstName+":"+root.lastName
   },
   college:(root) => {
      return db.colleges.get(root.collegeId);
   }
}
module.exports = {Query,Student}

Решатель возвращает значение College каждого студента, вызывая метод get из коллекции College и передавая CollegeId . У нас есть ассоциативные отношения между студентом и колледжем через collegeId .

Шаг 3 - Протестируйте приложение

Откройте окно терминала и перейдите в папку проекта. Введите команду -npm start. Запустите браузер и введите URLhttp://localhost:9000/graphiql.

Введите следующий запрос в окне GraphiQL -

{
   students{
      id
      firstName
      college {
         id
         name
         location
         rating
      }
   }
}

Ответ на запрос приведен ниже -

{
   "data": {
      "students": [
         {
            "id": "S1001",
            "firstName": "Mohtashim",
            "college": {
               "id": "col-102",
               "name": "CUSAT",
               "location": "Kerala",
               "rating": 4.5
            }
         },
         
         {
            "id": "S1002",
            "firstName": "Kannan",
            "college": {
               "id": "col-101",
               "name": "AMU",
               "location": "Uttar Pradesh",
               "rating": 5
            }
         },
         
         {
            "id": "S1003",
            "firstName": "Kiran",
            "college": {
               "id": "col-101",
               "name": "AMU",
               "location": "Uttar Pradesh",
               "rating": 5
            }
         }
      ]
   }
}

Что такое переменная запроса?

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

Иллюстрация

Давайте создадим простое приложение для понимания переменной запроса.

Шаг 1 - Редактировать файл схемы

Добавьте поле sayHello, которое принимает строковый параметр и возвращает строку. Значения имени будут динамическими в клиентском приложении.

type Query {
   sayHello(name:String!):String
}

Шаг 2 - Отредактируйте файл resolver.js

Добавьте резолвер sayHello, который принимает параметр, как показано ниже -

sayHello:(root,args,context,info) => `Hi ${args.name} GraphQL server says Hello to you!!`

Шаг 3 - Объявление переменной запроса в GraphiQL

Переменная объявляется с помощью $, за которым следует имя переменной. Например: $ myname_Variable.

Как только $ myname_Variable объявлено, его нужно использовать с синтаксисом именованного запроса. Запрос myQuery принимает строковое значение и передает его в sayHello, как показано ниже -

query myQuery($myname_Variable:String!) { sayHello(name:$myname_Variable)
}

Задайте значение для $ myname_Variable как объект JSON в разделе «Переменные запроса» клиента GraphiQL.

{
   "myname_Variable": "Mohtashim"
}

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

{
   "data": {
      "sayHello": "Hi Mohtashim GraphQL server says Hello to you!!"
   }
}

Как использовать переменную запроса с Enum

Давайте посмотрим, как использовать переменную запроса, когда параметр поля enum type.

Шаг 1. Отредактируйте файл schema.graphql

enum ColorType {
   RED
   BLUE
   GREEN
}

type Query {
   setFavouriteColor(color:ColorType):String
}

Функция setFavouriteColor принимает перечисление в качестве входных данных и возвращает строковое значение.

Шаг 2. Отредактируйте файл resolvers.js

Функция решателя setFavouriteColor получает root и args . К значению перечисления, переданному функции во время выполнения, можно получить доступ через параметр args.

setFavouriteColor:(root,args) => {
   return  "Your Fav Color is :"+args.color;
}

Шаг 3 - Объявление переменной запроса в GraphiQL

Запрос называется query_to_setColorкоторый принимает переменную с именем color_variable ColorType. Эта переменная передается в метод setFavouriteColor.

query query_to_setColor($color_variable:ColorType) {
   setFavouriteColor(color:$color_variable)
}

В разделе переменных запроса GraphiQL введите следующий код -

{
   "color_variable":"RED"
}

Ответ показан ниже -

{
   "data": {
      "setFavouriteColor": "Your Fav Color is: RED"
   }
}

В этой главе мы изучим запросы на мутацию в GraphQL.

Запросы на мутацию изменяют данные в хранилище данных и возвращают значение. Его можно использовать для вставки, обновления или удаления данных. Мутации определяются как часть схемы.

Синтаксис запроса на мутацию приведен ниже -

mutation{
   someEditOperation(dataField:"valueOfField"):returnType
}

Иллюстрация

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

Шаг 1 - Загрузите и установите необходимые зависимости для проекта

Создайте папку проекта с именем mutation-app. Измените свой каталог на приложение mutation из терминала. Выполните шаги с 3 по 5, описанные в главе «Настройка среды».

Шаг 2 - Создайте файл schema.graphql

Добавить schema.graphql файл в папке проекта mutation-app и добавьте следующий код -

type Query {
   greeting:String
}

type Mutation {
   createStudent(collegeId:ID,firstName:String,lastName:String):String
}

Обратите внимание, что функция createStudent возвращает тип String. Это уникальный идентификатор (ID), который создается после создания студента.

Шаг 3 - Создайте файл resolver.js

Создайте файл resolvers.js в папке проекта и добавьте следующий код -

const db = require('./db')
const Mutation = {
   createStudent:(root,args,context,info) => {
      return db.students.create({collegeId:args.collegeId,
      firstName:args.firstName,
      lastName:args.lastName})
   }
}
const Query = {
   greeting:() => "hello"
}

module.exports = {Query,Mutation}

Функция мутации указывает на коллекцию студентов в хранилище данных. Чтобы добавить нового студента , вызовите метод create в коллекции студентов. Объект args будет содержать параметры, которые передаются в запросе. Метод create коллекции студентов вернет идентификатор вновь созданного объекта student.

Шаг 4 - Запустите приложение

Создать server.jsфайл. См. Шаг 8 в главе «Настройка среды». Выполните в терминале команду npm start. Сервер будет работать на 9000 порте. Здесь мы используем GraphiQL в качестве клиента для тестирования приложения.

Следующим шагом является открытие браузера и ввод URL-адреса. http://localhost:9000/graphiql. Введите в редакторе следующий запрос -

//college Id should be matched with data from colleges.json for easy retrieval

mutation {
   createStudent(collegeId:"col-2",firstName:"Tim",lastName:"George")
}

Вышеупомянутый запрос создаст объект student в файле student.json. Запрос вернет уникальный идентификатор. Ответ на запрос показан ниже -

{
   "data": {
      "createStudent": "SkQtxYBUm"
   }
}

Чтобы проверить, создан ли объект ученика, мы можем использовать запрос studentById. Вы также можете открыть файл student.json из папки данных, чтобы проверить идентификатор.

Чтобы использовать запрос studentById, отредактируйте schema.graphql как указано ниже -

type Query {
   studentById(id:ID!):Student
}

type Student {
   id:ID!
   firstName:String
   lastName:String
   collegeId:String
}

Отредактируйте resolver.js файл, как указано ниже -

const db = require('./db')
const Query = {
   studentById:(root,args,context,info) => {
      return db.students.get(args.id);
   }
}

const Mutation = {
   createStudent:(root,args,context,info) => {
      return db.students.create({collegeId:args.collegeId,
      firstName:args.firstName,
      lastName:args.lastName})
   }
}

module.exports = {Query,Mutation}

Ниже приведен запрос на получение студента по уникальному идентификатору, возвращенному из запроса мутации -

{
    studentById(id:"SkQtxYBUm") {
    id
    firstName
    lastName
  }
}

Ответ от сервера следующий -

{
   "data": {
      "studentById": {
         "id": "SkQtxYBUm",
         "firstName": "Tim",
         "lastName":"George"
      }
   }
}

Возврат объекта в мутации

Лучше всего вернуть объект в состоянии мутации. Например, клиентское приложение хочет получить сведения о студентах и ​​колледжах. В этом случае, вместо того, чтобы делать два разных запроса, мы можем создать запрос, который возвращает объект, содержащий информацию о студентах и ​​их колледже.

Шаг 1 - Редактировать файл схемы

Добавьте новый метод с именем addStudent который возвращает объект в типе мутации schema.graphql.

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

type Mutation {
   addStudent_returns_object(collegeId:ID,firstName:String,lastName:String):Student

   createStudent(collegeId:ID,firstName:String,lastName:String):String
}

type College {
   id:ID!
   name:String
   location:String
   rating:Float
}

type Student {
   id:ID!
   firstName:String
   lastName:String
   college:College
}

Шаг 2. Обновите файл resolvers.js

Обновить файл resolvers.js в папке проекта и добавьте следующий код -

const Mutation = {
   createStudent:(root,args,context,info) => {

      return db.students.create({
         collegeId:args.collegeId,
         firstName:args.firstName,
         lastName:args.lastName
      })
   },
   
   // new resolver function
   addStudent_returns_object:(root,args,context,info) => {
      const id = db.students.create({
         collegeId:args.collegeId,
         firstName:args.firstName,
         lastName:args.lastName
      })

      return db.students.get(id)
   }
}

//for each single student object returned,resolver is invoked
const Student = {
   college:(root) => {
      return db.colleges.get(root.collegeId);
   }
}

module.exports = {Query,Student,Mutation}

Шаг 3 - Запустите сервер и введите запрос запроса в GraphiQL

Затем мы запустим сервер и запросим запрос в GraphiQL со следующим кодом -

mutation {
   addStudent_returns_object(collegeId:"col-101",firstName:"Susan",lastName:"George") {
      id
      firstName
      college{
         id
         name
      }
   }
}

Вышеупомянутый запрос добавляет нового студента и извлекает объект student вместе с объектом College. Это экономит круговые обращения к серверу.

Ответ такой, как указано ниже -

{
   "data": {
      "addStudent_returns_object": {
         "id": "rklUl08IX",
         "firstName": "Susan",
         "college": {
            "id": "col-101",
            "name": "AMU"
         }
      }
   }
}

При добавлении или изменении данных важно проверять вводимые пользователем данные. Например, нам может потребоваться убедиться, что значение поля всегда не равно нулю. Мы можем использовать! (non-nullable) введите маркер в GraphQL для выполнения такой проверки.

Синтаксис для использования ! маркер типа приведен ниже -

type TypeName {
   field1:String!,
   field2:String!,
   field3:Int!
}

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

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

Иллюстрация - Реализация пользовательских валидаторов

Давайте создадим форму регистрации с базовой проверкой. В форме будут поля для электронной почты, имени и пароля.

Шаг 1 - Загрузите и установите необходимые зависимости для проекта

Создайте папку с именем validation-app. Измените каталог на приложение проверки с терминала. Выполните шаги с 3 по 5, описанные в главе «Настройка среды».

Шаг 2 - Создайте схему

Добавить schema.graphql файл в папке проекта validation-app и добавьте следующий код -

type Query {
   greeting:String
}

type Mutation {
   signUp(input:SignUpInput):String
}

input SignUpInput {
   email:String!,
   password:String!,
   firstName:String!
}

Note- Мы можем использовать тип ввода SignUpInput, чтобы уменьшить количество параметров в функции signUp. Итак, функция signUp принимает только один параметр типа SignUpInput.

Шаг 3 - Создайте преобразователи

Создать файл resolvers.js в папке проекта и добавьте следующий код -

const Query = {
   greeting:() => "Hello"
}

const Mutation ={
   signUp:(root,args,context,info) => {

      const {email,firstName,password} = args.input;

      const emailExpression = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
      
      const isValidEmail =  emailExpression.test(String(email).toLowerCase())
      if(!isValidEmail)
      throw new Error("email not in proper format")

      if(firstName.length > 15)
      throw new Error("firstName should be less than 15 characters")

      if(password.length < 8 )
      throw new Error("password should be minimum 8 characters")
      
      return "success";
   }
}
module.exports = {Query,Mutation}

Функция распознавателя signUp принимает параметры email, пароль и firstName. Они будут переданы через входную переменную, чтобы к ней можно было получить доступ через args.input.

Шаг 4 - Запустите приложение

Создайте файл server.js. См. Шаг 8 в главе «Настройка среды». Выполните в терминале команду npm start . Сервер будет работать на 9000 порте. Здесь мы будем использовать GraphiQL в качестве клиента для тестирования приложения.

Откройте браузер и введите URL http://localhost:9000/graphiql. Введите в редакторе следующий запрос -

mutation doSignUp($input:SignUpInput) { signUp(input:$input)
}

Поскольку входные данные для функции регистрации являются сложным типом, нам нужно использовать переменные запроса в graphiql. Для этого нам нужно сначала дать имя запросу и вызвать его doSignUp, $ input - это переменная запроса.

Следующая переменная запроса должна быть введена на вкладке переменных запроса в graphiql -

{
   "input":{
      "email": "abc@abc",
      "firstName": "kannan",
      "password": "pass@1234"
   }
}

Массив ошибок содержит подробную информацию об ошибках проверки, как показано ниже -

{
   "data": {
      "signUp": null
   },
   
   "errors": [
      {
         "message": "email not in proper format",
         "locations": [
            {
               "line": 2,
               "column": 4
            }
         ],
         "path": [
            "signUp"
         ]
      }
   ]
}

Мы должны ввести правильный ввод для каждого поля, как указано ниже -

{
   "input":{
      "email": "[email protected]",
      "firstName": "kannan",
      "password": "pass@1234"
   }
}

Ответ следующий -

{
   "data": {
      "signUp": "success"
   }
}

Здесь, в запросе ниже, мы не назначаем пароль.

{
   "input":{
      "email": "[email protected]",
      "firstName": "kannan"
   }
}

Если обязательное поле не указано, то сервер qraphql отобразит следующую ошибку:

{
   "errors": [
      {
         "message": "Variable \"$input\" got invalid value {\"email\":\"[email protected]\",\"firstName\":\"kannan\"}; Field value.password of required type String! was not provided.",
         "locations": [
            {
               "line": 1,
               "column": 19
            }
         ]
      }
   ]
}

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

Рассмотрим приложение, использующее архитектуру клиент-сервер. Мы можем создать интерфейсную веб-страницу, которая запрашивает данные с сервера GraphQL. Веб-страница будет выполнять вызовы AJAX с помощью jQuery на сервер GraphQL.

Чтобы интегрировать GraphQL с JQuery, давайте проверим заголовки запросов GraphiQL и разберемся с параметрами запроса.

Начать hello-worldapp (см. соответствующую иллюстрацию в главе 6). Введите запрос graphql {приветствие} в окне GraphiQL. Щелкните правой кнопкой мыши и проверьте или нажмите (ctrl + shift + I) на Chrome, чтобы перейти на вкладку сети, как показано ниже -

От простого hello-world пример, мы можем понять, что http method используется POST. Теперь в браузере прокрутите вниз до раздела заголовка, чтобы просмотреть  полезные данные запроса .

Как только вы нажмете на view code, вы увидите следующее в разделе полезных данных запроса chrome.

{"query":"{\n  greeting\n}","variables":null,"operationName":null}

Также обратите внимание на URL-адрес запроса, http://localhost:9000/graphql который должен вызываться из клиентского приложения.

Иллюстрация

Давайте разберемся, как интегрировать GraphQL с JQuery, используя пошаговый процесс.

Настройка сервера

Мы научимся настраивать сервер, используя следующие шаги -

Шаг 1 - Загрузите и установите необходимые зависимости для проекта

Создайте папку с именем jquery-server-app. Измените свой каталог на jquery-server-app из терминала. Выполните шаги с 3 по 5, описанные в главе «Настройка среды».

Шаг 2 - Создайте схему

Добавьте файл schema.graphql в папку проекта jquery-server-app и добавьте следующий код -

type Query
{
   greeting: String
   sayHello(name:String!):String
}

В файле определены два запроса greeting и sayHello. Запрос sayHello принимает строковый параметр и возвращает другую строку. Параметр функции sayHello () не равен нулю.

Шаг 3 - Создайте преобразователи

Создайте файл resolvers.js в папке проекта и добавьте следующий код -

const Query =
{
   greeting: () => 'Hello GraphQL  From TutorialsPoint !!' ,
   sayHello:(root,args,context,info) =>  `Hi ${args.name} GraphQL server says Hello to you!!`
}
module.exports = {Query}

Вот, greeting и sayHelloдва резольвера. В преобразователе sayHello значение, переданное параметру name, можно получить с помощью args. Чтобы получить доступ к функциям преобразователя вне модуля, объект запроса должен быть экспортирован с использованиемmodule.exports.

Шаг 4 - Запустите приложение

Создайте файл server.js. См. Шаг 8 в главе «Настройка среды». Выполните в терминале команду npm start . Сервер будет работать на 9000 порте. Здесь мы используем GraphiQL в качестве клиента для тестирования приложения.

Откройте браузер и введите URL-адрес http://localhost:9000/graphiql. Введите в редакторе следующий запрос -

{
   greeting,
   sayHello(name:"Mohtashim")
}

Ответ сервера приведен ниже -

{
   "data": {
      "greeting": "Hello GraphQL From TutorialsPoint !!",
      "sayHello": "Hi Mohtashim GraphQL server says Hello to you!!"
   }
}

Настройка клиента

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

Шаг 1. Создайте новую папку jquery-client-app вне папки текущего проекта.

Сначала мы создадим папку с именем jquery-client-app вне папки проекта.

Шаг 2. Создайте HTML-страницу index.html для интеграции с jQuery.

Мы создадим клиентское приложение в jquery и вызовем оба метода. Ниже приведен код для index.html файл. В index.html страница отправляет запросы на сервер, когда кнопки - Greet и SayHelloнажаты. Мы сделаем асинхронный запрос, используя функцию $ .ajax ().

<!DOCTYPE html>
<html>
   <head>
      <script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
      <script>
         $(document).ready(function() { $("#btnSayhello").click(function() {

               const name = $("#txtName").val(); console.log(name); $("#SayhelloDiv").html('loading....');

               $.ajax({url: "http://localhost:9000/graphql", contentType: "application/json",type:'POST', data: JSON.stringify({ query:`{ sayHello(name:"${name}")}`
                  }),
                  success: function(result) {
                     console.log(JSON.stringify(result))
                     $("#SayhelloDiv").html("<h1>"+result.data.sayHello +"</h1>"); } }); }); $("#btnGreet").click(function() {
               $("#greetingDiv").html('loading....'); //https://kannan-first-graphql-app.herokuapp.com/graphql $.ajax({url: "http://localhost:9000/graphql",
                  contentType: "application/json",
                  type:'POST',
                  data: JSON.stringify({
                     query:`{greeting}`
                  }),
                  success: function(result) {
                     $("#greetingDiv").html("<h1>"+result.data.greeting+"</h1>");
                  }
               });
            });
         });
      </script>
   </head>
   
   <body>
      <h1>Jquery Client </h1>

      <hr/>
      <section>
         <button id = "btnGreet">Greet</button>
         <br/> <br/>
         <div id = "greetingDiv"> </div>
      </section>
      
      <br/> <br/> <br/>
      <hr/>

      <section>
         Enter a name:<input id = "txtName" type = "text" value = "kannan"/>
         <button id = "btnSayhello">SayHello</button>
         <div id = "SayhelloDiv"> </div>
      </section>
   </body>
</html>

Откройте этот файл в браузере и нажмите кнопку, чтобы увидеть ответ. Результат будет таким, как указано ниже -

React - это библиотека Javascript для создания пользовательских интерфейсов. В этой главе объясняется, как можно интегрировать GraphQL с приложением React.

Иллюстрация

Самый быстрый способ настроить проект React - использовать   инструмент Create React App . В следующих разделах мы узнаем, как настроить Сервер и Клиент.

Настройка сервера

Для настройки сервера выполните следующие действия:

Шаг 1 - Загрузите и установите необходимые зависимости для проекта

Создать папку react-server-app. Измените свой каталог на react-server-app с терминала. Выполните шаги с 3 по 5, описанные в главе «Настройка среды».

Шаг 2 - Создайте схему

Добавить schema.graphql файл в папке проекта react-server-app и добавьте следующий код -

type Query
{
   greeting: String
   sayHello(name:String!):String
}

В файле определены два запроса - приветствие и sayHello. Запрос sayHello принимает строковый параметр и возвращает другую строку. Параметр функции sayHello () не равен нулю.

Шаг 3 - Создайте преобразователи

Создать файл resolvers.js в папке проекта и добавьте следующий код -

const Query =
{
   greeting: () => 'Hello GraphQL  From TutorialsPoint !!' ,
   sayHello:(root,args,context,info) =>  `Hi ${args.name} GraphQL server says Hello to you!!`
}
module.exports = {Query}

Здесь Hello и SayHello - два преобразователя. В резолвере sayHello значение, переданное параметру name, можно получить через args. Чтобы получить доступ к функциям распознавателя вне модуля, объект Query должен быть экспортирован с помощью module.exports.

Шаг 4 - Запустите приложение

Создайте файл server.js. См. Шаг 8 в главе «Настройка среды». Выполните в терминале команду npm start . Сервер будет работать на 9000 порте. Здесь мы используем GraphiQL в качестве клиента для тестирования приложения.

Откройте браузер и введите URL-адрес http://localhost:9000/graphiql. Введите в редакторе следующий запрос -

{
   greeting,
   sayHello(name:"Mohtashim")
}

Ответ сервера приведен ниже -

{
   "data": {
      "greeting": "Hello GraphQL  From TutorialsPoint !!",
      "sayHello": "Hi Mohtashim GraphQL server says Hello to you!!"
   }
}

Настройка клиента

Откройте новый терминал для клиента. Перед запуском клиентского приложения серверный терминал должен быть запущен. Приложение React будет работать на порту с номером 3000, а серверное приложение - на порту с номером 9000.

Шаг 1. Создайте проект на React hello-world-client

В клиентском терминале введите следующую команду -

npx create-react-app hello-world-client

Это установит все необходимое для типичного реагирующего приложения. Вnpx полезность и create-react-appинструмент создать проект с именем hello-world-client. После завершения установки откройте проект в VSCode.

Шаг 2 - Запустите hello-world-client

Измените текущий путь к папке в терминале на hello-world-client. Введите npm start, чтобы запустить проект. Это запустит сервер разработки на порту 3000, автоматически откроет браузер и загрузит страницу индекса.

Это показано на скриншоте ниже -

Шаг 3 - Измените компонент приложения

В папке App.js внутри src добавьте две функции: одну для загрузки приветствия, а другую - для загрузки сообщений sayHello.

Ниже приведена функция loadGreeting, которая отправляет запрос GraphQL для приветствия.

async function loadGreeting() {
   const response = await fetch('http://localhost:9000/graphql', {
      method:'POST',

      headers:{'content-type':'application/json'},
      body:JSON.stringify({query:'{greeting}'})
   })

   const rsponseBody = await response.json();
   return rsponseBody.data.greeting;

   console.log("end of function")
}

Ниже приводится loadSayhello функция, которая отправляет запрос GraphQL для sayHello -

async function  loadSayhello(name) {
   const response = await fetch('http://localhost:9000/graphql', {
      method:'POST',
      headers:{'content-type':'application/json'},
      body:JSON.stringify({query:`{sayHello(name:"${name}")}`})
   })
}

Полный App.js файл показан ниже -

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

async function loadGreeting() {
   const response =  await fetch('http://localhost:9000/graphql', {
      method:'POST',
      headers:{'content-type':'application/json'},
      body:JSON.stringify({query:'{greeting}'})
   })
   const rsponseBody =  await response.json();
   return rsponseBody.data.greeting;
   console.log("end of function")
}

async function  loadSayhello(name) {
   const response =  await fetch('http://localhost:9000/graphql', {
      method:'POST',
      headers:{'content-type':'application/json'},
      body:JSON.stringify({query:`{sayHello(name:"${name}")}`})
   })
   const rsponseBody =  await response.json();
   return rsponseBody.data.sayHello;
}

class App extends Component {
   constructor(props) {
      super(props);
      this.state =  {greetingMessage:'',sayHelloMessage:'',userName:''}
      this.updateName =  this.updateName.bind(this);
      this.showSayHelloMessage =  this.showSayHelloMessage.bind(this);
      this.showGreeting =  this.showGreeting.bind(this);
   }
   
   showGreeting() {
      loadGreeting().then(g => this.setState({greetingMessage:g+" :-)"}))
   }
   
   showSayHelloMessage() {
      const name = this.state.userName;
      console.log(name)
      loadSayhello(name).then(m => this.setState({sayHelloMessage:m}))
   }
   
   updateName(event) {
      this.setState({userName:event.target.value})
   }
   render() {
      return (
         <div className = "App">
            <header className = "App-header">
               <img src = {logo} className = "App-logo" alt = "logo" />
               <h1 className = "App-title">Welcome to React</h1>
            </header>
            <br/><br/>
            <section>
               <button id = "btnGreet" onClick = {this.showGreeting}>Greet</button>
               <br/> <br/>
               <div id = "greetingDiv">
                  <h1>{this.state.greetingMessage}</h1>
               </div>
            </section>
            
            <hr/>
            
            <section>
               Enter a name:<input id = "txtName" type = "text" onChange = {this.updateName}
               value = {this.state.userName}/>
               <button id = "btnSayhello" onClick = {this.showSayHelloMessage}>SayHello</button>
               <br/>
               user name is:{this.state.userName}    <br/>
               <div id = "SayhelloDiv">
                  <h1>{this.state.sayHelloMessage}</h1>
               </div>
            </section>
         </div>
      );
   }
}

export default App;

Когда оба приложения запустятся, нажмите кнопку приветствия. Затем введите имя в текстовое поле и нажмите кнопку SayHello. Результат будет таким, как указано ниже -

Мы использовали Apollo Server для создания спецификации graphql на стороне сервера. Создать готовый к работе сервер GraphQL можно быстро и легко. Теперь давайте разберемся с клиентской стороной.

Apollo Client - лучший способ использовать GraphQL для создания клиентских приложений. Клиент разработан, чтобы помочь разработчику быстро создать пользовательский интерфейс, который извлекает данные с помощью GraphQL и может использоваться с любым интерфейсом JavaScript.

Клиент Apollo поддерживает следующие платформы -

Sr.No. Платформа и фреймворк
1

Javascript

Реагировать, Угловой, Vue, Метеор, Ember

2

WebComponents

Полимер, лит-аполлон

3

Native Mobile

Родной Android с Java, Родной iOS с Swift

Кэширование - одна из основных функций Apollo Client. apollo-boost - удобный пакет, который включает в себя множество других зависимостей.

Иллюстрация

Давайте посмотрим, как использовать Apollo Client для создания клиентских приложений, выполнив следующие шаги:

Настройка сервера

Мы должны выполнить следующие шаги для настройки сервера -

Шаг 1 - Загрузите и установите необходимые зависимости для проекта

Создайте папку apollo-server-app. Измените свой каталог на apollo-server-app с терминала. Затем выполните шаги с 3 по 5, описанные в главе «Настройка среды».

Шаг 2 - Создайте схему

Добавить schema.graphql файл в папке проекта apollo-server-app и добавьте следующий код -

type Query
{
   students:[Student]
}

type Student {
   id:ID!
   firstName:String
   lastName:String
   college:College
}

type College {
   id:ID!
   name:String
   location:String
   rating:Float
}

Шаг 3 - Добавьте решатели

Создать файл resolvers.js в папке проекта и добавьте следующий код -

const db = require('./db')

const Query = {
   //resolver function for students returns list
   students:() => db.students.list(),
}

const Student = {
   college:(root) => {
      return db.colleges.get(root.collegeId);
   }
}
module.exports = {Query,Student}

Шаг 4 - Запустите приложение

Создать server.jsфайл. См. Шаг 8 в главе «Настройка среды». Выполните  в терминале команду  npm start . Сервер будет работать на 9000 порте. Здесь мы будем использовать GraphiQL в качестве клиента для тестирования приложения.

Откройте браузер и введите URL-адрес http://localhost:9000/graphiql. Введите в редакторе следующий запрос.

{
   students{
      id
      firstName
      college{
         name
      }
   }
}

Ответ на запрос приведен ниже -

{
   "data": {
      "students": [
         {
            "id": "S1001",
            "firstName": "Mohtashim",
            "college": {
               "name": "CUSAT"
            }
         },
         
         {
            "id": "S1002",
            "firstName": "Kannan",
            "college": {
               "name": "AMU"
            }
         },
         
         {
            "id": "S1003",
            "firstName": "Kiran",
            "college": {
               "name": "AMU"
            }
         }
      ]
   }
}

Настройка клиента

Откройте новый терминал для клиента. Перед запуском клиентского приложения серверный терминал должен быть запущен. Приложение React будет работать на порту с номером 3000, а серверное приложение - на порту с номером 9000.

Шаг 1. Создайте приложение React

В клиентском терминале введите следующую команду -

npx create-react-app hello-world-client

Это установит все необходимое для типичного реагирующего приложения. Утилита npx и инструмент create-react-app создают проект с именемhello-world-client. После завершения установки откройте проект в VSCode.

Шаг 2 - Запустите hello-world-client

Измените текущий путь к папке в терминале на hello-world-client. Введите npm start, чтобы запустить проект. Это запустит сервер разработки на порту 3000, автоматически откроет браузер и загрузит страницу индекса.

Это показано на скриншоте ниже -

Шаг 3 - Установите клиентские библиотеки Apollo

Чтобы установить клиент Apollo, откройте новый терминал и перейдите в текущий путь к папке проекта. Введите следующую команду -

npm install apollo-boost graphql

Это загрузит библиотеки graphql для клиентской стороны, а также пакет Apollo Boost. Мы можем проверить это, набрав npm view в зависимостях apollo-boost. У этого будет много зависимостей, как показано ниже -

{
   'apollo-cache': '^1.1.15',
   'apollo-cache-inmemory': '^1.2.8',
   'apollo-client': '^2.4.0',
   'apollo-link': '^1.0.6',
   'apollo-link-error': '^1.0.3',
   'apollo-link-http': '^1.3.1',
   'apollo-link-state': '^0.4.0',
   'graphql-tag': '^2.4.2'
}

Мы ясно видим, что библиотека Apollo-Client установлена.

Шаг 4. Измените компонент приложения в файле index.js.

С Apollo Client мы можем напрямую вызывать сервер без использования API выборки. Кроме того, запросы и изменения не следует включать в строку, созданную с использованием обратного тика. Это потому, чтоgqlфункция напрямую анализирует запросы. Это означает, что программист может напрямую писать запросы таким же образом при написании запросов в инструменте GraphiQL. gql - это функция тега, которая будет анализировать строку шаблона, записанную в нотации обратного тика, в объект запроса graphql. Метод запроса клиента Apollo возвращает обещание.

В следующем фрагменте кода показано, как импортировать Apollo Client.

import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'

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

В предыдущей главе мы обсудили, как использовать fetch API для HTTP-запросов. Следующий код показывает, как использоватьgqlфункция. ВloadStudentsAsync функция использует клиент graphql для запроса сервера.

async function loadStudentsAsync() {
   const query = gql`
   {
      students{
         id
         firstName
         lastName
         college{
            name
         }
      }
   }`
   const {data} = await client.query({query}) ;
   return data.students;
}

Вам нужно только сохранить index.js в srcпапка и index.html в общей папке; все остальные файлы, которые создаются автоматически, могут быть удалены.

Структура каталогов приведена ниже -

hello-world-client /
   -->node_modules
   -->public
         index.html
   -->src
         index.js
   -->package.json

Ниже приводится index.js в приложении реакции -

import React, {Component} from 'react';
import ReactDOM from 'react-dom';

// apollo client

import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
import gql from 'graphql-tag'

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

async function loadStudentsAsync() {
   const query = gql`
   {
      students{
         id
         firstName
         lastName
         college{
            name
         }
      }
   }
   `
   const {data} = await client.query({query}) ;
   return data.students;
}
class  App  extends Component {
   constructor(props) {
      super(props);
      this.state = {
         students:[]
      }
      this.studentTemplate =  [];
   }
   async loadStudents() {
      const studentData =  await loadStudentsAsync();
      this.setState({
         students: studentData
      })
      console.log("loadStudents")
   }
   render() {
      return(
         <div>
            <input type = "button"  value = "loadStudents" onClick = {this.loadStudents.bind(this)}/>
            <div>
               <br/>
               <hr/>
               <table border = "3">
                  <thead>
                     <tr>
                        <td>First Name</td>
                        <td>Last Name</td>
                        <td>college Name</td>
                     </tr>
                  </thead>
                  
                  <tbody>
                     {
                        this.state.students.map(s => {
                           return (
                              <tr key = {s.id}>
                                 <td>
                                    {s.firstName}
                                 </td>
                                 <td>
                                    {s.lastName}
                                 </td>
                                 <td>
                                    {s.college.name}
                                 </td>
                              </tr>
                           )
                        })
                     }
                  </tbody>
               </table>
            </div>
         </div>
      )
   }
}
ReactDOM.render(<App/>, document.getElementById('root'));

Приложение реакции загрузит студентов с сервера GraphQL, как только мы нажмем кнопку loadStudents, как показано ниже -

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

Экспресс JWT

В этом примере мы будем использовать jQuery для создания клиентского приложения. Для аутентификации запросов мы будем использовать express-jwt модуль на стороне сервера.

Модуль express-jwt - это промежуточное ПО, которое позволяет аутентифицировать HTTP-запросы с помощью токенов JWT. Веб-токен JSON (JWT) - это длинная строка, которая идентифицирует вошедшего в систему пользователя.

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

Иллюстрация

Чтобы понять эту иллюстрацию, мы будем следовать пошаговой процедуре.

Настройка сервера

Ниже приведены шаги по настройке сервера -

Шаг 1 - Загрузите и установите необходимые зависимости для проекта

Создать папку auth-server-app. Измените свой каталог на auth-server-app с терминала. Выполните шаги с 3 по 5, описанные в главе «Настройка среды».

Шаг 2 - Создайте схему

schema.graphql auth-server-app
type Query
{
   greetingWithAuth:String
}

Шаг 3 - Добавьте решатели

Создать файл resolvers.js в папке проекта и добавьте следующий код -

Сопоставитель проверит, доступен ли объект аутентифицированного пользователя в объекте контекста GraphQL. Это вызовет исключение, если аутентифицированный пользователь недоступен.

const db = require('./db')

const Query = {
   greetingWithAuth:(root,args,context,info) => {

      //check if the context.user is null
      if (!context.user) {
         throw new Error('Unauthorized');
      }
      return "Hello from TutorialsPoint, welcome back : "+context.user.firstName;
   }
}

module.exports = {Query}

Шаг 4 - Создайте файл Server.js

ПО промежуточного слоя аутентификации аутентифицирует вызывающих абонентов с помощью веб-токена JSON. URL для аутентификации http://localhost:9000/login.

Это почтовая операция. Пользователь должен отправить свой адрес электронной почты и пароль, который будет подтвержден серверной частью. Если действительный токен создается с использованием метода jwt.sign, клиент должен будет отправить его в заголовке для последующих запросов.

Если токен действителен, req.user будет установлен с объектом JSON, декодированным для использования последующим промежуточным программным обеспечением для авторизации и контроля доступа.

В следующем коде для аутентификации запросов используются два модуля - jsonwebtoken и express-jwt.

  • Когда пользователь нажимает на greetвыдается запрос на маршрут / graphql. Если пользователь не аутентифицирован, ему будет предложено пройти аутентификацию.

  • Пользователю предоставляется форма, которая принимает идентификатор электронной почты и пароль. В нашем примере за аутентификацию пользователя отвечает маршрут / login.

  • Маршрут / login проверяет, найдено ли совпадение в базе данных для учетных данных, предоставленных пользователем.

  • Если учетные данные недействительны, пользователю возвращается исключение HTTP 401.

  • Если учетные данные действительны, сервер генерирует токен. Этот токен отправляется как часть ответа пользователю. Это делает функция jwt.sign.

const expressJwt = require('express-jwt');
const jwt = require('jsonwebtoken');

//private key
const jwtSecret = Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');

app.post('/login', (req, res) => {
   const {email, password} = req.body;
   
   //check database
   const user = db.students.list().find((user) =>  user.email === email);
   if (!(user && user.password === password)) {
      res.sendStatus(401);
      return;
   }
   
   //generate a token based on private key, token doesn't have an expiry
   const token = jwt.sign({sub: user.id}, jwtSecret);
   res.send({token});
});

Для каждого запроса будет вызываться функция app.use (). Это, в свою очередь, вызовет промежуточное программное обеспечение expressJWT. Это промежуточное программное обеспечение будет декодировать веб-токен JSON. Идентификатор пользователя, хранящийся в токене, будет извлечен и сохранен как пользователь свойства в объекте запроса.

//decodes the JWT and stores in request object
app.use(expressJwt({
   secret: jwtSecret,
   credentialsRequired: false
}));

Чтобы сделать доступным свойство пользователя в контексте GraphQL, это свойство присваивается объекту context объект, как показано ниже -

//Make req.user available to GraphQL context
app.use('/graphql', graphqlExpress((req) => ({
   schema,
   context: {user: req.user &&apm; db.students.get(req.user.sub)}
})));

Создайте server.js в текущем пути к папке. Полный файл server.js выглядит следующим образом:

const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const expressJwt = require('express-jwt'); //auth
const jwt = require('jsonwebtoken'); //auth
const db = require('./db');

var port = process.env.PORT || 9000
const jwtSecret = Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');
const app = express();

const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})
const resolvers = require('./resolvers')
const {makeExecutableSchema} = require('graphql-tools')

const schema = makeExecutableSchema({typeDefs, resolvers})

app.use(cors(), bodyParser.json(), expressJwt({
   secret: jwtSecret,
   credentialsRequired: false
}));

const  {graphiqlExpress,graphqlExpress} = require('apollo-server-express')

app.use('/graphql', graphqlExpress((req) => ({
   schema,
   context: {user: req.user && db.students.get(req.user.sub)}
})));
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))

//authenticate students
app.post('/login', (req, res) => {
   const email = req.body.email;
   const password = req.body.password;

   const user = db.students.list().find((user) =>  user.email === email);
   if (!(user && user.password === password)) {
      res.sendStatus(401);
      return;
   }
   const token = jwt.sign({sub: user.id}, jwtSecret);
   res.send({token});
});

app.listen(port, () => console.info(`Server started on port ${port}`));

Шаг 5 - Запустите приложение

Выполните в терминале команду  npm start. Сервер будет работать на 9000 порте. Здесь мы используем GraphiQL в качестве клиента для тестирования приложения.

Откройте браузер и введите URL-адрес http://localhost:9000/graphiql. Введите в редакторе следующий запрос -

{
   greetingWithAuth
}

В ответе ниже мы получили сообщение об ошибке, так как мы не авторизованный пользователь.

{
   "data": {
      "greetingWithAuth": null
   },
   "errors": [
      {
         "message": "Unauthorized",
         "locations": [
            {
               "line": 2,
               "column": 3
            }
         ],
         "path": [
            "greetingWithAuth"
         ]
      }
   ]
}

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

Настройка клиента JQuery

В клиентском приложении предусмотрена кнопка приветствия, которая будет вызывать схему. greetingWithAuth. Если вы нажмете кнопку без входа в систему, появится сообщение об ошибке, как показано ниже -

После входа в систему с пользователем, доступным в базе данных, появится следующий экран -

Чтобы получить доступ greeting, нам нужно сначала получить доступ к URL-адресу http://localhost:9000/login маршрут, как показано ниже.

Ответ будет содержать токен, сгенерированный сервером.

$.ajax({
   url:"http://localhost:9000/login",
   contentType:"application/json",
   type:"POST",
   data:JSON.stringify({email,password}),
   success:function(response) {
      loginToken = response.token;
      $('#authStatus') .html("authenticated successfully") .css({"color":"green",'font-weight':'bold'}); $("#greetingDiv").html('').css({'color':''});
   },
   error:(xhr,err) =>  alert('error')
})

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

{ 
   url: "http://localhost:9000/graphql",
   contentType: "application/json",
   headers: {"Authorization": 'bearer '+loginToken},  type:'POST',
   data: JSON.stringify({
   query:`{greetingWithAuth}`
}

Ниже приведен код для index.html -

<!DOCTYPE html>
<html>
   <head>
      <script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
      <script>
         $(document).ready(function() { let loginToken = ""; $("#btnGreet").click(function() {
                  $.ajax({url: "http://localhost:9000/graphql", contentType: "application/json", headers: {"Authorization": 'bearer '+loginToken}, type:'POST', data: JSON.stringify({ query:`{greetingWithAuth}` }), success: function(result) { $("#greetingDiv").html("<h1>"+result.data.greetingWithAuth+"</h1>")
                  },
                  error:function(jQxhr,error) {
                     if(jQxhr.status == 401) {
                        $("#greetingDiv").html('please authenticate first!!') .css({"color":"red",'font-weight':'bold'}) return; } $("#greetingDiv").html('error').css("color","red");
                  }
               });
            });
            $('#btnAuthenticate').click(function() { var email = $("#txtEmail").val();
               var password =  $("#txtPwd").val(); if(email && password) { $.ajax({
                     url:"http://localhost:9000/login",
                     contentType:"application/json",
                     type:"POST",
                     data:JSON.stringify({email,password}),
                     success:function(response) {
                        loginToken =  response.token;
                        $('#authStatus') .html("authenticated successfully") .css({"color":"green",'font-weight':'bold'}); $("#greetingDiv").html('').css({'color':''});
                     },
                     error:(xhr,err) =>  alert('error')
                  })
               }else alert("email and pwd empty")
            })
         });
      </script>
   </head>
   
   <body>
      <h1> GraphQL Authentication </h1>
      <hr/>
      <section>
         <button id = "btnGreet">Greet</button>
         <br/> <br/>
         <div id = "greetingDiv"></div>
      </section>
      <br/> <br/> <br/>
      <hr/>
      
      <section id = "LoginSection">
         <header>
            <h2>*Login first to  access greeting </h2>
         </header>
         <input type = "text" value = "[email protected]" placeholder = "enter email" id = "txtEmail"/>
         <br/>
         
         <input type = "password" value = "pass123" placeholder = "enter password" id = "txtPwd"/>
         <br/>
         
         <input type = "button" id = "btnAuthenticate"  value = "Login"/>
         <p id = "authStatus"></p>
      </section>
   </body>
</html>

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

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

Кэш InMemory

InMemoryCache - это нормализованное хранилище данных, обычно используемое в клиентских приложениях GraphQL без использования других библиотек, таких как Redux.

Пример кода для использования InMemoryCache с ApolloClient приведен ниже -

import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
const cache = new InMemoryCache();

const client = new ApolloClient({
   link: new HttpLink(),
   cache
});

Конструктор InMemoryCache принимает необязательный объект конфигурации со свойствами для настройки вашего кеша.

Sr.No. Параметр и описание
1

addTypename

Логическое значение, определяющее, следует ли добавлять в документ __typename (по умолчанию: true)

2

dataIdFromObject

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

3

fragmentMatcher

По умолчанию InMemoryCache использует эвристический сопоставитель фрагментов.

4

cacheRedirects

Карта функций для перенаправления запроса к другой записи в кэше до того, как запрос будет выполнен.

Иллюстрация

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

Мы также будем запрашивать время сервера, используя getTimeполе, чтобы проверить, кэширована ли страница. Если данные возвращаются из кеша, на странице будет отображаться время самого первого запроса, отправленного на сервер. Если данные являются результатом нового запроса, отправленного на сервер, всегда будет отображаться последнее время с сервера.

Настройка сервера

Ниже приведены шаги по настройке сервера -

Шаг 1 - Загрузите и установите необходимые зависимости для проекта

Создать папку cache-server-app. Измените свой каталог на cache-server-app с терминала. Выполните шаги с 3 по 5, описанные в главе «Настройка среды».

Шаг 2 - Создайте схему

Добавить schema.graphql файл в папке проекта cache-server-app и добавьте следующий код -

type Query {
   students:[Student]
   getTime:String
}

type Student {
   id:ID!
   firstName:String
   lastName:String
   fullName:String
}

Шаг 3 - Добавьте решатели

Создайте файл resolvers.js в папке проекта и добавьте следующий код -

const db = require('./db')

const Query = {
      students:() => db.students.list(),
      getTime:() => {
      const today = new Date();
      var h = today.getHours();
      var m = today.getMinutes();
      var s = today.getSeconds();
      return `${h}:${m}:${s}`;
   }
}
module.exports = {Query}

Шаг 4 - Запустите приложение

Создайте файл server.js. См. Шаг 8 в главе «Настройка среды». Выполните в терминале команду npm start . Сервер будет работать на 9000 порте. Здесь мы будем использовать GraphiQL в качестве клиента для тестирования приложения.

Откройте браузер и введите URL http://localhost:9000/graphiql. Введите в редакторе следующий запрос -

{
   getTime
   students {
      id
      firstName
   }
}

В образце ответа показаны имена студентов и время сервера.

{
   "data": {
      "getTime": "22:18:42",
      "students": [
         {
            "id": "S1001",
            "firstName": "Mohtashim"
         },
         {
            "id": "S1002",
            "firstName": "Kannan"
         },
         {
            "id": "S1003",
            "firstName": "Kiran"
         }
      ]
   }
}

Настройка клиента ReactJS

Откройте новый терминал для клиента. Перед запуском клиентского приложения серверный терминал должен быть запущен. Приложение React будет работать на порту с номером 3000, а серверное приложение - на порту с номером 9000.

Шаг 1. Создайте приложение React

В клиентском терминале введите следующую команду -

npx create-react-app hello-world-client

Это установит все необходимое для типичного реагирующего приложения. Вnpx utility и create-react-appинструменты создают проект с именем hello-world-client. После завершения установки откройте проект в VSCode.

Установите модули маршрутизатора для реакции, используя следующую команду - npm install react-router-dom.

Шаг 2 - Запустите hello-world-client

Измените текущий путь к папке в терминале на hello-world-client. Введите npm start, чтобы запустить проект. Это запустит сервер разработки на порту 3000, автоматически откроет браузер и загрузит страницу индекса.

Это показано на скриншоте ниже -

Шаг 3 - Установите клиентские библиотеки Apollo

Чтобы установить клиент Apollo, откройте новый терминал и перейдите в текущий путь к папке проекта. Введите следующую команду -

npm install apollo-boost graphql

Это загрузит библиотеки graphql для клиентской стороны, а также пакет Apollo Boost. Мы можем проверить это, набрав npm view apollo-boost dependencies. У этого будет много зависимостей, как показано ниже -

{ 
   'apollo-cache': '^1.1.15',
   'apollo-cache-inmemory': '^1.2.8',
   'apollo-client': '^2.4.0',
   'apollo-link': '^1.0.6',
   'apollo-link-error': '^1.0.3',
   'apollo-link-http': '^1.3.1',
   'apollo-link-state': '^0.4.0',
   'graphql-tag': '^2.4.2' 
}

Хорошо видно, что установлена ​​библиотека apollo-client.

Шаг 4. Измените компонент приложения в файле index.js.

Для простого реагирующего приложения вам нужно только сохранить index.js в src папка и index.htmlв общей папке; все остальные файлы, которые создаются автоматически, могут быть удалены.

Структура каталогов приведена ниже -

hello-world-client /
   -->node_modules
   -->public
      index.html
   -->src
      index.js
      students.js
   -->package.json

Добавьте дополнительный файл student.js, который будет содержать компонент «Студенты». Сведения о студенте получают через компонент "Студент". В компоненте приложения мы используем HashRouter.

Ниже приводится index.js в приложении реакции -

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {HashRouter, Route, Link} from 'react-router-dom'

//components
import Students from './students'
class App extends Component {
   render() {
      return(
         <div><h1>Home !!</h1>
         <h2>Welcome to React Application !! </h2>
         </div>
      )
   }
}

function getTime() {
   var d = new Date();
   return d.getHours()+":"+d.getMinutes()+":"+d.getSeconds()
}

const routes = <HashRouter>
   <div>
      <h4>Time from react app:{getTime()}</h4>
      <header>
         <h1>  <Link to="/">Home</Link> 
         <Link to = "/students">Students</Link>  </h1>
      </header>
      <Route exact path = "/students" component = {Students}></Route>
      <Route exact path = "/" component = {App}></Route>
   </div>
</HashRouter>

ReactDOM.render(routes, document.querySelector("#root"))

Шаг 5 - Отредактируйте компонент "Студенты" в Students.js

В компоненте «Студенты» мы будем использовать следующие два подхода к загрузке данных:

  • Fetch API (loadStudents_noCache) - Это будет вызывать новый запрос каждый раз, когда пользователь нажимает вкладку ученика.

  • Apollo Client (loadWithApolloclient) - Это будет извлекать данные из кеша.

Добавить функцию loadWithApolloclientкоторый запрашивает студентов и время с сервера. Эта функция включит кеширование. Здесь мы используем функцию gql для анализа запроса.

async loadWithApolloclient() {
   const query = gql`{
      getTime
      students {
         id
         firstName
      }
   }`;

   const {data} = await  client.query({query})
   return data;
}

В Fetch APIпростой интерфейс для получения ресурсов. Fetch упрощает выполнение веб-запросов и обработку ответов по сравнению со старым XMLHttpRequest. Следующий метод показывает загрузку данных напрямую с использованием fetch api -

async  loadStudents_noCache() {
      const response = await fetch('http://localhost:9000/graphql', {
      method:'POST',
      headers:{'content-type':'application/json'},
      body:JSON.stringify({query:`{
         getTime
         students {
            id
            firstName
         }
      }`})
   })

   const rsponseBody = await response.json();
   return rsponseBody.data;
}

В конструкторе StudentComponent вызовите loadWithApolloClientметод. Полный Student.js файл ниже -

import React, {Component} from 'react';
import { Link} from 'react-router-dom'

//Apollo Client
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
import gql from 'graphql-tag'
const client = new ApolloClient({
   link: new HttpLink({uri:`http://localhost:9000/graphql`}),
   cache:new InMemoryCache()
})

class Students extends Component {
   constructor(props) {
      super(props);
      this.state = {
         students:[{id:1,firstName:'test'}],
         serverTime:''
      }
      this.loadWithApolloclient().then(data => {
         this.setState({
            students:data.students,
            serverTime:data.getTime
         })
      })
   }
   
   async  loadStudents_noCache() {
      const response = await fetch('http://localhost:9000/graphql', {
         method:'POST',
         headers:{'content-type':'application/json'},
         body:JSON.stringify({query:`{
            getTime
            students {
               id
               firstName
            }
         }`})
      })
      const rsponseBody =  await response.json();
      return rsponseBody.data;
   }
   
   async loadWithApolloclient() {
      console.log("inside apollo client function")
      const query = gql`{
         getTime
         students {
            id
            firstName
         }
      }`;
      const {data} = await  client.query({query})
      return data;
   }
   
   render() {
      return(
         <div>
            <h3>Time from GraphQL server :{this.state.serverTime}</h3>
            <p>Following Students Found </p>
            <div>
               <ul>
                  {
                     this.state.students.map(s => {
                        return(
                           <li key = {s.id}>
                              {s.firstName}
                           </li>
                        )
                     })
                  }
               </ul>
            </div>
         </div>
      )
   }
}
export default Students

Шаг 6 - Запустите приложение React с npm start

Вы можете протестировать приложение React, переключившись с домашней вкладки на вкладку студентов. После того, как вкладка студентов загружена данными с сервера. Он кэширует данные. Вы можете проверить это, несколько раз переключаясь с домашней на вкладку студентов. Результат будет таким, как показано ниже -

Если вы сначала загрузили страницу студентов, введя URL-адрес, http://localhost:3000/#/students, вы можете видеть, что время загрузки для приложения React и GraphQL будет примерно одинаковым. После этого, если вы переключитесь в домашний вид и вернетесь на сервер GraphQL, время не изменится. Это показывает, что данные кэшированы.

Шаг 7. Измените вызов loadWithApolloclient на loadStudents_noCache

Если вы измените метод загрузки на loadStudents_noCacheв конструкторе StudentComponent выходные данные не будут кэшироваться. Это показывает разницу между кешированием и отсутствием кеширования.

this.loadStudents_noCache().then(data => {
   this.setState({
      students:data.students,
      serverTime:data.getTime
   })
})

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