Relay flavoured graphql mutation validation errors

310 views Asked by At

I've greated a simple relay flavoured mutation that works just fine. I've got a simple client side component that commits the mutation with the required data.

My question is how do I send back multiple errors to the client? Currently I can simply throw an error (or reject a promise) in mutateAndGetPayload and I will receive an error on the client side, but this currently only works with a string message. Should I simply reject the promise with a JSON string of an errors array? Or is there a better way?

const createCashAccountMutation = mutationWithClientMutationId({
    name: 'CreateCashAccount',
    inputFields: {
        name: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'Cash account name'
        },
        code: {
            type: GraphQLString,
            description: 'Optional code'
        },
        businessId: {
            type: new GraphQLNonNull(GraphQLString),
                description: 'Business ID'
        },
        currencyId: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'Currency ID'
        },
        isActive: {
            type: new GraphQLNonNull(GraphQLInt)
        }
    },
    outputFields: {
        name: {
            type: GraphQLString,
            resolve: (payload) => payload.name
        },
        code: {
            type: GraphQLString,
            resolve: (payload) => payload.code
        },
        businessId: {
            type: GraphQLString,
            resolve: (payload) => payload.businessId
        },
        currencyId: {
            type: GraphQLString,
            resolve: (payload) => payload.currencyId
        },
        isActive: {
            type: GraphQLString,
            resolve: (payload) => payload.isActive
        }
    },
    mutateAndGetPayload: async (options) => {
        throw 'wtf';
        return options;
    }
});

Update 1.

I've come up with the following example:

const graphQLCashAccount = new GraphQLObjectType({
    name: 'cashAccount',
    fields: {
        name: {
            type: GraphQLString,
            resolve: (payload) => payload.name
        },
        code: {
            type: GraphQLString,
            resolve: (payload) => payload.code
        },
        businessId: {
            type: GraphQLString,
            resolve: (payload) => payload.businessId
        },
        currencyId: {
            type: GraphQLString,
            resolve: (payload) => payload.currencyId
        },
        isActive: {
            type: GraphQLString,
            resolve: (payload) => payload.isActive
        }
    }
});

const graphQLErrors = new GraphQLList(new GraphQLObjectType({
    name: 'errors',
    fields: {
        key: {
            type: GraphQLString,
            resolve: (payload) => payload.key
        },
        message: {
            type: GraphQLString,
            resolve: (payload) => payload.message
        }
    }
}));

const graphQlInput = new GraphQLInputObjectType({
    name: 'data',
    fields: {
        name: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'Cash account name'
        },
        code: {
            type: GraphQLString,
            description: 'Optional code'
        },
        businessId: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'Business ID'
        },
        currencyId: {
            type: new GraphQLNonNull(GraphQLString),
            description: 'Currency ID'
        },
        isActive: {
            type: new GraphQLNonNull(GraphQLInt)
        }
    }
});

const createCashAccountMutation = mutationWithClientMutationId({
    name: 'CreateCashAccount',
    inputFields: {
        data: {
            type: graphQlInput
        }
    },
    outputFields: {
        data: {
            type: graphQLCashAccount,
            resolve: (payload) => payload.data
        },
        errors: {
            type: graphQLErrors,
            resolve: (payload) => payload.errors
        }
    },
    mutateAndGetPayload: async (options) => {
        const payload = {
            errors: [{ key: 'asd', message: 'asd failed' }],
            data: options
        };
        return payload;
    }
});

This will actually resolve the transaction and simply return 2 fields, a data field and an errors field. One of them will be populated.

Is this a better approach? I'm stumped on how I should apply the update in Relays fatquery though.

Update 2.

Relay Mutation client side example.

export class NewCashAccountMutation extends Relay.Mutation {

    getMutation () {
        return Relay.QL`mutation { 
            createCashAccount
        }`;
    }

    getVariables() {
        return { data: this.props.cashAccount };
    }

    getFatQuery() {
        return Relay.QL`
            fragment on CreateCashAccountPayload {
                data, errors
            }
        `;
    }
    getConfigs() {
        return [{
            type: 'FIELDS_CHANGE',
            fieldIDs: {
                data: this.props.cashAccount.id,
            },
        }];
    }
}
0

There are 0 answers