简体   繁体   English

graphql-compose,嵌套字段的触发解析器

[英]graphql-compose, trigger resolver of a nested field

I'm beginner in GraphQL and use it with Node and graphql-compose to create schemas.我是 GraphQL 的初学者,并将其与 Node 和graphql-compose一起使用来创建模式。

I'm not sure if is the correct way to do that: AddressTC is reusable Type, when UserTC or another Type is created or updated, I want to trigger validation automatically of AddressTC .我不确定这样做是否正确: AddressTC是可重用类型,当创建或更新UserTC或其他类型时,我想自动触发AddressTC的验证。 If you know a better way to do that, I'll take it.如果你知道更好的方法,我会接受的。

// userType.js
// In this example we'll use UserTC but this can another type which also use AdressTC.

const UserTC = schemaComposer.createObjectTC({
    name: 'User',
    fields: {
        id: 'String',
        name: 'String',
        slug: 'String',
        actived: 'Boolean',
        registered: 'Boolean',
        address: AddressTC,
    }
});

const UserITC = UserTC.getInputTypeComposer()

UserTC.addResolver({
    kind: 'mutation',
    name: 'create',
    args: {
        data: UserITC
    },
    type: UserTC,
    resolve: async ({args: {data}, context}) => {
        // Need to trigger validation and geocode of AddressTC
        // do something...
        // save in database
    },
})

// addressType.js
// reusable Address Type

const AddressTC = schemaComposer.createObjectTC({
    name: 'Address',
    description: 'Type of address',
    fields: {
        street: 'String',
        number: 'String',
        postcode: 'String',
        city: 'String',
        comment: 'String',
        country: 'String',
        quality: QualityETC
    }
});

const AddressITC = AddressTC.getInputTypeComposer()

AddressTC.addResolver({
    kind: 'mutation',
    name: 'validation',
    args: {
        data: AddressITC
    },
    type: AddressTC,
    resolve: async ({args: {data}, context}) => {
        // When address is puted or updated :
        // Make validation
        // Geocode {Lat,Lng} with map provider 
        // Save in DB           
    },
})

As your question, You can use a validation library such as joi , and inside your resolver apply your validation schema.作为您的问题,您可以使用joi等验证库,并在解析器中应用您的验证模式。

import joi from 'joi'

const UserTC = schemaComposer.createObjectTC({
    name: 'User',
    fields: {
        id: 'String',
        name: 'String',
        slug: 'String',
        actived: 'Boolean',
        registered: 'Boolean',
        address: AddressTC,
    }
});

const UserITC = UserTC.getInputTypeComposer()

/* Create it here, or in the address file and import it here.
   Personally, I place the validation schemas in separate files
*/
const addressTCSchema = Joi.object().keys({
    street: Joi.string().required(),
    number: Joi.number().required(),
    city: Joi.string().required(),
    postcode: Joi.string().required(),
    comment: Joi.string().required(),
    country: Joi.string().required(),
})

const userTCSchema = Joi.object({
    id: Joi.number().integer().required(),
    name: Joi.string()
        .pattern(new RegExp('^[a-zA-Z]')).required(),
    slug: Joi.string()
        .pattern(new RegExp('^[a-zA-Z]')).required(),
    actived: Joi.boolean().required(),
    registered: Joi.boolean().required(),
    address: addressTCSchema
})

UserTC.addResolver({
    kind: 'mutation',
    name: 'create',
    args: {
        data: UserITC
    },
    type: UserTC,
    resolve: async ({args: {data}, context}) => {
        // Need to trigger validation and geocode of AddressTC
        const { error } = userTCSchema.validate(data);
        if (error) {
            // return or send 400 bad request
        }
        // do someting...
        // save in database
    },
})

I would suggest using a resolver wrapper.我建议使用解析器包装器。 These are used for things like checking authentication/permissions but would apply to some sort of generic type validation that you are looking for.这些用于检查身份验证/权限之类的事情,但适用于您正在寻找的某种通用类型验证。

I believe this piece of documentation will help you out for a high level understanding -我相信这篇文档将帮助您获得更高层次的理解-
https://graphql-compose.github.io/docs/basics/what-is-resolver.html#wrapping-resolver https://graphql-compose.github.io/docs/basics/what-is-resolver.html#wrapping-resolver

What you need to understand is how resolverParams work (rp).您需要了解的是 resolverParams 是如何工作的 (rp)。 You can get a lot of information about what is going on in a query and do a lot with wrappers by investigating the rps.您可以通过调查 rps 获得很多关于查询中发生的事情的信息,并使用包装器做很多事情。

This documentation is specific for a MongoDB implementation but the code can be altered to fit any DB.本文档特定于 MongoDB 实现,但可以更改代码以适应任何 DB。 https://graphql-compose.github.io/docs/plugins/plugin-mongoose.html#access-and-modify-mongoose-doc-before-save https://graphql-compose.github.io/docs/plugins/plugin-mongoose.html#access-and-modify-mongoose-doc-before-save

This would be the general layout of the wrapper function I mentioned.这将是我提到的包装器 function 的一般布局。 The code is abstracted from the MongoDB implementation mentioned above.该代码是从上面提到的 MongoDB 实现中抽象出来的。

The function might look something like this: function 可能看起来像这样:

function addressValidationWrapper(resolvers){
  Object.keys(resolvers).forEach((k) => {
    resolvers[k] = resolvers[k].wrapResolve(next => async rp => {
      // check if has address field/type
         // validate address
            // if address valid - resolve
            // else throw error
      return next(rp)
    })
  })
 return resolvers
}

The best way to implement this will be based on your application structure and how you are composing the global schema.实现这一点的最佳方法将基于您的应用程序结构以及您如何组成全局模式。 I recommend reading through the resolver docs entirely to figure out what makes sense for you.我建议通读解析器文档以找出对您有意义的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM