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 / Students , в результате будет получена информация для всех полей объекта ученика . Это означает, что данные перегружены службой 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, могут быть быстрыми даже при медленных подключениях к мобильной сети.
Давайте рассмотрим еще один бизнес-объект, College, который имеет атрибуты: название и местонахождение. Бизнес-объект Student имеет связь с объектом College. Если бы мы использовали API REST для получения сведений о студентах и их колледжах, мы в конечном итоге сделаем два запроса к серверу, например / api / v1 / Students и / 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 — Настройка среды
В этой главе мы узнаем о настройке среды для GraphQL. Для выполнения примеров из этого урока вам понадобится следующее:
-
Компьютер под управлением Linux, macOS или Windows.
-
Веб-браузер, желательно последняя версия Google Chrome.
-
Установлена последняя версия Node.js. Последняя версия LTS рекомендуется.
-
Visual Studio Code с установленным расширением GraphQL для VSCode или любой другой редактор кода на ваш выбор.
Компьютер под управлением Linux, macOS или Windows.
Веб-браузер, желательно последняя версия Google Chrome.
Установлена последняя версия Node.js. Последняя версия LTS рекомендуется.
Visual Studio Code с установленным расширением GraphQL для VSCode или любой другой редактор кода на ваш выбор.
Как построить сервер GraphQL с Nodejs
Мы рассмотрим подробный пошаговый подход к созданию сервера GraphQL с Nodejs, как показано ниже —
Шаг 1 — Проверка версий узла и Npm
После установки NodeJs проверьте версию узла и 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 и добавьте два файла student.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 следующим образом:
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. Сервер называется Query. Другая важная концепция GraphQL — это агностика транспортного уровня. Он может использоваться с любым доступным сетевым протоколом, таким как TCP, веб-сокет или любой другой протокол транспортного уровня. Он также нейтрален для баз данных, поэтому вы можете использовать его с реляционными базами данных или базами данных NoSQL.
Сервер GraphQL может быть развернут любым из трех способов, перечисленных ниже:
- Сервер GraphQL с подключенной базой данных
- Сервер GraphQL, интегрирующий существующие системы
- Гибридный подход
Сервер GraphQL с подключенной базой данных
Эта архитектура имеет сервер GraphQL со встроенной базой данных и часто может использоваться с новыми проектами. При получении запроса сервер считывает полезную нагрузку запроса и получает данные из базы данных. Это называется разрешением запроса. Ответ, возвращаемый клиенту, соответствует формату, указанному в официальной спецификации GraphQL.
На приведенной выше диаграмме сервер GraphQL и база данных объединены в одном узле. Клиент (настольный / мобильный) связывается с сервером GraphQL через HTTP. Сервер обрабатывает запрос, получает данные из базы данных и возвращает их клиенту.
Сервер GraphQL, интегрирующий существующие системы
Этот подход полезен для компаний, которые имеют устаревшую инфраструктуру и разные API. GraphQL можно использовать для унификации микросервисов, устаревшей инфраструктуры и сторонних API в существующей системе.
На приведенной выше диаграмме API-интерфейс GraphQL действует как интерфейс между клиентом и существующими системами. Клиентские приложения связываются с сервером GraphQL, который, в свою очередь, разрешает запрос.
Гибридный подход
Наконец, мы можем объединить два вышеупомянутых подхода и построить сервер GraphQL. В этой архитектуре сервер GraphQL разрешит любой полученный запрос. Он будет либо извлекать данные из подключенной базы данных, либо из встроенных API. Это представлено на рисунке ниже —
GraphQL — Компоненты приложения
В этой главе обсуждаются различные компоненты GraphQL и способы их взаимодействия друг с другом. Все компоненты приложения можно выделить, как показано ниже:
- Серверные компоненты
- Клиентские компоненты
Серверные компоненты
Сервер GraphQL формирует основной компонент на стороне сервера и позволяет анализировать запросы, поступающие от клиентских приложений GraphQL. Apollo Server — наиболее часто используемая реализация спецификации GraphQL. Другие компоненты программирования сервера включают следующее:
Sr.No. | Основы и описание сервера |
---|---|
1 |
схема Схема GraphQL находится в центре любой реализации сервера GraphQL и описывает функциональные возможности, доступные для клиентов, которые к ней подключаются. |
2 |
запрос Запрос GraphQL — это запрос клиентского приложения на получение данных из базы данных или устаревших API. |
3 |
Резольвер Резолверы предоставляют инструкции по превращению операции GraphQL в данные. Они разрешают запрос к данным, определяя функции распознавателя. |
схема
Схема GraphQL находится в центре любой реализации сервера GraphQL и описывает функциональные возможности, доступные для клиентов, которые к ней подключаются.
запрос
Запрос GraphQL — это запрос клиентского приложения на получение данных из базы данных или устаревших API.
Резольвер
Резолверы предоставляют инструкции по превращению операции GraphQL в данные. Они разрешают запрос к данным, определяя функции распознавателя.
Клиентские компоненты
Ниже приведены клиентские компоненты —
Sr.No. | Инструмент и описание |
---|---|
1 |
GraphiQL Браузерный интерфейс для редактирования и тестирования запросов и мутаций GraphQL. |
2 |
ApolloClient Лучший инструмент для создания клиентских приложений GraphQL. Хорошо интегрируется со всем интерфейсом JavaScript. |
GraphiQL
Браузерный интерфейс для редактирования и тестирования запросов и мутаций GraphQL.
ApolloClient
Лучший инструмент для создания клиентских приложений GraphQL. Хорошо интегрируется со всем интерфейсом JavaScript.
На приведенной ниже схеме показана архитектура клиент-сервер . Веб-сервер построен на NodeJs и Express Framework. Запрос на сервер Apollo GraphQL выполняется приложением ReactJS (созданным с использованием клиентской библиотеки Apollo) или браузерным приложением GraphiQL. Запрос будет проанализирован и проверен по схеме, определенной на сервере. Если схема запроса проходит валидацию, то соответствующие функции распознавателя будут выполнены. Средство распознавания будет содержать код для извлечения данных из API или базы данных.
GraphQL — Пример
В этой главе мы создадим простой API, который возвращает приветственное сообщение HelloWorld, и получим к нему доступ с помощью GraphiQL.
пример
Этот пример основан на NodeJS, Express и сервере Apollo. Мы научимся объединять все концепции с помощью следующих шагов:
Шаг 1 — Настройка Экспресс
ExpressJS — это структура веб-приложений, которая помогает создавать веб-сайты и веб-приложения. В этом примере мы построим API-интерфейс GraphQL поверх платформы 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-инструменты
- аполлон-сервер-экспресс @ 1
Мы будем использовать сервер Apollo 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 . Теперь добавьте следующий фрагмент кода в файл server.js —
// Adding Type Definitions const typeDefinition = ` type Query { greeting: String }
Здесь запрос содержит атрибут приветствия, который возвращает строковое значение.
Шаг 4 — Создание резольвера
Первым шагом в создании распознавателя является добавление некоторого кода для обработки запроса поля приветствия. Это указано в резольвере . Структура функции распознавателя должна соответствовать схеме. Добавьте следующий фрагмент кода в файл 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 — Тестирование API GraphQL
Откройте браузер и введите http: // localhost: 9000 / graphiql . На вкладке запроса GraphiQL введите следующее —
{ greeting }
Ответ от сервера приведен ниже —
{ "data": { "greeting": "Hello GraphQL From TutorialsPoint !!" } }
Следующее изображение иллюстрирует ответ —
Примечание. Убедитесь, что используется сервер Apollo версии 1.0.
GraphQL — система типов
GraphQL — строго типизированный язык. Система типов определяет различные типы данных, которые можно использовать в приложении GraphQL. Система типов помогает определить схему, которая является контрактом между клиентом и сервером. Обычно используются следующие типы данных GraphQL:
Sr.No. | Типы и описание |
---|---|
1 |
скаляр Хранит одно значение |
2 |
объект Показывает, какой объект можно получить |
3 |
запрос Тип точки входа в другие конкретные типы |
4 |
перегласовка Точка входа для манипулирования данными |
5 |
Enum Полезно в ситуации, когда вам нужно, чтобы пользователь выбирал из заданного списка опций |
скаляр
Хранит одно значение
объект
Показывает, какой объект можно получить
запрос
Тип точки входа в другие конкретные типы
перегласовка
Точка входа для манипулирования данными
Enum
Полезно в ситуации, когда вам нужно, чтобы пользователь выбирал из заданного списка опций
Скалярный тип
Скалярные типы — это примитивные типы данных, которые могут хранить только одно значение. Скалярные типы по умолчанию, которые предлагает GraphQL:
-
Int — 32-разрядное целое число со знаком
-
Float — значение с плавающей запятой двойной точности со знаком
-
Строка — UTF — последовательность из 8 символов
-
Boolean — верно или неверно
-
Идентификатор — уникальный идентификатор, часто используемый в качестве уникального идентификатора для выборки объекта или в качестве ключа для кэша.
Int — 32-разрядное целое число со знаком
Float — значение с плавающей запятой двойной точности со знаком
Строка — UTF — последовательность из 8 символов
Boolean — верно или неверно
Идентификатор — уникальный идентификатор, часто используемый в качестве уникального идентификатора для выборки объекта или в качестве ключа для кэша.
Синтаксис для определения скалярного типа следующий:
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 в корневой схеме Query вернет список объектов Student.
Тип запроса
Запрос GraphQL используется для получения данных. Это похоже на запрос ресурса в API на основе REST. Для простоты тип Query — это запрос, отправляемый из клиентского приложения на сервер GraphQL. GraphQL использует язык определения схемы (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 }
Тип мутации
Мутации — это операции, отправляемые на сервер для создания, обновления или удаления данных. Они аналогичны глаголам PUT, POST, PATCH и DELETE для вызова API на основе REST.
Мутация — это один из типов данных корневого уровня в GraphQL. Тип Query определяет точки входа для операций выборки данных, тогда как тип Mutation определяет точки входа для операций манипулирования данными.
Синтаксис для определения типа мутации приведен ниже —
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 похож на скалярный тип. Перечисления полезны в ситуации, когда значение для поля должно быть из заданного списка опций.
Синтаксис для определения типа Enum —
type enum_name{ value1 value2 }
Следующий фрагмент иллюстрирует, как можно определить тип enum —
type Days_of_Week{ SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY }
Тип списка
Списки могут использоваться для представления массива значений определенного типа. Списки определяются с помощью модификатора типа [], который переносит типы объектов, скаляры и перечисления.
Следующий синтаксис может быть использован для определения типа списка —
field:[data_type]
Приведенный ниже пример определяет список задач todos —
type Query { todos: [String] }
Тип Nullable
По умолчанию каждый из базовых скалярных типов может быть установлен в нуль. Другими словами, эти типы могут либо возвращать значение указанного типа, либо они могут не иметь значения. Чтобы переопределить это значение по умолчанию и указать, что поле должно быть определено, к типу можно добавить восклицательный знак (!). Это гарантирует наличие значения в результатах, возвращаемых запросом.
Следующий синтаксис может быть использован для определения ненулевого поля —
field:data_type!
В приведенном ниже примере stud_id объявлен как обязательное поле.
type Student { stud_id:ID! firstName:String lastName:String fullName:String college:College }
GraphQL — схема
Схема 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 |
Определения типов Это обязательный аргумент. Он представляет запрос GraphQL в виде строки UTF-8. |
2 |
Resolvers Это необязательный аргумент (пустой объект по умолчанию). У этого есть функции, которые обрабатывают запрос. |
3 |
лесоруб Это необязательный аргумент и может использоваться для вывода ошибок на консоль сервера. |
4 |
parseOptions Это необязательный аргумент и позволяет настраивать синтаксический анализ при указании typeDefs в виде строки. |
5 |
allowUndefinedInResolve Это верно по умолчанию. Если установлено значение false, ваши функции разрешения выдают ошибки, если они возвращают неопределенное значение. |
6 |
resolverValidationOptions Это необязательный аргумент и принимает объект с логическими свойствами. |
7 |
inheritResolversFromInterfaces Это необязательный аргумент, и он принимает логический аргумент для проверки наследования объекта распознавателей. |
Определения типов
Это обязательный аргумент. Он представляет запрос GraphQL в виде строки UTF-8.
Resolvers
Это необязательный аргумент (пустой объект по умолчанию). У этого есть функции, которые обрабатывают запрос.
лесоруб
Это необязательный аргумент и может использоваться для вывода ошибок на консоль сервера.
parseOptions
Это необязательный аргумент и позволяет настраивать синтаксический анализ при указании typeDefs в виде строки.
allowUndefinedInResolve
Это верно по умолчанию. Если установлено значение false, ваши функции разрешения выдают ошибки, если они возвращают неопределенное значение.
resolverValidationOptions
Это необязательный аргумент и принимает объект с логическими свойствами.
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 }
Корнем схемы будет тип запроса. Запрос имеет два поля — приветствие и ученики, которые возвращают строку и список учеников соответственно. Студент объявлен как тип объекта, так как он содержит несколько полей. Поле идентификатора объявлено как необнуляемое.
Шаг 3 — Создание резольвера
Создайте файл resolvers.js в папке проекта и добавьте следующий код —
const db = require('./db') const Query = { greeting:() => { return "hello from TutorialsPoint !!!" }, students:() => db.students.list() } module.exports = {Query}
Здесь приветствие и учащиеся являются решателями, которые обрабатывают запрос. Функция распознавания студентов возвращает список студентов из слоя доступа к данным. Чтобы получить доступ к функциям распознавателя вне модуля, объект Query должен быть экспортирован с помощью module.exports .
Шаг 4 — Запустите приложение
Создайте файл server.js и обратитесь к шагу 8 в главе «Настройка среды». Следующим шагом является выполнение команды npm start в терминале. Сервер будет работать на 9000 портов. Здесь мы используем GraphiQL в качестве клиента для тестирования приложения. Откройте браузер и введите URL-адрес, http: // localhost: 9000 / graphiql .
Введите следующий запрос в редакторе —
{ greeting students { id firstName lastName } }
Запрос отобразит вывод, как показано ниже —
Примечание. Мы можем заменить student.json вызовом API RESTful для извлечения данных о студентах или даже реальной базы данных, такой как MySQL или MongoDB. GraphQL становится тонкой оберткой вокруг исходного уровня приложения для повышения производительности.
GraphQL — Resolver
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 |
корень Объект, который содержит результат, возвращаемый распознавателем в родительском поле. |
2 |
арг Объект с аргументами, переданными в поле в запросе. |
3 |
контекст Этот объект является общим для всех распознавателей в конкретном запросе. |
4 |
Информация Он содержит информацию о состоянии выполнения запроса, включая имя поля, путь к полю от корня. |
корень
Объект, который содержит результат, возвращаемый распознавателем в родительском поле.
арг
Объект с аргументами, переданными в поле в запросе.
контекст
Этот объект является общим для всех распознавателей в конкретном запросе.
Информация
Он содержит информацию о состоянии выполнения запроса, включая имя поля, путь к полю от корня.
Resolver Result Format
Решатели в GraphQL могут возвращать различные типы значений, как указано ниже —
Sr.No. | Аргументы и описание |
---|---|
1 |
нулевой или неопределенный это указывает на то, что объект не может быть найден |
2 |
массив это допустимо, только если схема указывает, что результатом поля должен быть список |
3 |
обещание распознаватели часто выполняют асинхронные действия, такие как выборка из базы данных или бэкэнд-API, поэтому они могут возвращать обещания |
4 |
скаляр или объект распознаватель также может возвращать другие значения |
нулевой или неопределенный
это указывает на то, что объект не может быть найден
массив
это допустимо, только если схема указывает, что результатом поля должен быть список
обещание
распознаватели часто выполняют асинхронные действия, такие как выборка из базы данных или бэкэнд-API, поэтому они могут возвращать обещания
скаляр или объект
распознаватель также может возвращать другие значения
иллюстрация
Давайте создадим простое приложение для понимания решателя. Это создаст схему для запроса студента по идентификатору с сервера. Данные об учениках будут храниться в плоском файле, и мы будем использовать модуль узла notarealdb для подделки базы данных и чтения из плоского файла.
Ниже приведен пошаговый процесс создания простого приложения:
Шаг 1 — Загрузите и установите необходимые зависимости для проекта
Создайте папку с именем resolver-app . Измените свой каталог на resolver-app с терминала. Далее выполните шаги с 3 по 5 в главе «Настройка среды».
Шаг 2 — Создание схемы
Добавьте файл schema.graphql в папку проекта resolver-app и добавьте следующий код —
type Query { greeting:String students:[Student] studentById(id:ID!):Student } type Student { id:ID! firstName:String lastName:String password:String collegeId:String }
Файл схемы показывает, что пользователь может запросить приветствие, студентов и studentById . Чтобы получить студентов с определенным идентификатором, мы используем идентификатор типа данных! который показывает необнуляемое поле уникального идентификатора. Поле студентов возвращает массив студентов, а приветствие возвращает простое строковое значение.
Шаг 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 может быть получен из аргументов; root будет содержать сам объект Query. Чтобы вернуть конкретного студента, нам нужно вызвать метод get с параметром id в коллекции студентов.
Здесь приветствие, Students, studentById являются резольверами, которые обрабатывают запрос. Функция распознавания студентов возвращает список студентов из слоя доступа к данным. Чтобы получить доступ к функциям распознавателя вне модуля, объект 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 используется для чтения или извлечения значений, в то время как мутация используется для записи или публикации значений. В любом случае операция представляет собой простую строку, которую сервер 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 в обоих средствах разрешения схем.
Давайте посмотрим, как сделать эту иллюстрацию, используя следующие шаги —
Шаг 1 — Загрузите и установите необходимые зависимости для проекта
Создайте папку с именем 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 }
Обратите внимание, что в файле Students.json отсутствует поле fullName . Однако нам нужно получить полное имя студента с помощью запроса. В данном случае 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
Нам нужно добавить функцию распознавания колледжа, как показано ниже. Функция распознавания колледжа будет выполняться для каждого возвращаемого объекта учащегося. Корневой параметр resolver в этом случае будет содержать 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}
Средство распознавания возвращает колледж каждого студента, вызывая метод get коллекционирования колледжа и передавая CollegeId . У нас есть отношения ассоциации между Студентом и Колледжем через колледж .
Шаг 3 — протестировать приложение
Откройте окно терминала и перейдите к папке проекта. Введите команду -npm start. Запустите браузер и введите URL-адрес http: // 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!!" } }
Как использовать Query Variable с Enum
Давайте посмотрим, как использовать переменную запроса, когда параметр поля имеет тип enum .
Шаг 1 — Редактирование файла schema.graphql
enum ColorType { RED BLUE GREEN } type Query { setFavouriteColor(color:ColorType):String }
Функция setFavouriteColor принимает в качестве входных данных перечисление и возвращает строковое значение.
Шаг 2 — Редактируйте файл resolvers.js
Функция резолвера setFavouriteColor получает корни и аргументы . Значение enum, переданное функции во время выполнения, доступно через параметр 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 — мутация
В этой главе мы изучим мутационные запросы в GraphQL.
Запросы мутации изменяют данные в хранилище данных и возвращают значение. Его можно использовать для вставки, обновления или удаления данных. Мутации определяются как часть схемы.
Синтаксис запроса мутации приведен ниже —
mutation{ someEditOperation(dataField:"valueOfField"):returnType }
иллюстрация
Давайте разберемся, как добавить новую запись студента в хранилище данных, используя запрос мутации.
Шаг 1 — Загрузите и установите необходимые зависимости для проекта
Создайте папку проекта с именем mutation-app. Измените свой каталог на mutation-app из терминала. Выполните шаги с 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 из коллекции студентов возвращает идентификатор вновь созданного студенческого объекта.
Шаг 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.json. Запрос вернет уникальный идентификатор. Ответ на запрос, как показано ниже —
{ "data": { "createStudent": "SkQtxYBUm" } }
Чтобы проверить, создан ли объект Student, мы можем использовать запрос studentById. Вы также можете открыть файл Students.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 } } }
Приведенный выше запрос добавляет нового студента и получает объект студента вместе с объектом колледжа. Это экономит поездки на сервер.
Ответ как указано ниже —
{ "data": { "addStudent_returns_object": { "id": "rklUl08IX", "firstName": "Susan", "college": { "id": "col-101", "name": "AMU" } } } }
GraphQL — валидация
При добавлении или изменении данных важно проверить вводимые пользователем данные. Например, нам может потребоваться убедиться, что значение поля всегда не равно нулю. Мы можем использовать ! (не обнуляемый) тип маркера в GraphQL для выполнения такой проверки.
Синтаксис для использования ! тип маркера как указано ниже —
type TypeName { field1:String!, field2:String!, field3:Int! }
Приведенный выше синтаксис гарантирует, что все поля не равны NULL.
Если мы хотим реализовать дополнительные правила, такие как проверка длины строки или проверка, находится ли число в заданном диапазоне, мы можем определить пользовательские валидаторы. Пользовательская логика проверки будет частью функции распознавателя. Позвольте нам понять это с помощью примера.
Иллюстрация — Реализация пользовательских валидаторов
Давайте создадим форму регистрации с базовой проверкой. Форма будет содержать поля электронной почты, имени и пароля.
Шаг 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! }
Примечание. Мы можем использовать тип входа 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 } ] } ] }
GraphQL — интеграция JQuery
Веб-приложения отправляют и получают данные асинхронно (в фоновом режиме). AJAX позволяет веб-сайтам загружать контент на экран без обновления страницы. jQuery предоставляет несколько методов для функциональности AJAX, что упрощает использование AJAX. В этой главе мы узнаем, как мы можем интегрировать GraphQL с jQuery.
Рассмотрим приложение, использующее архитектуру клиент-сервер. Мы можем создать интерфейсную веб-страницу, которая запрашивает данные с сервера GraphQL. Веб-страница будет выполнять вызовы AJAX с использованием jQuery на сервер GraphQL.
Чтобы интегрировать GraphQL с JQuery, давайте проверим заголовки запросов GraphiQL и разберемся с параметрами запроса.
Запустите приложение hello-world (см. Главу 6 для соответствующей иллюстрации). Введите запрос graphql {приветствие} в окне GraphiQL. Щелкните правой кнопкой мыши и проверьте или нажмите (Ctrl + Shift + I) на Chrome, чтобы перейти на вкладку сети, как показано ниже —
Из простого примера hello-world мы можем понять, что используемый метод http — это POST . Теперь в браузере прокрутите вниз до раздела заголовка, чтобы просмотреть полезную нагрузку запроса .
После того, как вы нажмете на код просмотра , вы увидите следующее в разделе полезной нагрузки 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 }
В файле определены два запроса приветствия и 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}
Здесь приветствие и sayHello являются двумя решающими. В преобразователе sayHello доступ к значению, передаваемому параметру name, можно получить через аргументы. Чтобы получить доступ к функциям распознавателя вне модуля, объект 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!!" } }
Настройка клиента
Поскольку мы уже настроили сервер, теперь мы узнаем, как настроить клиент.
Шаг 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>
Откройте этот файл в браузере и нажмите на кнопку, чтобы увидеть ответ. Выход будет как указано ниже —
GraphQL — реактивная интеграция
React — это библиотека Javascript для создания пользовательских интерфейсов. В этой главе объясняется, как можно интегрировать GraphQL с приложением React.
иллюстрация
Самый быстрый способ настроить реагирующий проект — использовать инструмент Создать приложение React . В последующих разделах мы узнаем, как настроить как Сервер, так и Клиент.
Настройка сервера
Для настройки Сервера выполните следующие действия:
Шаг 1 — Загрузите и установите необходимые зависимости для проекта
Создайте папку реакции-сервер-приложение . Измените ваш каталог на имя -сервер-приложение с терминала. Выполните шаги с 3 по 5, описанные в главе «Настройка среды».
Шаг 2 — Создание схемы
Добавьте файл schema.graphql в папку проекта response -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}
Здесь приветствие и сказать Привет два решателя. В резольвере sayHello к значению, передаваемому параметру name, можно получить доступ через аргументы. Чтобы получить доступ к функциям распознавателя вне модуля, объект 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-реагировать на приложение создают проект с именем 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;
После запуска обоих приложений нажмите кнопку приветствия. Затем введите имя в текстовое поле и нажмите кнопку «Скажи привет». Выход будет как указано ниже —
GraphQL — клиент Apollo
Мы использовали Apollo Server для построения спецификации graphql на стороне сервера. Быстро и легко построить готовый к работе сервер GraphQL. Теперь позвольте нам понять сторону клиента.
Apollo Client — лучший способ использовать GraphQL для создания клиентских приложений. Клиент разработан, чтобы помочь разработчику быстро создать пользовательский интерфейс, который извлекает данные с помощью GraphQL и может использоваться с любым интерфейсом JavaScript.
Apollo Client поддерживает следующие платформы —
Sr.No. | Платформа и фреймворк |
---|---|
1 |
Javascript Реагировать, Угловой, Вьет, Метеор, Ember |
2 |
веб-компоненты Полимер, лит-аполлон |
3 |
Родной мобильный Родной Android с Java, Родной iOS с Swift |
Javascript
Реагировать, Угловой, Вьет, Метеор, Ember
веб-компоненты
Полимер, лит-аполлон
Родной мобильный
Родной Android с Java, Родной iOS с Swift
Кэширование является одной из основных функций Apollo Client. apollo-boost — это удобный пакет, который включает в себя множество других зависимостей.
иллюстрация
Давайте посмотрим, как использовать клиент Apollo для создания клиентских приложений, выполнив следующие шаги:
Настройка сервера
Мы должны выполнить следующие шаги для настройки сервера —
Шаг 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-реагировать на приложение создают проект с именем 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 мы можем напрямую вызывать сервер без использования 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() });
В предыдущей главе мы обсуждали, как использовать 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 — клиент для аутентификации
Аутентификация — это процесс или действие по проверке личности пользователя или процесса. Важно, чтобы приложение аутентифицировало пользователя, чтобы гарантировать, что данные не доступны анонимному пользователю. В этом разделе мы узнаем, как аутентифицировать клиента GraphQL.
Экспресс JWT
В этом примере мы будем использовать jQuery для создания клиентского приложения. Для аутентификации запросов мы будем использовать модуль express-jwt на стороне сервера.
Модуль express-jwt — это промежуточное ПО, которое позволяет аутентифицировать HTTP-запросы с использованием токенов JWT. JSON Web Token (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 для аутентификации запросов —
-
Когда пользователь нажимает кнопку приветствия , выдается запрос на маршрут / graphql. Если пользователь не аутентифицирован, ему будет предложено аутентифицировать себя.
-
Пользователю предоставляется форма, которая принимает идентификатор электронной почты и пароль. В нашем примере маршрут / login отвечает за аутентификацию пользователя.
-
Маршрут / login проверяет, найдено ли совпадение в базе данных для учетных данных, предоставленных пользователем.
-
Если учетные данные недействительны, исключение HTTP 401 возвращается пользователю.
-
Если учетные данные действительны, токен генерируется сервером. Этот токен отправляется как часть ответа пользователю. Это делается с помощью функции jwt.sign.
Когда пользователь нажимает кнопку приветствия , выдается запрос на маршрут / 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, это свойство назначается объекту контекста, как показано ниже:
//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
В клиентском приложении предусмотрена кнопка приветствия, которая вызовет схему приветствияWithAuth . Если вы нажмете кнопку без входа в систему, появится сообщение об ошибке, как показано ниже:
Как только вы войдете в систему с пользователем, доступным в базе данных, появится следующий экран —
Чтобы получить доступ к приветствию , нам сначала нужно получить доступ к URL-адресу http: // localhost: 9000 / login route, как показано ниже.
Ответ будет содержать токен, сгенерированный с сервера.
$.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') })
После успешного входа в систему мы можем получить доступ к схемеreetingWithAuth, как показано ниже. Должен быть заголовок авторизации для всех последующих запросов с токеном носителя.
{ 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>
GraphQL — Кэширование
Кэширование — это процесс хранения данных во временной области хранения, называемой кешем . Когда вы возвращаетесь на страницу, которую вы недавно посещали, браузер может получать эти файлы из кэша, а не с исходного сервера. Это экономит ваше время и сеть от бремени дополнительного трафика.
Клиентские приложения, взаимодействующие с GraphQL, несут ответственность за кэширование данных в их конце. Одним из возможных шаблонов для этого является резервирование поля, такого как id, в качестве глобального уникального идентификатора.
InMemory Cache
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 Карта функций для перенаправления запроса на другую запись в кеше до его выполнения. |
addTypename
Логическое значение, определяющее, следует ли добавлять __typename в документ (по умолчанию: true)
dataIdFromObject
Функция, которая принимает объект данных и возвращает уникальный идентификатор, который будет использоваться при нормализации данных в хранилище.
fragmentMatcher
По умолчанию InMemoryCache использует эвристический алгоритм сопоставления фрагментов.
cacheRedirects
Карта функций для перенаправления запроса на другую запись в кеше до его выполнения.
иллюстрация
Мы создадим одностраничное приложение в ReactJS с двумя вкладками — одна для домашней вкладки и другая для студентов. Вкладка студентов будет загружать данные из API сервера GraphQL. Приложение будет запрашивать данные о студентах, когда пользователь переходит с домашней вкладки на вкладку студентов. Полученные данные будут кэшироваться приложением.
Мы также запросим время сервера, используя поле getTime, чтобы проверить, кэширована ли страница. Если данные возвращаются из кэша, на странице будет отображаться время самого первого запроса, отправленного на сервер. Если данные являются результатом нового запроса к серверу, он всегда будет показывать самое последнее время с сервера.
Настройка сервера
Ниже приведены шаги для настройки сервера:
Шаг 1 — Загрузите и установите необходимые зависимости для проекта
Создайте папку 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 и инструменты create-реагировать на приложение создают проект с именем hello-world-client. После завершения установки откройте проект в VSCode.
Установите модули маршрутизатора для реакции, используя следующую команду — npm install response-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 зависимости. Это будет иметь много зависимостей, как показано ниже —
{ '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, который будет содержать компонент Students. Сведения об ученике извлекаются через компонент ученика. В компоненте приложения мы используем 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 (loadWithApolloclient) — будет извлекать данные из кэша.
Fetch API (loadStudents_noCache) — это будет запускать новый запрос каждый раз, когда нажимает вкладку ученика.
Клиент Apollo (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; }
В конструкторе StudentsComponent вызовите метод 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
Вы можете протестировать приложение реагирования, переключившись с домашней вкладки на вкладку студентов. После того, как вкладка студентов загружается с данными с сервера. Это будет кешировать данные. Вы можете проверить это, переключаясь из дома на вкладку студентов несколько раз. Вывод будет таким, как показано ниже —
Если вы сначала загрузили страницу учеников, введя URL-адрес http: // localhost: 3000 / # / Students, вы увидите, что время загрузки приложения реагировать и GraphQL будет примерно одинаковым. После этого, если вы переключитесь в режим домашнего просмотра и вернетесь на сервер GraphQL, время не изменится. Это показывает, что данные кэшируются.
Шаг 7 — Измените вызов loadWithApolloclient на loadStudents_noCache
Если вы измените метод загрузки на loadStudents_noCache в конструкторе StudentComponent, выходные данные не будут кэшироваться в данных. Это показывает разницу между кэшированием и отсутствием кэширования.
this.loadStudents_noCache().then(data => { this.setState({ students:data.students, serverTime:data.getTime }) })
Из вышеприведенного вывода ясно, что если вы переключаетесь между вкладками, время с сервера GraphQL всегда будет самым последним, что означает, что данные не кэшируются.