graphql,当存在“时如何设计输入类型”;加上「;及;更新;突变

graphql,当存在“时如何设计输入类型”;加上「;及;更新;突变,graphql,graphql-js,apollo-server,Graphql,Graphql Js,Apollo Server,以下是我的要求: “添加”变异,每个BookInput输入类型的字段(或称为标量)都应该有额外的类型修饰符“!”来验证非空值。这意味着当我添加一本书时,参数必须有title和author字段,比如{title:“angular”,author:“novaline”} “更新”变异,我想更新这本书的一部分字段,不想更新整本书(MongoDB文档,我不想前端通过graphql服务器传递整本书的变异参数来节省带宽)。这意味着book参数可以是{title:“angular”}或{title:“angu

以下是我的要求:

  • “添加”变异,每个
    BookInput
    输入类型的字段(或称为标量)都应该有额外的类型修饰符“!”来验证非空值。这意味着当我添加一本书时,参数必须有
    title
    author
    字段,比如
    {title:“angular”,author:“novaline”}

  • “更新”变异,我想更新这本书的一部分字段,不想更新整本书(MongoDB文档,我不想前端通过graphql服务器传递整本书的变异参数来节省带宽)。这意味着book参数可以是
    {title:“angular”}
    {title:“angular”,author:“novaline”}

  • 以下是我的类型定义:

    const typeDefs=`
    输入书输入{
    标题:字符串!
    作者:字符串!
    }
    打字簿{
    id:id!
    标题:字符串!
    作者:字符串!
    }
    类型查询{
    书:[书!
    }
    类型突变{
    添加(书本:书本输入!):书本
    更新(id:String!,book:BookInput!):book
    }
    `;
    
    目前,“添加”突变效果良好。但是如果我通过
    {title:“angular”}
    参数,则“update”变异无法通过非空检查

    这是一个未通过非空检查的变异,缺少
    BookInput
    input类型的“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
      }
    `;
    
    最后,您可能希望使用“有效负载”类型作为返回类型,以增加灵活性(为您以后在不破坏API的情况下更改返回类型提供更多回旋空间):


    希望这有帮助

    这是我的解决方案,我编写了一个助手函数来生成“创建”
    input
    type和“更新”
    input
    type

    const{parse}=require('graphql');
    /**
    *架构定义辅助函数-动态生成graphql输入类型
    *
    *@作者https://github.com/mrdulin
    *@param{string}baseSchema
    *@param{object}选项
    *@返回{string}
    */
    函数generateInputType(baseSchema,选项){
    const inputTypeNames=Object.keys(选项);
    const schema=inputTypeNames
    .map(inputTypeName=>{
    const{validator}=options[inputTypeName];
    const validatorSchema=Object.keys(验证器)
    .map(字段=>`${field}:${validator[field]}\n`)
    .加入(“”);
    返回`
    输入${inputTypeName}{
    ${baseSchema}
    ${validatorSchema}
    }
    `;
    })
    .加入(“”)
    。替换(/^\s*$(?:\r\n?|\n)/gm“”);
    解析(模式);
    返回模式;
    }
    
    schema.js

    ${generateInputType(
    `
    活动模板名称:字符串
    `,
    {
    CreateActiveTemplateInput:{
    验证器:{
    频道:“ChannelUnionInput!”,
    活动模板SharedLocationId:“[ID]!”,
    活动模板可编辑字段:“[String]!”,
    organizationId:'ID!',
    },
    },
    UpdateCampaignTemplateInput:{
    验证器:{
    频道:“ChannelUnionInput”,
    活动模板SharedLocationId:“[ID]”,
    活动模板可编辑字段:“[String]”,
    organizationId:'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 AddBookPayload {
        book: Book!
      }
    
      type UpdateBookPayload {
        book: Book!
      }
    
      type Query {
        books: [Book!]!
      }
    
      type Mutation{
        addBook(input: AddBookInput!): AddBookPayload!
        updateBook(input: UpdateBookInput!): UpdateBookPayload!
      }
    `;