mirror of
https://github.com/wassname/talk.git
synced 2026-07-09 06:24:18 +08:00
Merge pull request #604 from coralproject/graphql-errors-handling
Support response errors in the graphql framework
This commit is contained in:
@@ -124,36 +124,28 @@ const extension = {
|
||||
mutations: {
|
||||
IgnoreUser: ({variables}) => ({
|
||||
updateQueries: {
|
||||
EmbedQuery: (previousData, {mutationResult}) => {
|
||||
EmbedQuery: (previousData) => {
|
||||
const ignoredUserId = variables.id;
|
||||
const response = mutationResult.data.ignoreUser;
|
||||
if (ignoredUserId && !response.errors) {
|
||||
const updated = update(previousData, {me: {ignoredUsers: {$push: [{
|
||||
id: ignoredUserId,
|
||||
__typename: 'User',
|
||||
}]}}});
|
||||
return updated;
|
||||
}
|
||||
return previousData;
|
||||
const updated = update(previousData, {me: {ignoredUsers: {$push: [{
|
||||
id: ignoredUserId,
|
||||
__typename: 'User',
|
||||
}]}}});
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
}),
|
||||
StopIgnoringUser: ({variables}) => ({
|
||||
updateQueries: {
|
||||
EmbedStreamProfileQuery: (previousData, {mutationResult}) => {
|
||||
EmbedStreamProfileQuery: (previousData) => {
|
||||
const noLongerIgnoredUserId = variables.id;
|
||||
const response = mutationResult.data.stopIgnoringUser;
|
||||
if (noLongerIgnoredUserId && !response.errors) {
|
||||
|
||||
// remove noLongerIgnoredUserId from ignoredUsers
|
||||
const updated = update(previousData, {me: {ignoredUsers: {
|
||||
$apply: (ignoredUsers) => {
|
||||
return ignoredUsers.filter((u) => u.id !== noLongerIgnoredUserId);
|
||||
}
|
||||
}}});
|
||||
return updated;
|
||||
}
|
||||
return previousData;
|
||||
// remove noLongerIgnoredUserId from ignoredUsers
|
||||
const updated = update(previousData, {me: {ignoredUsers: {
|
||||
$apply: (ignoredUsers) => {
|
||||
return ignoredUsers.filter((u) => u.id !== noLongerIgnoredUserId);
|
||||
}
|
||||
}}});
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
}),
|
||||
@@ -221,12 +213,7 @@ const extension = {
|
||||
variables: {id, edit},
|
||||
}) => ({
|
||||
updateQueries: {
|
||||
EmbedQuery: (previousData, {mutationResult: {data: {editComment: {comment, errors}}}}) => {
|
||||
|
||||
// @TODO (kiwi) revisit after streamlining error handling
|
||||
if (errors && errors.length) {
|
||||
return previousData;
|
||||
}
|
||||
EmbedQuery: (previousData, {mutationResult: {data: {editComment: {comment}}}}) => {
|
||||
const {status} = comment;
|
||||
const updateCommentWithEdit = (comment, edit) => {
|
||||
const {body} = edit;
|
||||
|
||||
@@ -6,7 +6,25 @@ import flatten from 'lodash/flatten';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import {getMutationOptions, resolveFragments} from 'coral-framework/services/graphqlRegistry';
|
||||
import {store} from 'coral-framework/services/store';
|
||||
import {getDefinitionName} from '../utils';
|
||||
import {getDefinitionName, getResponseErrors} from '../utils';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
|
||||
class ResponseErrors extends Error {
|
||||
constructor(errors) {
|
||||
super(`Response Errors ${JSON.stringify(errors)}`);
|
||||
this.errors = errors.map((e) => new ResponseError(e));
|
||||
}
|
||||
}
|
||||
|
||||
class ResponseError {
|
||||
constructor(error) {
|
||||
Object.assign(this, error);
|
||||
}
|
||||
|
||||
translate(...args) {
|
||||
return t(`error.${this.translation_key}`, ...args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports a HOC with the same signature as `graphql`, that will
|
||||
@@ -41,6 +59,11 @@ export default (document, config) => (WrappedComponent) => {
|
||||
.filter((i) => i);
|
||||
|
||||
const update = (proxy, result) => {
|
||||
if (getResponseErrors(result)) {
|
||||
|
||||
// Do not run updates when we have mutation errors.
|
||||
return;
|
||||
}
|
||||
updateCallbacks.forEach((cb) => cb(proxy, result));
|
||||
};
|
||||
|
||||
@@ -53,7 +76,14 @@ export default (document, config) => (WrappedComponent) => {
|
||||
.reduce((res, map) => {
|
||||
Object.keys(map).forEach((key) => {
|
||||
if (!(key in res)) {
|
||||
res[key] = map[key];
|
||||
res[key] = (prev, result) => {
|
||||
if (getResponseErrors(result.mutationResult)) {
|
||||
|
||||
// Do not run updates when we have mutation errors.
|
||||
return prev;
|
||||
}
|
||||
return map[key](prev, result);
|
||||
};
|
||||
} else {
|
||||
const existing = res[key];
|
||||
res[key] = (prev, result) => {
|
||||
@@ -75,7 +105,14 @@ export default (document, config) => (WrappedComponent) => {
|
||||
if (isEmpty(wrappedConfig.optimisticResponse)) {
|
||||
delete wrappedConfig.optimisticResponse;
|
||||
}
|
||||
return data.mutate(wrappedConfig);
|
||||
return data.mutate(wrappedConfig)
|
||||
.then((res) => {
|
||||
const errors = getResponseErrors(res);
|
||||
if (errors) {
|
||||
throw new ResponseErrors(errors);
|
||||
}
|
||||
return Promise.resolve(res);
|
||||
});
|
||||
};
|
||||
return config.props({...data, mutate});
|
||||
};
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import * as React from 'react';
|
||||
import {graphql} from 'react-apollo';
|
||||
import {getQueryOptions, resolveFragments} from 'coral-framework/services/graphqlRegistry';
|
||||
import {getDefinitionName, separateDataAndRoot} from '../utils';
|
||||
import {getDefinitionName, separateDataAndRoot, getResponseErrors} from '../utils';
|
||||
|
||||
const withSkipOnErrors = (reducer) => (prev, action, ...rest) => {
|
||||
if (action.type === 'APOLLO_MUTATION_RESULT' && getResponseErrors(action.result)) {
|
||||
return prev;
|
||||
}
|
||||
return reducer(prev, action, ...rest);
|
||||
};
|
||||
|
||||
/**
|
||||
* Exports a HOC with the same signature as `graphql`, that will
|
||||
@@ -23,10 +30,11 @@ export default (document, config) => (WrappedComponent) => {
|
||||
.concat(...configs.map((cfg) => cfg.reducer))
|
||||
.filter((i) => i);
|
||||
|
||||
const reducer = reducerCallbacks.reduce(
|
||||
(a, b) => (prev, ...rest) =>
|
||||
b(a(prev, ...rest), ...rest),
|
||||
);
|
||||
const reducer = withSkipOnErrors(
|
||||
reducerCallbacks.reduce(
|
||||
(a, b) => (prev, ...rest) =>
|
||||
b(a(prev, ...rest), ...rest),
|
||||
));
|
||||
|
||||
return {
|
||||
...base,
|
||||
|
||||
@@ -100,3 +100,14 @@ export function mergeDocuments(documents) {
|
||||
const literals = [main, ...substitutions.map(() => '\n')];
|
||||
return gql.apply(null, [literals, ...substitutions]);
|
||||
}
|
||||
|
||||
export function getResponseErrors(mutationResult) {
|
||||
const result = [];
|
||||
Object.keys(mutationResult.data).forEach((response) => {
|
||||
const errors = mutationResult.data[response].errors;
|
||||
if (errors && errors.length) {
|
||||
result.push(...errors);
|
||||
}
|
||||
});
|
||||
return result.length ? result : false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user