Вы можете получить исходные коды:

Репозиторий серверов

Клиентское репо

ГрафQL

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

GraphQL использует расширенную систему типизации для определения данных на сервере и для клиентских запросов.

Узнайте больше на GraphQL.org

Аполлон

Apollo — это полноценная платформа для реализации графа ваших данных. Он включает в себя две библиотеки времени выполнения, Apollo Server и Apollo Client, для создания API графа и выполнения запросов к нему. Он также включает инструменты разработчика, которые интегрируются с вашим существующим рабочим процессом и дают вам полное представление о производительности и безопасности вашего графа.

Причина, по которой мы решили использовать Apollo, заключается в том, что он реализует большинство полных функций спецификаций GraphQL, которые имеют две среды выполнения:

  • Сервер Apollo: для реализации сервера, который поддерживает множество фреймворков.
  • Клиент Apollo: для поддержки реализации на стороне клиента (Angular, Vanilla, React…).

Мы будем использовать пакеты Apollo для интеграции GraphQL с нашим базовым сервером Nodejs/Express и реализации нашего API.

ОТДЫХ против. ГрафQL

Representational State Transfer — это API, который позволяет передавать данные по HTTP-протоколу, который в основном используется для веб-приложений для реализации своего сервисного API и позволяет извлекать, отправлять и удалять данные для реализации CRUD.

REST является революционным и до сих пор используется крупными компаниями и командами для реализации своих API, но у него есть некоторые недостатки:

  • Чрезмерная выборка
  • /products?field=name&field=description&field=variants[*].price
  • недовыбор
  • /products?expand=productType&expand=variants[*].price.taxRate
  • Изменения и эволюция API
  • Версии
  • Устаревание
  • техническое обслуживание

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

  • Язык запросов данных
  • Разработано Facebook
  • Используется внутри компании с 2012 года.
  • Версия с открытым исходным кодом, опубликованная в июле 2015 г.
  • Реле выпущено в августе 2015 г.
  • Спецификация: https://facebook.github.io/graphql

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

REST по-прежнему очень распространен и при некоторых обстоятельствах все еще является отличным выбором.

Сервер Apollo (внедрение GraphQL-сервера)

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

Я предполагаю, что у вас уже есть базовый сервер Nodejs/Express (например: PORT 4000).

Давайте установим Apollo и GraphQL:

npm install graphql apollo-server-express --save

Вам также может потребоваться установить пакет cors для разрешения CORS (обмена ресурсами между источниками) для разрешения запросов из другого домена (только для разработки).

npm install cors --save

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

  • TypeDefs: ваша схема типов, которая определяет основной запрос и ваши типы данных.
  • Резолверы: сопоставление резолверов — это то, что сопоставляет каждую конечную точку запроса с функцией, которая запускается после отправки запроса.

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

/* schema.js */

const { gql } = require("apollo-server-express");
//Using template string literals 
module.exports = gql`
  type Author {
    name: String!
  }

  type Book {
    name: String!
    author: String!
    numPages: Int!
  }

  type Query {
    hello: String!
    books: [Book]
    book(name: String!): Book
  }
`;

У нас есть тип автора, который определяет его атрибут имени, тип книги определяет имя (обязательно), автора (обязательно) и numPages (обязательно), восклицательный знак в конце означает, что текущее поле является обязательным и не может быть пустым.

Тип Query является основной точкой входа для нашего GraphQL API, что означает, что они играют роли функций, которые позволяют нам вызывать его со стороны клиента, только объект Query доступен со стороны клиента, все остальное хранится на вашем сервере для выполнения. запрос.

Изучай СДЛ.

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

Давайте создадим нашу карту резольверов.

const { Books } = require("./constants");

module.exports = {
  Query: {
    hello() {
      return "Hello World from the Other Side!";
    },

    books() {
      return Books;
    },

    book(root, args, context) {
      const { name } = args;
      if (!name || name === "") return null;
      const foundBook = Books.find(book => book.name === name);
      if (!foundBook) return null;
      return foundBook;
    }
  }
};

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

hello() просто возвращает строку, так как мы ожидали наличие необходимой строки в схеме.

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

book() принимает некоторые аргументы, и они существуют по умолчанию в каждой функции-преобразователе apollo (функция находит книгу по имени и возвращает книгу или null).

  • root: это объект, который содержит возвращаемые данные из родительского запроса в случае, если текущий преобразователь является вложенным дочерним.
  • аргументы: аргументы запроса, отправляемые клиентом (пары ключ-значение). Помните, что вы не можете отправлять аргументы, отличные от тех, которые указаны в схеме.
  • context: это общий экземпляр объекта среди всех распознавателей, поэтому вы можете обмениваться данными между одним распознавателем и другим (запрос зависит от других запросов, например: аутентификация).

Протестируем наш сервер с помощью Apollo-playground — инструмента тестирования API, разработанного Prisma. Откройте http://localhost:4000/graphql

Ответ представляет собой объект с полем данных, которое содержит запрошенные вами данные.

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

Клиент Apollo (реализация приложения React)

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

Я создал и загрузил реагирующий проект с помощью create-react-app.

Давайте установим необходимые пакеты apollo и Graphql для нашего приложения React.

npm install apollo-boost react-apollo graphql --save

Вам также может понадобиться использовать styled-components для работы с CSS-in-JS.

npm install styled-components --save

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

/* components/books.jsx */
import React from "react";
//We use styled compoents to write CSS in JS for our React Components.
import styled from "styled-components/macro";

const BooksContainer = styled.div`
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
`;

const Book = styled.div`
  display: flex;
  flex-direction: column;
  min-height: 5em;
  padding: 25px;
  border: 1px solid rgba(15, 15, 15, 0.2);
  margin-right: 25px;
  border-radius: 4px;
`;

const BookTitle = styled.div`
  font-size: 20px;
  margin-bottom: 1em;
  color: #3d3d3d;
  font-weight: 700;
`;

const AuthorName = styled.div`
  font-size: 17px;
`;

const NumPages = styled.div`
  color: rgba(15, 15, 15, 0.5);
  font-size: 14px;
`;

export function Books(props) {
  const { books } = props;

  //NOTE: loop through the books array received through props and render each one.

  return (
    <BooksContainer>
      {books.map((book, idx) => {
        return (
          <Book key={`${book.name}-${idx}`}>
            <BookTitle>{book.name}</BookTitle>
            <AuthorName>{book.author}</AuthorName>
            <NumPages>{book.NumPages}</NumPages>
          </Book>
        );
      })}
    </BooksContainer>
  );
}

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

/* App.jsx */ 
import React from "react";
import "./App.css";
import ApolloClient, { gql } from "apollo-boost";
import { ApolloProvider, Query } from "react-apollo";
import { Books } from "./components/books";

//We write our GraphQL Query 
const GET_BOOKS = gql`
  query getBooks {
    myBooks: books {
      name
      author
      numPages
    }
  }
`;

Запрос GraphQL должен быть написан в литеральном парсере шаблона gql для обработки и отправки по сети.

Сначала мы пишем имя запроса getBooks, а внутри него мы указываем, какой ресурс (конечная точка) мы запрашиваем, в этом случае книги мы также используем псевдоним для создания поля, содержащего все извлеченные книги с именем myBooks вместо books.

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

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

function App() {
  //Create ApolloClient instance 
  //Provide your GraphQL API Endpoint
  const client = new ApolloClient({ uri: "http://localhost:4000/graphql" });
  
  /* ApolloProvider uses the context API, it has to take the client instance 
     and then provide it to all children through ApolloConsumer  
  */

  /* Query is imported from react-apollo which takes care of running the GET_BOOKS query 
     and provides fetched data through render-props.
  */  

  return (
    <ApolloProvider client={client}>
      <div className="App">
        <h3>Store Books</h3>
        <Query query={GET_BOOKS}>
          {props => {
            console.log("Props: ", props);
            const { error, loading, data } = props;
            if (error) return <div>Error: {error.message}</div>;
            if (loading) return <div>Loading...</div>;
            if (!data && !data.myBooks) return <div>No Books Found!</div>;
            return <Books books={data.myBooks} />;
          }}
        </Query>
      </div>
    </ApolloProvider>
  );
}

export default App;

ApolloProvider использует React Context API для передачи всем своим дочерним элементам клиентской поддержки, чтобы сделать запрос GraphQL Query к инициализированной конечной точке.

Компонент запроса принимает ваш запрос GraphQL и выполняет его, а затем предоставляет извлеченные данные (асинхронно) через Render-Props React API, который дает нам функцию обратного вызова с нужными данными, ошибками и реквизитами загрузки.

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

Откройте приложение React, вы должны увидеть список книг.