- PVSM.RU - https://www.pvsm.ru -
В данной статье я расскажу вам как исходя из своего опыта я написал небольшой npm-модуль, который помог мне и, думаю, может помочь вам сэкономить приличное количество времени и сократить код практически в два раза.
Все начал с того что я решил написать изоморфный CMS для одного из моих проектов с использованием следующих технологий:
Упрощенная архитектура выглядит следующим образом:
__root
1 |__client
2 |__public
3 |__middleware
4 |__server
Соответственно, для каждой сущности в базе данных мы должны создать Mongoose-схему, чтобы иметь возможность манипулировать данными. Выглядит это примерно следующим образом:
let couponSchema = mongoose.Schema({
couponCode: Array,
description: String,
discountAmount: String,
minimumAmount: String,
singleUseOnly: Boolean,
createdAt: mongoose.Schema.Types.Date,
updatedAt: mongoose.Schema.Types.Date,
expirationDate: mongoose.Schema.Types.Date
});
Теперь если мы используем graphQL мы должны создать тип для каждой сущности в базе данных, причем тип каждого свойства должен быть идентичен тому же, что и в Mongoose схеме. Без graphQL-типов мы просто не сможем сгенерировать graphQL-схему. Тип выглядит следующим образом:
let couponType = new GraphQLObjectType({
name: 'couponType',
description: 'single use coupon',
fields: {
_id: {type: GraphQLString},
couponCode: {type: new GraphQLList(GraphQLString)},
description: {type: GraphQLString},
discountAmount: {type: GraphQLString},
minimumAmount: {type: GraphQLString},
singleUseOnly: {type: GraphQLBoolean},
createdAt: {type: GraphQLString},
updatedAt: {type: GraphQLString},
expirationDate: {type: GraphQLString}
}
});
Думаю, схожесть очевидна? А теперь представьте, что вы имеете несколько десятков сущностей и для каждой из них вам нужно практически дублировать одну и ту же логику. А ведь типы могут содержать массивы других типов и множество других вложенных элементов.
Собственно, для разрешения этой проблемы я написал небольшой модуль (всего 3kb), который поможет избежать дублирования логически идентичного кода и практически сократит вдвое ваш код, в моем случае я сократил код более чем на 2000 строк.
Для начала установим модуль:
npm i mongoose-schema-to-graphql --save
Модуль содержит одну единственную функцию “MTGQL”, которая принимает один объект с конфигурациями в качестве аргумента. Объект имеет следующую структуру:
let configs = {
name: 'couponType',
// название graphQL типа
description: 'Coupon base schema',
// описание graphQL типа
class: 'GraphQLObjectType',
// graphQL класс который будет использован для сборки
schema: couponSchema,
// Mongoose схема
exclude: ['_id'],
// свойства которые нужно исключить
props: {
price: {type: GraphQLFloat}
}
// дополнительные свойства которые нужно добавить или переписать
}
Пару примеров использования модуля ниже:
dbSchema.js
import mongoose from 'mongoose';
let selectObj = {
value: String,
label: String
};
let answerSchema = mongoose.Schema({
createdAt: mongoose.Schema.Types.Date,
updatedAt: mongoose.Schema.Types.Date,
title: String,
answersImage: String,
recommended: [selectObj],
isPublished: Boolean
});
export let questionSchema = mongoose.Schema({
question: String,
defRecommended: [selectObj],
createdAt: mongoose.Schema.Types.Date,
updatedAt: mongoose.Schema.Types.Date,
isPublished: Boolean,
multipleChoice: Boolean,
answers: [answerSchema]
});
В файле с вашими graphQL типами:
type.js
import MTGQL from 'mongoose-schema-to-graphql';
import {questionSchema} from './dbSchemas';
let config = {
name: 'questionType',
description: 'Question collection's type',
class: 'GraphQLObjectType',
schema: questionSchema,
exclude: ['_id']
};
export let questionType = MTGQL(config);
Собственно всего 10 строк кода, которые равносильны следующему:
import {
GraphQLObjectType,
GraphQLString,
GraphQLBoolean,
GraphQLList,
GraphQLInt
} from 'graphql';
let selectType = new GraphQLObjectType({
name: 'selectType',
fields: {
value: {type: GraphQLString},
label: {type: GraphQLString}
}
});
let answerType = new GraphQLObjectType({
name: 'answerType',
description: 'answer type for question',
fields: {
title: {type: GraphQLString},
answersImage: {type: GraphQLString},
recommended: {type: new GraphQLList(selectType)},
createdAt: {type: GraphQLString},
updatedAt: {type: GraphQLString},
isPublished: {type: GraphQLBoolean}
}
});
export let questionType = new GraphQLObjectType({
name: 'questionType',
description: 'Question collection's type',
fields: {
_id: {type: GraphQLString},
question: {type: GraphQLString},
defRecommended: {type: new GraphQLList(selectType)},
createdAt: {type: GraphQLString},
updatedAt: {type: GraphQLString},
isPublished: {type: GraphQLBoolean},
multipleChoice: {type: GraphQLBoolean},
answers: {type: new GraphQLList(answerType)}
}
});
Думаю, разница очевидна. Модуль не поддерживает напрямую “GraphQLFloat”, потому что в Mongoose схеме вы можете задать только тип «Number», который эквивалентен целому числу. Но эту проблему можно легко решить, передав нужное свойство через конфигурационный объект.
Более подробно о том, как работает модуль, вы можете посмотреть на GitHub [1].
Надеюсь, статья была вам полезна, если у вас есть какие-то предложения по улучшению, пишите, обязательно учту. Спасибо за внимание.
Оригинал статьи находится на medium.com [2].
Автор: sarkis-tlt
Источник [3]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/191398
Ссылки в тексте:
[1] GitHub: https://github.com/sarkistlt/mongoose-schema-to-graphql
[2] medium.com: https://medium.com/@sarkis.tlt/how-to-use-mongoose-schema-to-generate-graphql-type-ada63a89915#.90mrkwcgw
[3] Источник: https://habrahabr.ru/post/310820/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox
Нажмите здесь для печати.