graphql,当有"add"和"update"突变时如何设计输入类型?
graphql, how to design input type when there are "add" and "update" mutation?
这是我的要求:
"add" 突变,BookInput
输入类型的每个字段(或称为标量)都应该有额外的类型修饰符“!”验证非空值。这意味着当我添加一本书时,参数必须有 title
和 author
字段,例如 {title: "angular", author: "novaline"}
"update"突变,我想更新书的一部分字段,不想更新整本书(MongoDB文档,而且,我不不希望前端向 graphql 服务器传递一整本大书变异参数以节省带宽)。这意味着 book 参数可以是 {title: "angular"}
或 {title: "angular", author: "novaline"}
.
这是我的类型定义:
const typeDefs = `
input BookInput {
title: String!
author: String!
}
type Book {
id: ID!
title: String!
author: String!
}
type Query {
books: [Book!]!
}
type Mutation{
add(book: BookInput!): Book
update(id: String!, book: BookInput!): Book
}
`;
目前,"add" 突变工作正常。但是如果我传递 {title: "angular"}
参数
,"update" 突变无法通过非空检查
这是一个未通过非空检查的突变,BookInput
输入类型缺少 "author" 字段。
mutation {
update(id: "1", book: {title: "angular"}) {
id
title
author
}
}
所以,graphql 会给我一个错误:
{
"errors": [
{
"message": "Field BookInput.author of required type String! was not provided.",
"locations": [
{
"line": 2,
"column": 24
}
]
}
]
}
如何设计BookInput
输入类型?不想定义 addBookInput
和 updateBookInput
。重复了。
一个非常常见的模式是为每个突变使用单独的输入类型。您可能还想为每个操作创建一个突变查询。也许是这样的:
const typeDefs = `
input AddBookInput {
title: String!
author: String!
}
input UpdateBookInput {
# NOTE: all fields are optional for the update input
title: String
author: String
}
type Book {
id: ID!
title: String!
author: String!
}
type Query {
books: [Book!]!
}
type Mutation{
addBook(input: AddBookInput!): Book
updateBook(id: String!, input: UpdateBookInput!): Book
}
`;
有些人还喜欢将更新 ID 作为更新输入的一部分:
const typeDefs = `
input AddBookInput {
title: String!
author: String!
}
input UpdateBookInput {
# NOTE: all fields, except the 'id' (the selector), are optional for the update input
id: String!
title: String
author: String
}
type Book {
id: ID!
title: String!
author: String!
}
type Query {
books: [Book!]!
}
type Mutation{
addBook(input: AddBookInput!): Book
updateBook(input: UpdateBookInput!): Book
}
`;
最后,您可能希望对 return 类型使用 'payload' 类型 - 以增加灵活性(为您提供更多回旋余地以在以后更改 return 类型而不会破坏您的API):
const typeDefs = `
input AddBookInput {
title: String!
author: String!
}
input UpdateBookInput {
# NOTE: all fields, except the 'id' (the selector), are optional for the update input
id: String!
title: String
author: String
}
type Book {
id: ID!
title: String!
author: String!
}
type AddBookPayload {
book: Book!
}
type UpdateBookPayload {
book: Book!
}
type Query {
books: [Book!]!
}
type Mutation{
addBook(input: AddBookInput!): AddBookPayload!
updateBook(input: UpdateBookInput!): UpdateBookPayload!
}
`;
希望对您有所帮助!
这是我的解决方案,我写了一个辅助函数来生成 "create" input
类型和 "update" input
类型。
const { parse } = require('graphql');
/**
* schema definition helper function - dynamic generate graphql input type
*
* @author https://github.com/mrdulin
* @param {string} baseSchema
* @param {object} options
* @returns {string}
*/
function generateInputType(baseSchema, options) {
const inputTypeNames = Object.keys(options);
const schema = inputTypeNames
.map(inputTypeName => {
const { validator } = options[inputTypeName];
const validatorSchema = Object.keys(validator)
.map(field => `${field}: ${validator[field]}\n`)
.join(' ');
return `
input ${inputTypeName} {
${baseSchema}
${validatorSchema}
}
`;
})
.join(' ')
.replace(/^\s*$(?:\r\n?|\n)/gm, '');
parse(schema);
return schema;
}
schema.js
:
${generateInputType(
`
campaignTemplateNme: String
`,
{
CreateCampaignTemplateInput: {
validator: {
channel: 'ChannelUnionInput!',
campaignTemplateSharedLocationIds: '[ID]!',
campaignTemplateEditableFields: '[String]!',
organizationId: 'ID!',
},
},
UpdateCampaignTemplateInput: {
validator: {
channel: 'ChannelUnionInput',
campaignTemplateSharedLocationIds: '[ID]',
campaignTemplateEditableFields: '[String]',
organizationId: 'ID',
},
},
},
)}
这是我的要求:
"add" 突变,
BookInput
输入类型的每个字段(或称为标量)都应该有额外的类型修饰符“!”验证非空值。这意味着当我添加一本书时,参数必须有title
和author
字段,例如{title: "angular", author: "novaline"}
"update"突变,我想更新书的一部分字段,不想更新整本书(MongoDB文档,而且,我不不希望前端向 graphql 服务器传递一整本大书变异参数以节省带宽)。这意味着 book 参数可以是
{title: "angular"}
或{title: "angular", author: "novaline"}
.
这是我的类型定义:
const typeDefs = `
input BookInput {
title: String!
author: String!
}
type Book {
id: ID!
title: String!
author: String!
}
type Query {
books: [Book!]!
}
type Mutation{
add(book: BookInput!): Book
update(id: String!, book: BookInput!): Book
}
`;
目前,"add" 突变工作正常。但是如果我传递 {title: "angular"}
参数
这是一个未通过非空检查的突变,BookInput
输入类型缺少 "author" 字段。
mutation {
update(id: "1", book: {title: "angular"}) {
id
title
author
}
}
所以,graphql 会给我一个错误:
{
"errors": [
{
"message": "Field BookInput.author of required type String! was not provided.",
"locations": [
{
"line": 2,
"column": 24
}
]
}
]
}
如何设计BookInput
输入类型?不想定义 addBookInput
和 updateBookInput
。重复了。
一个非常常见的模式是为每个突变使用单独的输入类型。您可能还想为每个操作创建一个突变查询。也许是这样的:
const typeDefs = `
input AddBookInput {
title: String!
author: String!
}
input UpdateBookInput {
# NOTE: all fields are optional for the update input
title: String
author: String
}
type Book {
id: ID!
title: String!
author: String!
}
type Query {
books: [Book!]!
}
type Mutation{
addBook(input: AddBookInput!): Book
updateBook(id: String!, input: UpdateBookInput!): Book
}
`;
有些人还喜欢将更新 ID 作为更新输入的一部分:
const typeDefs = `
input AddBookInput {
title: String!
author: String!
}
input UpdateBookInput {
# NOTE: all fields, except the 'id' (the selector), are optional for the update input
id: String!
title: String
author: String
}
type Book {
id: ID!
title: String!
author: String!
}
type Query {
books: [Book!]!
}
type Mutation{
addBook(input: AddBookInput!): Book
updateBook(input: UpdateBookInput!): Book
}
`;
最后,您可能希望对 return 类型使用 'payload' 类型 - 以增加灵活性(为您提供更多回旋余地以在以后更改 return 类型而不会破坏您的API):
const typeDefs = `
input AddBookInput {
title: String!
author: String!
}
input UpdateBookInput {
# NOTE: all fields, except the 'id' (the selector), are optional for the update input
id: String!
title: String
author: String
}
type Book {
id: ID!
title: String!
author: String!
}
type AddBookPayload {
book: Book!
}
type UpdateBookPayload {
book: Book!
}
type Query {
books: [Book!]!
}
type Mutation{
addBook(input: AddBookInput!): AddBookPayload!
updateBook(input: UpdateBookInput!): UpdateBookPayload!
}
`;
希望对您有所帮助!
这是我的解决方案,我写了一个辅助函数来生成 "create" input
类型和 "update" input
类型。
const { parse } = require('graphql');
/**
* schema definition helper function - dynamic generate graphql input type
*
* @author https://github.com/mrdulin
* @param {string} baseSchema
* @param {object} options
* @returns {string}
*/
function generateInputType(baseSchema, options) {
const inputTypeNames = Object.keys(options);
const schema = inputTypeNames
.map(inputTypeName => {
const { validator } = options[inputTypeName];
const validatorSchema = Object.keys(validator)
.map(field => `${field}: ${validator[field]}\n`)
.join(' ');
return `
input ${inputTypeName} {
${baseSchema}
${validatorSchema}
}
`;
})
.join(' ')
.replace(/^\s*$(?:\r\n?|\n)/gm, '');
parse(schema);
return schema;
}
schema.js
:
${generateInputType(
`
campaignTemplateNme: String
`,
{
CreateCampaignTemplateInput: {
validator: {
channel: 'ChannelUnionInput!',
campaignTemplateSharedLocationIds: '[ID]!',
campaignTemplateEditableFields: '[String]!',
organizationId: 'ID!',
},
},
UpdateCampaignTemplateInput: {
validator: {
channel: 'ChannelUnionInput',
campaignTemplateSharedLocationIds: '[ID]',
campaignTemplateEditableFields: '[String]',
organizationId: 'ID',
},
},
},
)}