|
@@ -0,0 +1,187 @@
|
|
|
+GraphQL
|
|
|
+==========
|
|
|
+
|
|
|
+**[GraphQL](https://graphql.org/)** - слой приложения, который обеспечивает
|
|
|
+удобный язык запросов к бэку.
|
|
|
+
|
|
|
+**GraphQL** используется:
|
|
|
+- На **backend** для того, что бы запустить тот или иной код для сбора данных.
|
|
|
+ Обычно это запросы к СУБД через **Sequelize** или **Mongoose**.
|
|
|
+- На **frontend** для того, что бы сделать запрос к **backend**.
|
|
|
+
|
|
|
+
|
|
|
+Таким образом **GraphQL** берет на себя передачу данных с бэка на фронт
|
|
|
+(**AJAX**)
|
|
|
+
|
|
|
+
|
|
|
+GraphQL minimal
|
|
|
+----
|
|
|
+
|
|
|
+### Устанавка
|
|
|
+
|
|
|
+```bash
|
|
|
+npm install --save express-graphql graphql`
|
|
|
+```
|
|
|
+
|
|
|
+### Подключение
|
|
|
+
|
|
|
+```javascript
|
|
|
+const express_graphql = require('express-graphql');
|
|
|
+const { buildSchema } = require('graphql');
|
|
|
+```
|
|
|
+
|
|
|
+### Схема.
|
|
|
+
|
|
|
+По аналогии с **Sequelize** и **Mongoose** вы указываете **схему** - структуру
|
|
|
+ваших данных. Если в **ORM** и **ODM** это делается с помощью ассоциативных
|
|
|
+массивов, то в **GraphQL** используется специальный язык:
|
|
|
+
|
|
|
+```javascript
|
|
|
+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` описывает структуру поста, она во многом повторяет схему для **ORM**/**ODM**
|
|
|
+
|
|
|
+#### Типы данных
|
|
|
+
|
|
|
+С примитивами все достаточно грустно, `String` и `Int`. Массивы декларируются c помощью
|
|
|
+`[]`
|
|
|
+
|
|
|
+### Резолверы
|
|
|
+
|
|
|
+**Резолверами** в **GraphQL** называют функции, которые запускаются движком **GraphQL**
|
|
|
+для реализации тех или иных запросов или мутаций в реальной **CУБД**.
|
|
|
+
|
|
|
+Например, в простейшем виде:
|
|
|
+
|
|
|
+```javascript
|
|
|
+async function getPost({id}){
|
|
|
+ return await Post.findById(id)
|
|
|
+}
|
|
|
+
|
|
|
+async function getPosts({id}){
|
|
|
+ return await Post.findAll({})
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### Подключение **express-graphql** **middleware**
|
|
|
+
|
|
|
+При наличии схемы и резолверов остается отдать их в использование **GraphQL**
|
|
|
+и подключить **GraphQL** к **express** для обработки входящих запросов:
|
|
|
+
|
|
|
+```javascript
|
|
|
+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. он будет доступен по адресу /graphiql вашего бэка
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+### Frontend
|
|
|
+Есть разные степени завязки **фронтэнда** на **GraphQL**, однако в простейшем случае достаточно небольшой библиотеки для взаимодействия с **бэкэндом**
|
|
|
+
|
|
|
+#### Установка
|
|
|
+
|
|
|
+```bash
|
|
|
+npm install --save graphql graphql-express
|
|
|
+```
|
|
|
+
|
|
|
+#### Подключение
|
|
|
+```javascript
|
|
|
+import { GraphQLClient } from 'graphql-request'
|
|
|
+
|
|
|
+const gql = new GraphQLClient("http://localhost:4000/graphql", { headers: {} })
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+Адрес должен соответствовать конфигурации **бэкэнда** - убедитесь что ваш **express** висит на нужном порту (4000 в примере) и что первый параметр в `app.use` (**endpoint**) верен.
|
|
|
+#### Запрос на бэкэнд
|
|
|
+
|
|
|
+```javascript
|
|
|
+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** - тестовой консоли разработчика (доступна по ссылке `/graphiql` на вашем бэке). Потом копипастите его в код и далее **Developer Tools** и/или `console.log` в помощь.
|
|
|
+
|
|
|
+## Почитать
|
|
|
+- [статья на хабре](https://habr.com/post/326986/)
|
|
|
+
|