How to Fix Bug in Apollo-link for GraphQL Error - error-handling

In here, I can both graphQLErrors and networkError:
const errorLink = onError(({ operation, graphQLErrors, networkError, forward }) => {
if (process.env.NODE_ENV !== 'production') {
if (networkError) {
console.log(`[Network Error]:`, networkError.message);
}
if (graphQLErrors) {
graphQLErrors.forEach((error) => {
console.log(`[GraphQL Error]:`, error.message);
});
}
}
});
but when trying to get these errors inside useQuery, at the component level, only networkError is returned while graphQLErrors is an empty array:
let { loading, error, data } = useQuery(GET_ALL_PROJECTS, {
 variables: { pageNum: 1, pageSize: 10 },
 fetchPolicy: 'network-only',
 });
For example, I get an error 403 to onError function from backend, but could not handle this error inside useQuery!
How to fix this issue??

Apollo client passes either graphQLErrors or networkError forward, that's true. I believe it's under an assumption that when the network error happens, the GraphQL error in returned data is more technical and shouldn't be shown to the user. If you really want to access the additional error info sent by your server, you can actually access it in networkError.result.errors.
My code in typescript extracting the error:
const { networkError } = error
const networkGraphQLErrorsPresent =
networkError &&
"result" in networkError &&
networkError.result.errors &&
networkError.result.errors.length > 0
const extractedError =
networkGraphQLErrorsPresent ?
(networkError.result.errors[0] as GraphQLError) :
undefined

Related

Property 'on' does not exist on type 'Stan'.ts(2339)

I'm actually working on microservices project using a nats-streaming-server as a event-bus and i trying to write a publisher.ts file
but i face this erreur
PS: i'm writing this code with typescript
Property 'on' does not exist on type 'Stan'.ts(2339)
import nats, { connect, Message } from 'node-nats-streaming';
console.clear();
const stan = nats.connect('ticketing', '123', {
url: 'http://localhost:4222'
});
stan.on('connect', () => {
console.log('Listener connected to NATS');
const subscription = stan.subscribe('ticket:created');
subscription.on('message', (msg: Message) => {
const data = msg.getData();
if (typeof data === 'string') {
console.log(`Recieved event #${msg.getSequence()}, with data: ${data}`);
}
});
})
Seems like typescript doesn't know what events are. Try adding #types/events to the dependencies via npm i #types/events

promise returned from getRestaurantsFromYelp is ignored

Morning/Evening everybody
So I'm tryna get restaurants from yelpApi(react native App), but the fetch is not working.
First I'm getting a message as what "businesses" isn't a resolved variable, and the response from my getRestaurantsFromYelp() function is getting ignored, don't know why. If anybody could hep me fix that.
const [restaurantsData, setRestaurantsData] = useState(localRestaurants);
const getRestaurantsFromYelp = () => {
const yelpUrl = "api.yelp.com/v3/businesses/search?term=restaurants&location=US"
const apiOptions = {
headers : {
Authorization : `Bearer ${YELP_API_KEY}`,
}
}
return fetch(yelpUrl, apiOptions).then((res) => res.json()).then((json) => setRestaurantsData(json.businesses)); //message => unresolved variable businesses
};
useEffect(() =>{
getRestaurantsFromYelp(); // message => promise returned from getRestaurantsFromYelp is ignored
}, [])

How to prevent error propagation in Apollo Client useQuery in react?

I'd like to catch the error in component level and prevent propagation while using the useQuery in #apollo/react-hook.
Here is my example code
const invitationDocument = gql`
query DecodeInvitation($token: String!) {
DecodeInvitation(token: $token) {
name
email
}
}
`
const InvitationPage = (props) => {
const { data, error, loading } = useQuery(invitationDocument, {variables: { token: "XXXX" }});
if(error)
{
return <InvitationErrorPage error={error.message}/>
}
return loading? <LoadingPage> : <InvitationAcceptPage />
}
It works fine but at the same time, the error is being propagated to its parents level so I get another error notification message which comes from the error handler at the global level.
At the application level, I use the apollo-link-error to manage the Graphql errors.
import { onError } from 'apollo-link-error';
const errorLink = onError (({ graphqlErrors, networkError }) => {
if(graphqlErrors)
notification.error(graphqlErrors[0].message);
});
const client = ApolloClient({
cache: new InMemoryCache(),
link: ApolloLink.from([
errorLink,
new HttpLink({ uri: `http://localhost:8080/graphql`})
])
})
For now, I am finding a solution to stop propagation to top-level so that I can show only InvitationErrorPage and stop displaying error notification at the global level.
I was also trying to prevent errors from being logged in an Error Link by handling them on a useQuery hook and a further delve into the ApolloLink documentation helped clear up what is happening. The key misunderstanding is that the Error Link is not a parent- or application-level handler, it is request middleware. It's helpful to think about how the data is coming back from the server:
Thus, when you see an error notification from the Error Link it is not something that "propagated up" from the useQuery hook: it occurred in the request path before the useQuery result was available on the client.
Thus, the onError callback for the Error Link will always be called before any error handling code in the useQuery hook.
Probably your best bet is to use a combination of the operation and graphQLErrors[x].extensions to figure out what errors you should pass through the Error Link middleware like so:
const errorLink = onError(({operation, response, graphQLErrors}) => {
if (!graphQLErrors) {
return;
}
if (operation.operationName === "DecodeInvitation") {
for (const err of graphQLErrors) {
if (err.extensions?.code === 'UNAUTHENTICATED') {
// Return without "notifying"
return;
}
}
}
// Notify otherwise
notification.error(graphqlErrors[0].message);
})

Vuejs error after passing axios interceptor

I have a problem that I can't solve with vue.js
I intercept queries that return an error (axios interceptor), and when it passes through this interceptor, the catch of the axios query is still taken into account.
Except that I wait for an error "error.api". which I don't receive, so it generates a console error.
Here is the code:
axios.interceptors.response.use(null, error => {
let path = '/login';
switch (error.response.status) {
case 401: path = '/login'; break;
case 404: path = '/404'; break;
}
store.commit('logout')
router.push(path);
return Promise.reject(error);
});
this error
2.js:376 Uncaught (in promise) TypeError: Cannot read property 'api' of undefined
And finally, the axios query and the error is generated by the last line (err.api[0])
deleteApi(id) {
this.$store.dispatch('deleteApi', id)
.then((res) => {
this.$toast.success(res.data.success)
this.deleteApiModal(id)
})
.catch(err => this.$toast.error(err.api[0]))
},
I finally found a solution but very dirty, which I find repetitive for not much.
It's on each call axios, to put a condition that checks if "err" exists...
I would have preferred to be able to interact on the interceptor to have managed this in only one place.
If someone has a better solution, I'll take it !
deleteApi(id) {
this.$store.dispatch('deleteApi', id)
.then((res) => {
this.$toast.success(res.data.success)
this.deleteApiModal(id)
})
.catch(err => { if(err) this.$toast.error(err.api[0]) })
},

Error occurs infinitely on nuxt axios. What did I do wrong?

I am currently working on a project with nuxt, and I communicate data with axios.
However, if an error occurs in Axios, it requests Axios indefinitely and stops.
If I make a wrong Axios request, I want an error return right away. What did I do wrong?
The error 'cannot read property 'length' of undefined' occurs at first. And there's an infinite number of errors 'cannot read property 'data' of undefined'
This is code written in plugin.
import SecureLS from 'secure-ls'
export default function({ app, $axios, store }) {
if (process.client) {
const ls = new SecureLS({
encodingType: 'aes',
encryptionSecret: 'key'
})
$axios.defaults.timeout = 3000
$axios.onRequest((config) => {
if (ls.get('key')) {
config.headers.common['X-Token'] = `token ${ls.get('key')}`
}
})
$axios.onError((error) => {
if (
error.response.data &&
error.response.data.detail === 'email confirmed required.'
) {
app.router.push({ name: 'check' })
}
})
}
}