DevGang
Авторизоваться

Начните строить API-интерфейсы GraphQL с Node 

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

Что такое GraphQL?

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

Что мы строим

Чтобы следовать этому руководству, вам понадобится Node v8.x или более поздней версии, а также некоторые навыки работы с командной строкой. 

Мы собираемся создать приложение API для подсветки книг, что позволит нам хранить запоминающиеся фрагменты из того, что мы читаем. Пользователи API смогут выполнять операции «CRUD» (создавать, читать, обновлять, удалять) со своими highlight:

  1. Создать новый highlight
  2. Прочить отдельный highlight, а также список highlight.
  3. Обновите содержание
  4. Удалить

Начало работы

Чтобы начать, сначала создайте новый каталог для нашего проекта, инициализируйте новый Node проект и установите зависимости, которые нам понадобятся:

# make the new directory
mkdir highlights-api
# change into the directory
cd highlights-api
# initiate a new node project
npm init -y
# install the project dependencies
npm install apollo-server graphql
# install the development dependencies
npm install nodemon --save-dev

Прежде чем двигаться дальше, давайте разберем наши зависимости:

  1. apollo-server это библиотека, которая позволяет нам работать с GraphQL в нашем приложении Node. Мы будем использовать его в качестве автономной библиотеки.
  2. graphql включает в себя язык GraphQL и является необходимой зависимостью apollo-server.
  3. nodemon это полезная библиотека, которая будет следить за изменениями в нашем проекте и автоматически перезагружать наш сервер.

Установив наши пакеты, давайте теперь создадим корневой файл нашего приложения с именем  index.js. На данный момент мы выведем сообщение в этом файле с помощью console.log():

console.log("📚 Hello Highlights");

Чтобы упростить процесс разработки, мы обновим объект scripts в нашем файле package.json, чтобы использовать пакет nodemon:

"scripts": {
  "start": "nodemon index.js"
},

Теперь мы можем запустить наше приложение, набрав npm start в терминале. Если все работает правильно, вы увидите  📚 Hello Highlights в терминал.

Типы схем GraphQL

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

  1. String:  строка с кодировкой символов UTF-8
  2. Boolean:  истинное или ложное значение
  3. Int:  32-разрядное целое число
  4. Float: значение с  плавающей точкой
  5. ID:  уникальный идентификатор

Мы можем построить схему для API с этими основными компонентами. В файле с именем schema.js мы можем импортировать библиотеку gql и подготовить файл для нашего синтаксиса схемы:

const { gql } = require('apollo-server');

const typeDefs = gql`
  # The schema will go here
`;

module.exports = typeDefs;

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

const typeDefs = gql`
  type Highlight {
  }
`;

Каждое highlight будет иметь уникальный идентификатор, некоторый контент, заголовок и автора. Схема Highlight будет выглядеть следующим образом:

const typeDefs = gql`
  type Highlight {
    id: ID
    content: String
    title: String
    author: String
  }
`;

Мы можем сделать некоторые из этих полей обязательными, добавив восклицательный знак:

const typeDefs = gql`
  type Highlight {
    id: ID!
    content: String!
    title: String
    author: String
  }
`;

Хотя мы определили тип объекта для наших основных моментов, мы также должны предоставить описание того, как клиент будет получать эти данные. Это называется query. Вскоре мы углубимся в запросы, но сейчас давайте опишем в нашей схеме способы, которыми кто-то будет получать highlight. При запросе всех наших данные будут возвращены в виде массива (представленного в виде [Highlight]), а когда мы хотим получить одно выделение, нам нужно будет передать идентификатор в качестве параметра.

const typeDefs = gql`
  type Highlight {
    id: ID!
    content: String!
    title: String
    author: String
  }
  type Query {
    highlights: [Highlight]!
    highlight(id: ID!): Highlight
  }
`;

Теперь в файле index.js мы можем импортировать наши определения типов и настроить сервер Apollo:

const { ApolloServer } = require('apollo-server');
const typeDefs = require('./schema');

const server = new ApolloServer({ typeDefs });

server.listen().then(({ url }) => {
  console.log(`📚 Highlights server ready at ${url}`);
});

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

[nodemon] 2.0.2
[nodemon] to restart at any time, enter `rs`
[nodemon] watching dir(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node index.js`
📚 Highlights server ready at http://localhost:4000/

Посещение URL в браузере запустит приложение GraphQL Playground, которое предоставляет пользовательский интерфейс для взаимодействия с нашим API.

GraphQL Resolvers

Хотя мы разработали наш проект с начальной схемой и настройкой сервера Apollo, мы пока не можем взаимодействовать с нашим API. Для этого мы представим распознаватели. Резольверы выполняют именно то действие, которое подразумевает их имя; они разрешают данные, запрошенные пользователем API. Мы напишем эти преобразователи, сначала определив их в нашей схеме, а затем реализовав логику в нашем коде JavaScript. Наш API будет содержать два типа преобразователей: запросы и мутации.

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

let highlights = [
  {
    id: '1',
    content: 'One day I will find the right words, and they will be simple.',
    title: 'Dharma Bums',
    author: 'Jack Kerouac'
  },
  {
    id: '2',
    content: 'In the limits of a situation there is humor, there is grace, and everything else.',
    title: 'Arbitrary Stupid Goal',
    author: 'Tamara Shopsin'
  }
]

Запросы

Запрос запрашивает определенные данные из API в желаемом формате. Затем запрос вернет объект, содержащий данные, запрошенные пользователем API. Запрос никогда не изменяет данные; это только доступ к нему. Мы уже написали два запроса в нашей схеме. Первый возвращает массив бликов, а второй возвращает определенный блик. Следующим шагом является написание распознавателей, которые будут возвращать данные.

В файл index.js мы можем добавить объект резолверов, который может содержать наши запросы:

const resolvers = {
  Query: {
    highlights: () => highlights,
    highlight: (parent, args) => {
      return highlights.find(highlight => highlight.id === args.id);
    }
  }
};

Запрос highlights возвращает полный массив данных. Запрос highlight принимает два параметра: parent и args. parent это первый параметр любого запроса GraqhQL в Apollo Server и предоставляет способ доступа к контексту запроса. Параметр args позволяет получить доступ аргументов при условии пользователей. В этом случае пользователи API будут предоставлять аргумент id для доступа к конкретному выделению.

Затем мы можем обновить нашу конфигурацию сервера Apollo, включив в нее преобразователи:

const server = new ApolloServer({ typeDefs, resolvers });

После написания наших распознавателей запросов и обновления сервера Apollo мы теперь можем запрашивать API с помощью GraphQL Playground. Чтобы получить доступ к GraphQL Playground, ведит http://localhost:4000 в свой веб-браузер.

Запрос отформатирован так:

query {
  queryName {
      field
      field
    }
}

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

query {
  highlights {
    id
    content
    title
    author
  }
}

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

query {
  highlights {
    title
    author
  }
}

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

query {
  highlight(id: "1") {
    content
  }
}

Мутации

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

Первым шагом к обновлению чего-либо в GraphQL является написание схемы. Мы можем включить мутации в нашу схему, добавив тип мутации в наш файл schema.js:

type Mutation {
  newHighlight (content: String! title: String author: String): Highlight!
  updateHighlight(id: ID! content: String!): Highlight!
  deleteHighlight(id: ID!): Highlight!
}

Наша мутация newHighlight примет требуемое значение содержания вместе с опциональными значениями title и author и возвращает Highlight. Мутация updateHighlight требует, чтобы были указаны id и content и возвращает обновленным Highlight. Наконец, мутация deleteHighlight примет аргумент ID и вернет удаленное выделение.

С обновленной схемой, включающей в себя мутации, теперь мы можем обновить  resolvers в нашем файле index.js для выполнения этих действий. Каждая мутация будет обновлять наш массив данных highlights.

const resolvers = {
  Query: {
    highlights: () => highlights,
    highlight: (parent, args) => {
      return highlights.find(highlight => highlight.id === args.id);
    }
  },
  Mutation: {
    newHighlight: (parent, args) => {
      const highlight = {
        id: String(highlights.length + 1),
        title: args.title || '',
        author: args.author || '',
        content: args.content
      };
      highlights.push(highlight);
      return highlight;
    },
    updateHighlight: (parent, args) => {
      const index = highlights.findIndex(highlight => highlight.id === args.id);
      const highlight = {
        id: args.id,
        content: args.content,
        author: highlights[index].author,
        title: highlights[index].title
      };
      highlights[index] = highlight;
      return highlight;
    },
    deleteHighlight: (parent, args) => {
      const deletedHighlight = highlights.find(
        highlight => highlight.id === args.id
      );
      highlights = highlights.filter(highlight => highlight.id !== args.id);
      return deletedHighlight;
    }
  }
};

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

mutation {
  newHighlight(author: "Adam Scott" title: "JS Everywhere" content: "GraphQL is awesome") {
    id
    author
    title
    content
  }
}

Затем мы можем написать мутации, чтобы обновить выделение:

mutation {
  updateHighlight(id: "3" content: "GraphQL is rad") {
    id
    content
  }
}

И удалить выделение:

mutation {
  deleteHighlight(id: "3") {
    id
  }
}

Источник:

#NodeJS #GraphQL #Apollo
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

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

Попробовать

Оплатив хостинг 25$ в подарок вы получите 100$ на счет

Получить