graphql.md 6.9 KB

GraphQL

GraphQL - слой приложения, который обеспечивает удобный язык запросов к бэку. Является альтернативой для REST, JSON-RPC и прочих протоколов общения.

GraphQL используется:

  • На backend для того, что бы запустить тот или иной код для сбора данных. Обычно это запросы к СУБД через Sequelize или Mongoose.
  • На frontend для того, что бы сделать запрос к backend.

Таким образом GraphQL берет на себя передачу данных с бэка на фронт (AJAX)

GraphQL minimal

Backend

Установка

npm install --save express-graphql graphql

Подключение

const express_graphql = require('express-graphql');
const { buildSchema } = require('graphql');

Схема.

По аналогии с Sequelize и Mongoose вы указываете схему - структуру ваших данных. Если в ORM и ODM это делается с помощью ассоциативных массивов, то в GraphQL используется специальный язык:

var schema = buildSchema(`
    type Query {
        getPost(id: String!): Post
        getPosts: [Post]
        getComments(id: Int!): [Comment]
        getSubComments(id: Int!): [Comment]
    }
    type Mutation {
        createPost(title: String!, text: String!): Post
        createComment(postID: Int!, text: String!): Post
    }

    type Post {
        id: Int
        title: String
        text:  String
        age:   String
        tagz:  [String]
        comments: [Comment]
        timestamp: Int
        key: String
    }
    type Comment {
        id: Int
        text:  String
        age:   String
        commentId: Int
    }
`);

В примере выше:

- `type Query` (запрос) отвечает за виды запросов, которые вы можете посылать с
    фронта. В данном случае реализовано четыре вида запросов:
    - `getPost` - один пост из СУБД. 
    - `getPosts` - лента постов
    - `getComments` - комментарии верхнего уровня 
    - `getSubComments` - комментарии к комментариям
- `type Mutation` (мутация) отвечает за запросы _на изменение_ данных:
    - `createPost`
    - `createComment`
- `type Post` описывает структуру поста, она во многом повторяет схему для **ORM**/**ODM**
- `type Comment` описывает структуру комментария.
Типы данных

С примитивами все достаточно грустно, String и Int. Массивы декларируются c помощью []

Резолверы

Резолверами в GraphQL называют функции, которые запускаются движком GraphQL для реализации тех или иных запросов или мутаций в реальной CУБД.

Например, в простейшем виде:

async function getPost({id}){
   return await Post.findById(id)
}

async function getPosts(){
   return await Post.findAll({})
}

Подключение express-graphql middleware

При наличии схемы и резолверов остается отдать их в использование GraphQL и подключить GraphQL к express для обработки входящих запросов:

var root = {
    getPost,
    getPosts,
    getPostComments,
    getSubComments,
    createPost,
    createComment,
};



// Create an express server and a GraphQL endpoint
var app = express();
app.use(cors())

app.use('/graphql', express_graphql({
    schema: schema,
    rootValue: root,
    graphiql: true
}));

В примере выше:

- `root` является _корневым резолвером_ и отвечает за связь 
    названий запросов и мутаций из схемы с **резолверами**
- `app.use` используется для подключения **GraphQL** к **express**:
    - `schema` указывает на схему
    - `rootValue` - корневой резолвер
    - `graphiql` - ключ, который включает отладочный интерфейс **GraphQL**.
        он будет доступен по адресу `/graphql` вашего **бэка**

Frontend

Есть разные степени завязки фронтэнда на GraphQL, однако в простейшем случае достаточно небольшой библиотеки для взаимодействия с бэкэндом

Установка

npm install --save graphql-request

Подключение

import { GraphQLClient } from 'graphql-request'

const gql = new GraphQLClient("http://localhost:4000/graphql", { headers: {} })

Адрес должен соответствовать конфигурации бэкэнда - убедитесь что ваш express висит на нужном порту (4000 в примере) и что первый параметр в app.use (endpoint) верен.

Запрос на бэкэнд

gql.request(`query getPost($postID: String!){
                      getPost(id:$postID){
                            id
                            title
                            timestamp
                            tagz
                          }
                        }`, {postID: this.props.match.params.id}) 
    .then(data => store.dispatch({type: "DATA", data}))

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

Отладка

Backend

console.log в резолвере позволит вам увидеть параметры запроса, сам факт запуска резолвера и, возможно, результат

Frontend

Текст запроса проще всего отладить в GraphIQL - тестовой консоли разработчика. Потом копипастите его в код и далее Developer Tools и/или console.log в помощь.

Почитать