I am trying to do customize messaging with GraphQLError.
There are few use cases that I want to handle with GraphQL Error:
when username and password did not match, I want to return customize the message that username and password did not match.
When the user entered an invalid email, I want to return customize the message that entered email is not valid.
And few other use cases.
I created a ValidateError.js File to use GraphQLError handling function:
const { GraphQLError } = require('graphql');
module.exports = class ValidationError extends GraphQLError {
constructor(errors) {
super('The request is invalid');
var err = errors.reduce((result, error) => {
if (Object.prototype.hasOwnProperty.call(result, error.key)) {
result[error.key].push(error.message);
} else {
result[error.key] = [error.message];
}
return result;
}, {});
}
}
Here is the code of my application index file app.js:
app.use('/graphql', graphqlExpress(req => ({
schema,
context: {
user: req.user
},
formatError(err) {
return {
message: err.message,
code: err.originalError && err.originalError.code,
locations: err.locations,
path: err.path
};
}
})));
My question is how can I use this function for grabbing graphQLError
formatError
Thanks in advance.
"apollo-server-express": "^1.3.5"
"graphql": "^0.13.2"
Just throw your error in resolver, formatError function will catch each error thrown in resolver.
Here is my work:
appError.js
class AppError extends Error {
constructor(opts) {
super(opts.msg);
this.code = opts.code;
}
}
exports.AppError = AppError;
throw an custom error in resolver:
throw new AppError({ msg: 'authorization failed', code: 1001 });
catch this error in formatError:
formatError: error => {
const { code, message } = error.originalError;
return { code, message };
},
Other sample:
throw your error in resolver:
const resolvers = {
Query: {
books: () => {
throw new GraphQLError('something bad happened');
}
}
};
catch error in formatError:
graphqlExpress(req => {
return {
schema,
formatError: err => {
console.log('format error');
return err;
}
};
})
Here is the output:
format error
GraphQLError: something bad happened
at books (/Users/ldu020/workspace/apollo-server-express-starter/src/graphql-error/index.js:23:13)
at /Users/ldu020/workspace/apollo-server-express-starter/node_modules/graphql-tools/dist/schemaGenerator.js:518:26
at resolveFieldValueOrError (/Users/ldu020/workspace/apollo-server-express-starter/node_modules/graphql/execution/execute.js:531:18)
at resolveField (/Users/ldu020/workspace/apollo-server-express-starter/node_modules/graphql/execution/execute.js:495:16)
at /Users/ldu020/workspace/apollo-server-express-starter/node_modules/graphql/execution/execute.js:364:18
at Array.reduce (<anonymous>)
at executeFields (/Users/ldu020/workspace/apollo-server-express-starter/node_modules/graphql/execution/execute.js:361:42)
at executeOperation (/Users/ldu020/workspace/apollo-server-express-starter/node_modules/graphql/execution/execute.js:289:122)
at executeImpl (/Users/ldu020/workspace/apollo-server-express-starter/node_modules/graphql/execution/execute.js:154:14)
at Object.execute (/Users/ldu020/workspace/apollo-server-express-starter/node_modules/graphql/execution/execute.js:131:229)
Inside of GraphQLError you should have access to GraphQLErrorExtensions which should allow you to append your custom messages when throwing errors.
This answer was written with knowledge of apollo server throwing custom errors through this extensions option. This may be achievable but more complex. I suggest checking out apollo server error: https://github.com/apollographql/apollo-server/blob/main/packages/apollo-server-errors/src/index.ts
It looks like what you can do is just pass any additional information through the extensions, but you will only be able to set it inside the constructor: new GraphQLError('your error message', null, null, null, null, null, {"message1": [ "custom message1" ], "message2": [ "customer message1", "custom message2" ]})
Related
I am getting an error when I request. Оn the backend side there is a check that the name length is at least 3 characters. The response from the server is correct. but when I try to display an error, the message comes out saying that the answer was not found.
async saveBoard(id, index) {
await this.API.put("/boards/" + id, {
name: this.boards[index].name,
})
.then((response) => {
alert(response.data.message);
this.boards[index].etitable = !this.boards[index].etitable;
})
.catch((error) => {
console.log(error);
});
},
when I try to output error.response.date to the console, I get an error that response is not defined.
How can I solve this problem, why does axios not see the response from the server and the error code?
Error code must be in your catch You can't reach error message in then.
You are probably see error in your console right now
return response;
},
error => {
if (error.response.status == 401 || error.response.status == 419) {
const token = localStorage.getItem('token');
if (token) {
localStorage.removeItem('token');
}
const user = localStorage.getItem('user');
if (user) {
localStorage.removeItem('user');
}
router.push('/login');
} else {
if (error.response.status == 403) {
router.push('/');
}
}
return Promise.reject(error);
});```
I added a return to the interceptors function. Problem solved thanks for your help.
I have aproblem when test Apollo.When I try query with apollo and graphql, i want response return error and partical data, so I set property errorPolicy:'all'. But its not work. I don't no why? Help please!
Here my code:
query { animal {
name
age }, school {
name
numberfd } } `
const { loading,data,error} = useQuery(GET_DASHBOARD_DATA, {
errorPolicy:'all',
onCompleted: (res) => {console.log("complete",res)},
onError : (res,data) => {console.log("ERRRR",res,data)},
})
and i want to receive:
{
error:[...], data:[animal:[...]] }
but its only response error.Here is Apollo's doc: https://www.apollographql.com/docs/react/data/error-handling/
onError type is onError?: (error: ApolloError) => void;. You don't have data inside onError callback.
After useQuery you can add:
console.log('data', data)
console.log('error', error)
I faced the same issue with errorPolicy: 'all', I only received the partial result inside onCompleted callback of useQuery, but no errors.
I created an ErrorLink like this:
private createErrorLink = () => {
return new ApolloLink((operation, forward) => {
return forward(operation).map((response) => {
// filter out errors you don't want to display
const errors = filterSomeErrors(response.errors);
if (errors && response?.data) {
response.data.errors = errors;
}
return response;
});
});
};
Now inside my onCompleted callback I get my data as well as errors. You will have to tweak your types a bit, because seems there is no errors field on response.data by default.
Mind that if you use onError from Apollo and return something from the link, it will retry your request containing errors!
I am using Vue.js with Vue-Apollo and trying to fetch shared member list using query. I am using the graphQL service in backend.
I am using apollo 'error' function to handle GraphQL error. When the request is made with invalid input, I can see the errors in the network tab, I can see the JSON for the custom errors messages. But I can't console the errors in 'error' function.
Here is the apollo query that is used to fetch shared member list -
apollo: {
sharedMembers: {
query: gql`
query item($uuid: ID) {
item(uuid: $uuid) {
...itemTemplate
members {
...member
permission
}
}
}
${ITEM_TEMPLATE}
${MEMBER}
`,
variables() {
return {
uuid: this.$route.params.uuid,
}
},
update(data) {
return data.item.members
},
error(error) {
console.log('errors', error)
}
},
},
The network response I got -
network_error
Using graphQLErrors
You could get the errors by looking in the error object for graphQLErrors:
error(error) {
console.log('errors', error.graphQLErrors)
}
or
error({ graphQlErrors }) {
console.log('errors', graphQLErrors)
}
Using apollo-error-link
You can use apollo-error-link to help solve your problem if the above doesn't work, docs here.
Here's an example from the docs and I added to it in the networkErrors section to show what you can do to edit the error message you see in your error block, or catch block if its a mutation.
import { onError } from "apollo-link-error";
const link = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors)
graphQLErrors.map(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
),
);
if (networkError) {
// Add something like this to set the error message to the one from the server response
networkError.message = networkError.result.errors[0].debugMessage
console.log(`[Network error]: ${networkError}`)
};
});
And then in your code:
error(error) {
console.log('error-message', error.message)
}
The console should then log your debugMessage from the server.
unfortunately i couldn't find out how i'd handle errors in such of graphql method call, but as an option you could provide onError method to ApolloClient constructor options. first argument is the error object. hopefully it may help. like so..
const apolloClient = new ApolloClient({
uri: 'http://localhost:4000',
onError(err) {
console.log(err)
},
})
I am looking to write what I am calling structural expectations with Jest and I am not sure how this could be accomplished.
To start I have a graphql server and a database with a number of todo items. I currently have the following test that just returns true if the content within the database is the same as the response that I have written. I want to check instead that the response looks like an object with data that could be anything.
Here is the code that I have:
describe('To Do:', () => {
it('add todo items', async () => {
const response = await axios.post('http://localhost:5000/graphql', {
query: `
query {
getTodoItems {
message
id
dateCreated
dateDue
}
}
`
});
const { data } = response;
expect(data).toMatchObject({
data: {
getTodoItems: [
{
message: "message",
id: "5bd9aec8406e0a2170e04494",
dateCreated: "1540992712052",
dateDue: "1111111111"
},
{
message: "message",
id: "5bd9aeec60a9b2579882a308",
dateCreated: "1540992748028",
dateDue: "1111111111"
},
{
message: "new message",
id: "5bd9af15922b27236c91837c",
dateCreated: "1540992789836",
dateDue: "1111111111"
}
]
}
})
});
});
Now I want to write something like this, where there can be any number of returned items and they follow similar structuring:
describe('To Do:', () => {
it('add todo items', async () => {
const response = await axios.post('http://localhost:5000/graphql', {
query: `
query {
getTodoItems {
message
id
dateCreated
dateDue
}
}
`
});
const { data } = response;
expect(data).toMatchObject({
data: {
getTodoItems: [
{
message: expect.any(String),
id: expect.any(String),
dateCreated: expect.any(String),
dateDue: expect.any(String)
} // There needs to be unlimited additional items here
]
}
})
});
});
I have been looking throught the docs and I even tried nesting the expectations but I can't seem to get the desired response. Let me know what yo think or if I can clarify in any way.
I figured out the best way for me to do it. I would love to hear better answers. I wrote a function within the scope of the test as a jest.fn and then I called it. In that function, I made custom checks to parse the data that was received in the response. From there I added an expect function with the 'toHaveReturnedWith' method to see what the response of my custom function was and finishing out the test.
const addTodoResponse = jest.fn(() => {
// Custom parsing and check here
// Returns true or false
});
addTodoResponse();
expect(addTodoResponse).toHaveReturnedWith(true);
Are there better ways to do this out there?
My backend is returning the following response:
const errorMessage = {
errors: [
{
message: 'User is logged out',
},
],
data: null,
};
return res.status(200).json(errorMessage);
My react-native app using relay is returning the following error:
RelayObservable: Unhandled Error Error:
Relay request for `HomeQuery` failed by the following reasons:
This error shows up when I try to query the backend and it returns the above 'errorMessage' graphql errors array. I have no way of catching this error in my relay network layer BEFORE it throws the redscreen. My Relay Environment looks like this:
const network = new RelayNetworkLayer([
urlMiddleware({
url: () => Promise.resolve(`${config.endpoint}backend`),
headers: async () => authenticateHeaders(fetchHeaders),
}),
retryMiddleware({ fetchTimeout: 1000 }),
next => req => {
if (!req.uploadbles) {
req.Accept = 'application/json';
req['Content-Type'] = 'application/json';
}
return next(req);
},
next => async req => {
const res = await next(req);
if (isLoggedOut(res)) {
// Using react-navigation, route to the login screen
dispatch(routeToLogin())
// I also tried returning `dispatch(routeToLogin())` and `{ data: null, errors: res.payload.errors }` without luck
}
return res;
}
]);
Is there a way I can navigate using dispatch(routeToLogin()) without seeing the redscreen error when graphql errors are returned?
Edit 1
For react-relay-network-modern: You can add the noThrow option like so: new RelayNetworkLayer(middlewares, { noThrow: true });
The noThrow option doesn't exist for react-relay-network-layer (relay classic), is there anything I can do to work around it?
Please try noThrow option:
const network = new RelayNetworkLayer(middlewares, { noThrow: true });