Руководство по настройке сервера Apollo в Node.JS для подключения к источнику данных RESTful

В этой короткой статье давайте рассмотрим, как мы могли бы создать простой запрос graphQL, который извлекает данные из конечной точки RESTful. Для этой цели мы будем использовать Node.js и Apollo Server.

В этой статье мы рассмотрим в качестве примера простой ресурс Users. Цель этой статьи — просто описать шаги и конфигурации, необходимые для создания запроса, который использует существующую конечную точку REST в качестве источника данных, используя сервер apollo graphQL.

Больше контента на PlainEnglish.io.

Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord.

Хотите повысить узнаваемость и принятие вашего технологического стартапа? Посмотрите Цирк.

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

Без лишних слов, давайте начнем:

Инициализируйте проект GraphQL:

Давайте создадим новый каталог с именем gserver, а затем изменим каталог, набрав cd gserver.

Теперь давайте инициируем проект с yarn init -y

Добавьте зависимости:

Нашими основными зависимостями являются пакеты graphQL и apollo-server. Итак, давайте добавим их в проект:

yarn add apollo-server graphql

Чтобы включить автоматический перезапуск сервера при изменениях во время разработки, добавим nodemon в качестве dev-зависимости:

yarn add --dev nodemon

Теперь наш package.json должен выглядеть примерно так:

{
  "name": "gserver",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "type": "module",
  "dependencies": {
    "apollo-server": "^3.10.2",
    "graphql": "^16.6.0"
  },
  "devDependencies": {
    "nodemon": "^2.0.19"
  }
}

Примечание. Я использую Yarn в качестве менеджера пакетов, но вы можете использовать npm, если хотите.

Создайте индексный файл:

В корне проекта создайте файл с именем index.js, который будет точкой входа для нашего сервера graphQL.

// index.js
import { ApolloServer } from "apollo-server";
const server = new ApolloServer();
server
  .listen({port: process.env.PORT || 5000})
  .then(({url})=> console.log(`gserver at : ${url}`));

Теперь, когда у нас настроен базовый сервер graphQL, давайте добавим скрипт в наш package.json, чтобы запустить его в режиме разработки с nodemon:

{
...existing package.json content
"scripts": {
    "dev": "nodemon index.js"
  }
 ... remaining content
}

Создайте схему пользователя:

Схемы — это способы, которыми мы определяем типы и, следовательно, базовые структуры для запросов и мутаций в graphQL.

Давайте быстро создадим каталог с именем schema в корне проекта.

Мы будем использовать специальный тег gql для определения наших схем.

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

// schema/user.js
import { gql } from "apollo-server";
export const User = gql`
  type User {
    id: ID!,
    email: String,
    name: String
}
`

для UUID мы используем специальный тип в graphQL под названием ID, а отметка ! означает, что он не может быть нулевым.

Таким образом, мы определили тип с именем User и создали схему для нашего пользовательского объекта.

Определите запрос пользователей:

В graphQL queries, который извлекает данные (можно считать эквивалентным запросу GET в терминах REST), а также должен иметь четко определенную схему. В этом примере мы просто хотели бы получить всех пользователей из базовой конечной точки пользовательской службы. Итак, давайте определим наш запрос, чтобы получить всех пользователей:

// schema/query.js
import { gql } from "apollo-server";
export const Query = gql`
  type Query {
    users: [User]
}
`

Поскольку с помощью запроса users мы получим более одного пользователя, мы указываем его тип как массив типа User (который мы определили ранее в схеме).

Для простоты импорта давайте создадим индексный файл в каталоге схемы и предоставим определенную схему следующим образом:

// schema/index.js
export { User } from './user.js';
export { Query } from './query.js';

Запустите сервер:

давайте изменим точку входа нашего сервера index.js, чтобы включить схемы, которые мы определили:

// index.js
import { ApolloServer } from "apollo-server";
import { Query, User } from "./schema/index.js";
const server = new ApolloServer({typeDefs:[Query,User]});
server
  .listen({ port: process.env.PORT || 5000 })
  .then(({ url }) => console.log(`gserver at : ${url}`));

Теперь давайте наберем yarn dev в терминале:

когда мы открываем наш браузер по адресу http://localhost:5000 , если все прошло хорошо, мы должны увидеть следующий экран:

Когда вы нажмете кнопку Query Your Server, вы попадете в студию Apollo, где сможете найти определенную схему:

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

Служба RESTful для пользователей:

У нас есть служба users, работающая на порту 3000, которая в настоящее время возвращает следующий ответ для конечной точки localhost:3000/users:

Это обычная конечная точка RESTful, работающая на экспресс-сервере. Нам не нужно сильно беспокоиться о его реализации, поскольку основное внимание в этой статье уделяется взаимодействию существующей конечной точки REST с запросом graphQL.

Пользователи DataSource и Resolver:

Теперь нам нужно сопоставить наш запрос graphQL users для получения данных из указанной выше конечной точки RESTful. Мы могли бы сделать этот graphQL, определив dataSource, а затем сопоставив его с resolver.

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

Источник данных пользователей:

Поскольку мы собираемся использовать конечную точку отдыха в качестве источника данных, давайте установим пакет apollo-datasource-rest, созданный командой Apollo. Этот пакет заботится о таких важных вещах, как кэширование, поэтому нам не нужно об этом беспокоиться.

Добавим пакет в наш проект:

yarn add apollo-datasource-rest

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

// datasource/users.js
import { RESTDataSource } from "apollo-datasource-rest";
export class UsersAPI extends RESTDataSource {
  constructor(){
    super();
    this.baseURL = "http://localhost:3000/"
  }
  async getAllUsers() {
    return this.get('users')
  }
}

baseURL должен быть базовым URL-адресом для нашего usersservice.

Индексный файл для каталога datasource будет следующим:

// datasource/index.js
import { UsersAPI } from "./users.js";
export const dataSources = () => ({
  UsersAPI: new UsersAPI()
});

Резолвер пользователей:

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

// resolvers/users.js
export const userResolvers = {
  users: (parent, args, {dataSources}, info) =>   dataSources.UsersAPI.getAllUsers()
}

Это будет иметь смысл, когда мы свяжем его с точкой входа сервера в следующем сеансе. Для индекса resolvers добавим следующее:

// resolvers/index.js
import { userResolvers } from "./users.js";
export const resolvers = {
  Query: {
    ...userResolvers
  }
}

Подключите его к серверу:

Мы подключим источник данных и преобразователь к нашему серверу, изменив файл index.js в корне проекта следующим образом:

// index.js
import { ApolloServer } from "apollo-server";
import { Query, User } from "./schema/index.js";
import { resolvers } from "./resolver/index.js";
import { dataSources } from "./datasource/index.js";
const server = new ApolloServer({ typeDefs:[Query,User ], resolvers, dataSources });
server
  .listen({ port: process.env.PORT || 5000 })
  .then(({ url }) => console.log(`gserver at : ${url}`));

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

Как мы видим, в отличие от конечной точки REST, которая возвращает нам все поля, в запросе graphQL мы можем выбрать только те поля, которые нам нужны, из схемы users.

Заключение:

Таким образом, мы создали работающий запрос graphQL, который извлекает данные из существующей конечной точки REST. Мы также увидели, какие различные компоненты и конфигурации необходимы, и как они связаны друг с другом, чтобы это произошло.