Как создать полноценный сервер GraphQL с помощью Node.js

1656541365 kak sozdat polnoczennyj server graphql s pomoshhyu nodejs

Джека Р. Скотта

Итак, вы, наверное, думаете — это просто еще один шумный учебник GraphQL, который просто скажешь много больших слов, но на самом деле не поможет мне ничего реализовать?

✋ Ответ – нет.

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

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

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

? Как вы знаете, что это законно?

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

? Примечание.

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

Ладно, давайте сделаем это!

Немного контекста?‍

Прежде чем я начну, вероятно, было бы хорошей идеей дать некоторый контекст для людей, которые еще не знают. GraphQL был создан в 2012 году Facebook (еще раз спасибо). Он был разработан как альтернатива к существующему стандарту REST для структурирования запросов сервера.

? Что такое ОТДЫХ?

Это то, что ты получаешь, когда ложишься спать… Понял?

1*gIVNrG1C7dHjH9866IFJyw
Почему этот человек считает себя смешным?

Честно говоря, я хочу, чтобы эта статья была как можно более лаконична. Итак, чтобы помочь объяснить, вот полезная ссылка на статью, объясняющую концепцию REST. Причина, почему Facebook создал GraphQL как альтернативу, заключалась в том, что стандарт REST имел несколько ключевых проблем:

  1. Для получения сложных объектов требуется несколько вызовов к серверу – задержка.
  2. Вы получаете больше, чем просите. REST обычно определяет форму данных на сервере. Таким образом, вы получаете кучу данных, которые вы даже не используете.
  3. Нужно много работать, чтобы точно понять, какую информацию вы получаете от сервера – не слишком предсказуемо.

В то время у Facebook было много страстных разработчиков, любящих тестировать новые крутые концепции. Им удалось начать работать над новой концепцией, которая позже стала GraphQL. Они хотели спросить у своих серверов именно то, что хотели, и знали, что они получат именно это обратно. Без пуха. ?

Поэтому они создали новый язык, который был разработан специально для запросов серверов. Вот почему GraphQL описывается как «язык запросов для вашего API».

1*aIejg1WlHOhUngmLsILnjQ

Выше приведен пример запроса GraphQL, а также пример ответа JSON. Я бы описал, что происходит… но это вполне понятно.

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

Идём дальше!

Дайте мне код! ?‍?

Ладно, хорошо… Эй, ты требовательный… Я перехожу к коду. Но, прежде чем мы начнем, нам нужно создать новый репозиторий Node.js и установить несколько зависимостей NPM.

? Горячий совет: ознакомьтесь с Parcel.js, чтобы найти отличный пакет программ, который поможет вам упорядочить среду разработки в считанные секунды (убедитесь, что вы установили целевое значение node окружающая среда). Посылка используется в CodeSandbox.

Ps: Я предполагаю, что вы уже знаете, как настроить репозиторий Node.js. Если вы этого не сделаете, то понятия, приведенные в этой статье, могут быть несколько сложными. Вы все еще можете следить, чтобы получить общее понимание.

Наши зависимости NPM:

  1. apollo-сервер
  2. мангуста
  3. graphql-инструменты

Подожди… ? кто такой Аполлон и зачем нам его сервер?

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

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

? Файл: src/index.ts

Я добавил ряд комментариев к коду, которые помогут объяснить происходящее в файле. По сути, мы создали сервер и предоставили серверу схему, содержащую «пустой» тип для наших запросов (type Query) и «пустой» тип для наших мутаций (type Mutation).

  • Пустой означает, что у него нет свойств (пока).

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

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

? Файл: src/common/users/user.model.ts

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

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

1*tHAnZewCOhGiUlQ2Bm4J1Q

Для этого мы создадим файл, содержащий 2 вещи:

  1. Набор типов GraphQL, сообщающий клиенту, «какие» данные мы имеем
  2. Подходящий набор функций резольвера GraphQL, который сообщает серверу «как» делать то, что описывают наши типы.

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

? Файл: src/common/users/user.schema.ts

Праздники моли! Это очень много… Так что давайте разберем это, начиная с наших определений типов:

  • type User { ... }: это простой тип GraphQL Это лишь сообщает нам, какая форма Пользователя, чтобы клиент мог правильно спрашивать его. Вы можете найти больше здесь, в документации.
  • input UserFilterInput { ... }: подобно объекту «тип», входные данные определяют структуру сложного параметра, то есть нечто более сложное, чем String, ID, Int, FLoat или Boolean.
  • extend type Query { ... }: поэтому вспомните, когда мы создавали нашу корневой тип запроса обратно в файл индекса? Ну, это касается того. Мы расширяем этот корневой запрос и определяем функциональные возможности, которые мы хотим предоставить нашим клиентам. Почему мы делаем это именно так? Пффф… Я не хочу сделать это таким образом (это как-то хакерски)… К сожалению, это был лучший способ сделать это из нескольких плохих альтернатив. Не стесняйтесь дать мне лучшее предложение.
  • extend type Mutation { ... }: так же, как мы расширяем корневой запрос, мы также расширяем корневую мутацию.

Теперь давайте разберем, что происходит в наших опознавателях пользователей:

  • Названия наших функций распознавания совпадают с названиями полей у обоих Query и Mutation в определениях типов. Это помогает Apollo знать, какие функции выполняют.
  • users: async (_, { filter = {} }) => { ... }: Ну, разве эта строка не очень вкусна для разработчиков, которые не видели ее раньше. Не волнуйтесь, это указано только для должногоty usМы назначаем анонимную функцию, которая использует async/await для запроса в базу данных и возвращения некоторых пользователей. Простой? Аргументы функции совпадают с аргументами в документации сервера Apollo, которую вы можете найти здесь.
  • await User.something(): Этот синтаксис показывает, как мы используем mongoose для получения или сохранения данных в базе данных. Это очень просто, как только вы поймете это, вы можете найти документы о mongoose здесь.
  • user.toGraph(): Здесь большинство людей запутается Эта функция «toGraph» происходит из нашего файла модели мангуста (найдите ее в файле модели, где указано userSchema.method('toGraph', ...). Причина, почему нам нужна эта функция, в том, что Mongoose не возвращает простой объект JavaScript. Скорее он возвращает сложный объект с некоторыми случайными свойствами, которые GraphQL не нравятся. Таким образом, с помощью toGraph Мы превращаем сложный объект в обычный объект, который может обрабатывать GraphQL.

? Wowzers! Это была перегрузка мозга.

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

хорошо! Теперь давайте исправим все это вместе в индексный файл…

? Файл: src/index.ts

Все, что нам нужно было сделать, это импортировать наши определения типов и резольверы, а затем мы добавили их в нашу схему. Если вы уйдете и запустите свою программу (надеюсь, вы бы настроили сценарий запуска, т.е. npm start) вы должны увидеть, что ваше приложение откроется на http://localhost:4000.

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

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

1*QTEJESaA__GF8GJKoBv-rA

Вам может быть любопытно; что делает query GetAllUsers или mutation AddUser значит?

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

? Привет, Джек, я все еще не уверен в одной вещи. Какая разница между Queries и Мутации?

Отличный вопрос! У меня было чувство, что ты спросишь. Чтобы по-настоящему это понять, нужно посмотреть, что происходит под капотом нашего сервера. Многие считают, что запросы являются эквивалентом a GET запрос. Мутации для всех других, т.е. POST, PUT, PATCHи DELETE но это не совсем так.

Давайте посмотрим на примере 2 запросов к нашему серверу GraphQL с нашей игровой площадки Apollo GraphQL — который поставляется с Apollo Server прямо из коробки.

1*60TibCKmU8VJo8-DZnUh9Q

Как видите, оба query и mutation запросы есть POST запросы. Причина этого состоит в том, что они оба имеют возможность передавать переменные в свои запросы, например users (limit: $maxUsers) { ... }.

Настоящая разница между ними состоит в том, что:

  1. Запросы выполняются параллельно.
  2. Мутации производятся последовательно.

Таким образом можно выполнять запросы быстро и мутации могут быть выполнены надежно. Спасибо Prisma за помощь в этом.

⏰ Пора подняться на новый уровень!

Итак, сейчас мы проделали достаточно хорошую работу, мы знаем, как:

  • ✅ Создайте базовый сервер.
  • ✅ Создайте схему mongoose, которая проверит данные нашей базы данных.
  • ✅ Определите структуру данных GraphQL на сервере, используя определение типов.
  • ✅ Подключите нашу схему mongoose к серверу GraphQL с помощью резольверов.
  • ✅ Делайте несколько запросов и мутаций через игровую площадку Apollo.

Я бы сказал, что это справедливое потрясение бутылки соуса – Кевин ’07. Но еще не хватает нескольких вещей…

? Что делать, когда у нас есть связанные элементы базы данных, как с этим бороться?

По сути это довольно просто, давайте это сделаем!

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

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

? Файл: src/common/workspace/workspace.model.ts

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

? Файл: src/common/workspace/workspace.schema.ts

Мыло, теперь нам просто нужно обновить файл индекса, чтобы он распознавал нашу схему GraphQL рабочего пространства и резольвера. Чтобы объединить резольверы, нам нужно использовать lodash merge функция, которая глубоко объединяет два объекта.

? Файл: src/index.ts

После того, как вы реализуете приведенный выше код, вы сможете создавать и запрашивать рабочую область так же, как мы делали это с нашими пользователями! Но это не намного круче, чем раньше. Действительно круто будет, когда мы спрашиваем данные о рабочей области «через» пользовательский объект.

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

? Файл: src/common/user/user.model.ts

Наконец нам нужно обновить файл схемы нашего пользователя, чтобы Apollo знал, как решить нашу (вложенную) ссылку на рабочую область пользователя.

? Файл: src/common/user/user.schema.ts

Давайте посмотрим на 2 основных изменения, которые мы только что внесли в файл схемы пользователя:

  1. The type User теперь обладает 2 дополнительными свойствами: workspaceId (что соответствует модели Mongoose) и workspace (это будет место, где мы поместим объект рабочей области, когда мы его спрашиваем).
  2. Сейчас есть свойство под названием User в наших развязчиках. Это одна из моих любимых частей GraphQL, поскольку она позволяет разрешать отдельные свойства типа. В приведенном выше примере мы решаем workspace Взяв WorkspaceId пользователя, а затем воспользовавшись Mongoose, чтобы получить его из базы данных для нас. Это то же самое, что мы делали для обычных разрешителей запросов, но на этот раз это вложенный объект.

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

1*agNIJbcqZBHGgveZKuRiBA

К черту так! Мы расскажем о том, что вы можете превратить в полностью рабочий сервер.

? Праздники моли! Вы работаете с GraphQL!

1*IZCJKz3761vChU1VFHfzkw

Авторизация?️‍

Поэтому у нас есть достаточно хороший GraphQL API. Но остается проблема: нет ограничений по поводу того, кто может получить доступ к нашим данным! Чтобы это исправить, нам нужно добавить аутентификацию и авторизацию.

✋ Подожди… аутентификация и авторизация не одинаковы?

Это распространенное заблуждение, но его важно понимать, поскольку это поможет вам создать лучшие API:

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

? Итак, как мы это реализуем?

Еще один замечательный вопрос, вы действительно любознательный человек! К сожалению, есть много способов сделать это в зависимости от того, как вы хотите, чтобы ваша программа работала. Например:

  • Возможно, вы захотите, чтобы пользователи регистрировались только с помощью аутентификации GitHub, а не с помощью электронной почты и пароля.
  • У вас может быть 3 разные роли пользователя, а не 100 подробных ролей пользователей.
  • Пользователей может не быть вообще, а вся ваша программа может использоваться анонимно.

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

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

~ Вот ссылка на демонстрационный репозиторий GraphQL ~

? Горячий бес! Нам удалось создать сервер GraphQL! Иди ты!

1*DduhOox_qT0srXwxjnkK7A

Если вам понравилась эта статья, отдайте ей оценку несколько шлепков (можно оставить до 50) или можно комментарий если у вас есть вопросы, я сделаю все возможное, чтобы ответить! ?

Следите за мной в Twitter.

Спасибо!

Больше сообщений Джека Скотта.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *