В моей предыдущей статье "ну Русском. Оригинал" я рассказывал как можно вдвое сократить свой код и время, если вы используете GraphQL вместе с Mongoose.
Сегодня речь также пойдет о технологии GraphQL и если вы работаете с ней то данная статья сможет помочь вам сохранить приличное количество времени на разработку. Оригинал статьи на английском вы можете найту по ссылке.
» Ссылка на сам модуль: graphql-auto-generating-cms.
Как вы уже наверное догадались данный модуль использует вашу готовую GraphQL схему для генерации полнофункциональной CMS. Вам не нужно будет тратить кучу времени на разработку административной панели, и вы сможете больше сосредоточиться на бизнес процессах вашего проекта и на его архитектуре.
Важным достоинством данного модуля является то что он не требует от вас никаких изменений в вашем готовом коде или архитектуре проекта, что делает его интеграцию максимально простым даже на уже готовых проектах.
У вас есть два способа использовать данный модуль.
- Первый максимально быстрый и подойдет для нового проекта. От вас требуется только GraphQL схема и следование легкому паттерну по наименованию GraphQL методов и типов.
- И второй способ который не требует от вас следованию никаких паттернов, и может быть легко интегрирован в уже готовый проект. Все что от вас нужно предоставить конфигурационный объект вместе с GraphQL схемой.
На данный момент модуль не поддерживает GraphQLList, вложенные объекты и загрузку файлов, их поддержка будет реализована в будущих версиях. На данный момент вы можете легко обойти эти ограничения используя самописные функции и компоненты которыми вы можете дополнить CMS, мы рассмотрим как это сделать в данной статье.
Исходя из всего выше перечисленного давайте разделим текущую статью на несколько пунктов:
- Общие правила
- Подготовка к работе
- Первый способ использования, с паттерном
- Второй способ использования, с конфигурационным объектом
- Дополнение CMS своими компонентами и функциями
Общие правила
Модуль будет использовать graphQL тип как сущность которая будет доступна в боковом меню CMS.
Чтобы исключить типы которые используются только как вложенные объекты. Соответственно за сущность будут взяты только те типы у которых есть один «Query» метод и хотя бы один «Mutation» метод.
Каждый тип может иметь только один «Query» [find], который будет использоваться для получения массива объектов, или для получение одного объекта с использованием аргумента «id» или "_id" в зависимости какой тип базы данных вы используете. Так же тип может иметь один или несколько из следующих «Mutation» методов [create, update, remove].
Query метод должен обязательно поддерживать следующие аргументы:
{
offset: number,
limit: number,
id: number || _id: string // в зависимости от вашего хранилища
}
Аргументы «offset» и «limit» будут использованы для нумерации страниц и что бы получать данные с сервера по порциям, а не скажем получить сразу 50т. объектов из за чего ваше приложение просто повиснет.
На серверной стороне это может выглядеть следующим образом:
let {offset, limit} = args;
return new Promise((resolve, reject) => {
Ingredients.find(query).skip(offset).limit(limit).exec((err, res) => err ? reject(err) : resolve(res));
});
И аргумент «id» будет использован чтобы получить один экземпляр. Если вы будете использовать метод вроде «findOne» чтобы вернуть один элемент используя «id» убедитесь что вы вернете его внутри массива, так как graphQL будет ожидать именно массив, даже если это один элемент.
Подготовка к работе
Установка:
npm i -S graphql-auto-generating-cms
На серверной стороне мы должны запустить middleware через которое будем обрабатывать GrpahQL схему, в примере ниже мы будем использовать URL "/graphql_cms_endpoint" в качестве конечной точки:
…
import express from 'express';
import graphqlCMS from 'graphql-auto-generating-cms/lib/middleware';
import schema from '../schema';
const printSchema = require('graphql/utilities/schemaPrinter').printSchema;
let app = express();
let config = {schema: printSchema(schema)}
app.use('/graphql_cms_endpoint', graphqlCMS(config));
…
app.listen(port)
После этого мы можем использовать наш React компонент на клиентской стороне. Вы можете загрузить его по отдельной ссылке или как обычный React компонент.
Внутри роутера:
...
import GraphqlCMS from 'graphql-auto-generating-cms';
export default (
<Router onUpdate={() => window.scrollTo(0, 0)} history={browserHistory}>
<Route
path='/graphql-cms'
endpoint='/graphql_cms_endpoint'
graphql='/graphql'
components={GraphqlCMS}
/>
…
</Router>
Или в качестве компонента:
<GraphqlCMS
endpoint='/graphql_cms_endpoint'
graphql='/graphql'
/>
В свойстве «endpoint» мы указываем тот же URL который мы использовали на серверной стороне.
В свойстве «graphql» ссылка на ваш GraphQL API.
Второй вариант хорошо подходит если вы скажем хотите дополнить CMS функциями авторизации и тп. Вы просто вставите его как дочерний компонент в Layout с навигационной панелью, системой авторизации и тп.
Первый способ использования, с паттерном
Чтобы использовать быстрый способ генерации вашей CMS, без дополнительных конфигураций, вам нужно следовать следующему простому паттерны в наименовании GrpahQL «Query» и «Mutation» методах.
[graphql Type name]_[action]
пример:
productType_find
productType_create
productType_update
productType_remove
Сортировка пунктов меню и input полей в CMS будет идентично порядку свойств в объекте.
Например если в нашей схеме следующий порядок типов:
{
productType: {},
userType: {},
categoryType: {},
...
}
То в боковой панели, пункты меню будут иметь тот же порядок:
productType
userType
categoryType
То же самое относится к порядку полей типов, их порядок будет взят за основу построения UI для страницы просмотра одного экземпляра элемента, или для добавления нового элемента:
let productType = new GraphQLObjectType({
name: 'productType',
fields: {
_id: {type: GraphQLString},
title: {type: GraphQLString},
shortDescription: {type: GraphQLString},
price: {type: GraphQLString},
isPublished: {type: GraphQLBoolean},
createdAt: {type: GraphQLString},
updatedAt: {type: GraphQLString},
bulletPoints: {type: GraphQLString},
scienceShort: {type: GraphQLString},
scienceFull: {type: GraphQLString},
}
});
Соответственно если вы хотите изменить порядок пунктов в боковом меню, или поменять порядок input полей, вы просто должны поменять местами свойства в GrpahQL схеме.
Второй способ использования, с конфигурационным объектом
Преимущества второго способа:
- Вам не нужно вносить никакие изменения в текущий код и/или архитектуру
- Не обязательно использовать naming паттерн
- Вы можете запретить любые «Mutation» методы для каждого типа
- Вы можете изменить сортировку полей и бокового меню, без изменения в схеме, просто меняя порядок правил в свойстве «rules»
- Вы можете задавать произвольное название пунктов бокового меню, и всех полей. Изначально в качестве названий пунктов меню будут использованы имена graphQL типов, и в качестве название полей, будет использовано название свойств типа
- Вы можете запретить редактирование любых полей
- Вы можете задать произвольно какие свойства будут использоваться внутри таблицы со списком документов. Изначально для поля [#/ID] будет использовано свойство «id» или "_id" типа, и в качестве [title] будет использовано второе свойство GraphQL типа
- Вы можете изменять какое поле нужно использовать для конкретного свойства, к примеру использовать input или textarea, изменить input тип, скажем на «date» и тп
Давайте рассмотрим как это работает, все что вам для этого нужно, расширить конфигурационный объект на серверной стороне. Все поля кроме «schema» не обязательны к использованию.
let config = {schema: printSchema(schema)}
app.use('/graphql_cms_endpoint', graphqlCMS(config));
let config = {
schema: printSchema(schema),
// ваша "printed" схема [required]
exclude: ['paymentType', 'invoiceType'],
//graphql типы котрые вы хотите исключить из CMS
rules: {
// дерево правил для каждого или некоторых graphQL типов
categoryType: {
// имя вашего graphQL типа
label: 'Categories',
// кастомное имя которое будет использовано в боков меню
listHeader: {
// данные из этого свойства используются для таблицы объектов
// первый столбец [id] и второй [title]
// вы можете использовать одно или несколько свойств для каждого столбца
// в UI они будут отображаться как “String” + “ “ + “String”
id: ['id'],
title: ['description']
},
resolvers: {
// если вы не хотите использовать naming паттерн
// вы должны указать имя для каждого
// Query's и Mutation's метода для данного типа
find: {
resolver: 'getCategories'
// Query method name
},
create: {
resolver: 'addCategory'
// Mutation method name
allowed: true
},
update: {
resolver: 'updateCategory'
// Mutation method name
allowed: true
},
remove: {
allowed: false
// если вы не хотите предоставлять доступ
// к данному методу со стороны клиента
// вы можете его запретить, указав true
// кром “find”, его нельзя запретить
}
},
fields: {
_id: {},
sortNumber: {
label: 'custom field name to show in UI',
inputControl: 'input',
// can be “input” or “textarea”
inputType: 'number',
// can be any input type: date, text, file etc.
disabled: true,
// запретить редактирование данного поля
exclude: false,
// не отображать данное поле в CMS
},
name: {},
// вы также можете использовать пустой объект
// скажем если вы хотите просто отсортировать элементы
createdAt: {},
updatedAt: {},
isPublished: {}
}
}
}
}
Дополнение CMS своими компонентами и функциями
Вы также можете дополнить пункты меню CMS своими React компоненты с дополнительными функциями, скажем для каких нибудь кастомных решений, таких как статистика или общий dashboard.
Все что для этого нужно просто добавить еще одно свойство 'newMenuItems' на клиентской стороне, к компоненту:
<Route
path='/graphql-cms'
endpoint='/graphql_cms_endpoint'
graphql='/graphql'
newMenuItems={customPages}
components={GraphqlCMS}
/>
Через которое мы отправляем массив с дополнительными пунктами меню и компонентами, структура объектов в массиве ниже:
let customPages = [
{
label: 'Custom Page',
secret: 'uniqeForEachComponentSecret',
view: {
secret: 'sameUniqeComponentSecret',
component: CustomDashboard // Ваш React компонент
}
}
]
Код выше будет выглядеть следующим образом:
Спасибо за внимание, надеюсь данный модуль будет вам полезен. Чтобы быть в курсе обновлений или новых функций, вы можете добавить проект в избранные, на GitHub.
» example code
» GitHub
Несколько скриншотов рабочей версии:
Автор: sarkis-tlt