How to catch 403 response inside graphql api call? - javascript

I have a server that does the rendering of the component and returns an HTML when the request is made while rendering the server does a graphql call for a particular component which sometimes returns a 403 response.
Code:
const client = new ApolloClient({
link: new HttpLink({
uri: 'https://url/graphql',
fetch,
headers: {
'csrf-tokens': tokens,
Referer: header_referer,
},
}),
queryDeduplication: false
)}
export const getProperties = async () => {
try {
await client
.query({query, variables})
.then((response) => {
const data = response.data.properties;
if(response.error) {
throw new Error("Error encountered");
}
}
.catch((error) => {
console.log("gettProperites error")
})
} catch (err) {
console.log("Execution failed")
}
}
I'm making a graphql call inside the getProperties function and whenever I get a 403 error my pod crashes. I have wrapped the call inside try-catch block and added an additional if condition inside .then() to check for any error inside the response. Still, the 403 response is not caught and crashes the pod.
The above code is the overall structure of the code that I'm running, I have removed a few details that were not required to keep it small.

Try interceptors.
I can just tell for vue, but I think in react it's quite similar:
const link = createUploadLink({ uri: '/graphql' });
const errors = onError(({ networkError }) => {
if (networkError.statusCode === 403) {
// do something with 403 response code like:
router.push('/403');
}
else {
// do something with any other error response code
}
})
const apolloClient = new ApolloClient({
link: errors.concat(link),
...
})

Related

Handling errors in javascript/react when calling backend APIs

I am building a react-native app, and I am starting to implement a more robust and sophisticated error-handling system, specifically for handling server errors when making http requests. Here is a basic example of how I am currently making http requests in my app.
I have a 'client.js' file which is essentially just a wrapper around axios. I have a 'get' method that looks like this:
const get = async (endpoint, config = {}) => {
try {
const result = await axios.get(domain + endpoint, config);
return result;
} catch (error) {
throw new Error(error.message);
}
};
Then, I have a file for each api endpoint that I need to access. For example, I have a 'posts.js' file, and in that file I have a 'getPosts' method:
const getPosts = async (userID, page, pageSize) => {
try {
const response = await client.get(
`${endpoint}?userID=${userID}&page=${page}&pageSize=${pageSize}`
);
return response.data;
} catch (error) {
throw new Error(error.message);
}
};
And then finally, in the component that is calling getPosts, I have a function that looks something like this:
const loadPosts = async () => {
try {
const response = await getPosts();
// do something with the response from the server
} catch (error) {
// display an error message to the client
}
}
Obviously this is a very simple example of what a request might look like, but this is the basic structure that I use throughout my app. The problem I am having is that it seems very repetitive and messy to have to wrap almost all of my functions in a try/catch block, and then basically raise an error object until I get to the function that is actually going to handle the error. Is there some sort of 'design method' for error handling that simplifies and centralizes this process? Perhaps something similar to an express-middleware when creating a node server? Or is this a standard way to handle errors in javascript?
Thank you to anyone who can help!
As you are using axios as the http library here, so you can take a look at axios interceptor in order to hook the response and do something with that before passing it to the consumer. This will help you to respond to errors raised from once cental place.
axios.interceptors.response.use((response) => {
return response;
}, function(error) {
// do what you want to do with the error.
return Promise.reject(error)
});
Or with ES5 syntax
axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
// Not 200 Ok
// Do something with response error
return Promise.reject(error);
});

How am I meant to see the errors in this response return res.status(400).json({ errors: errors.array() }); I just see a 400 bad request in my console

I'm trying to implement validation on my Node.js back-end so whenever the data doesn't pass the validation, I'm sending this to the front-end:
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
so that I could render the errors on the front-end. Sadly, when I open the console, I only see:
POST http://localhost:3000/login 400 (Bad Request)
as opposed to an object that would contain config, data, headers, request and status. So I am wondering how the hell am I supposed to access the errors object I'm returning to the front-end. I'm following express-validator's docs and this is how they do it as well - https://express-validator.github.io/docs/index.html
You just need to retrieve and parse the response body, even for non-successful requests.
Here's an example using fetch but the approach would be similar using other libs
const doFetch = async (url) => {
const res = await fetch(url, {
// method, headers, body, etc
})
if (!res.ok) {
if (res.status === 400) {
throw await res.json() // this will parse the JSON response body
}
// handle other errors
throw { errors: [ res.statusText ] } // conform to a standard format
}
// handle success
}
doFetch('http://example.com').catch(({ errors }) => {
console.error(errors)
})

How to call an external API then return this data from an in hapi.js Api

I am new to the Hapi.js node extension.
I am trying to call an external API into my server because the external API is protected with CORS and I can't call it from my front (Angular 9).
So I set up my hapi server with routes etc and now in a route I am trying to import the external data and when the front call the route of my hapi api it show the data from the external API.
I didn't find any documentation or already topics about this problem, if you could provide me with some information it would be very helpful!
(I want to do my external API call from the route solcast)
This is my index.js :
'use strict';
require('dotenv').config()
const Hapi = require('#hapi/hapi');
const init = async () => {
const server = Hapi.server({
port: 3000,
host: 'localhost',
routes: {
cors: true
}
});
server.route(require('./routes/base').test);
server.route(require('./routes/solcast').solcast);
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();
This is my solcast.js :
This while console.log the error :
Error: handler method did not return a value, a promise, or throw an error
And then console.log the data. I assume that the data is not received when the return is done.
const joi = require('#hapi/joi');
const fetch = require("node-fetch");
exports.solcast = {
method: 'GET',
path: '/solcasttest',
handler: (request, h) => {
fetch("https://linkToTheExternalApi")
.then(response => response.json())
.then(data => {
console.log(data)
return data
})
.catch(err => console.log(err))
console.log(testSolcast)
}
}
Thank you for your help, if you need any other information hit me up.
As the error thrown suggests, a handler in hapi.js must return a value, a promise or throw an error.
In your case, the handler is an asynchronous operation, so you have to return a promise.
As fetch already creates a promise, it is enough if you return the promise created by fetch in your handler :
const fetch = require("node-fetch");
exports.solcast = {
method: 'GET',
path: '/solcasttest',
handler: (request, h) => {
return fetch("https://linkToTheExternalApi")
.then(response => response.json())
.then(data => {
console.log(data)
return data
})
.catch(err => console.log(err));
}
}

Axios cancel token cancelling request before even called

So I am implementing axios call cancelation in the project. Right now looking at axios documentation it seems pretty straight forward https://github.com/axios/axios#cancellation
So I did define variables on the top of my Vue component like
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
obviously on top of that is import axios from 'axios';
Then I have a method of fetching the API
On the top of the method I want to cancel out the request in case it is running so the last one cancels out if the user spams the filtering.
async fetchPartners(inputToClear) {
source.cancel();
...
try {
const response = await axios.get(`../partners?limit=1000${this.createRequestString()}`, {
cancelToken: source.token
});
// Here you can see I did add the cancelToken to the request
this.partners = response.data.data;
} catch (error) {
if (axios.isCancel(error)) {
console.log('Request canceled', error.message);
}
const fetchErrors = this.utilGlobalHandleErrorMessages(error);
this.utilGlobalDisplayMessage(fetchErrors.message, { type: 'error' });
return [];
} finally {
...
}
},
So it is pretty straight forward, just took the code from axios documentation I gave you above, it should be working by logic. But what is actually happening, it doesn't even allow me to fetch the call, it is already cancelled out before I can call it. On console it shows me
Request canceled undefined
It just catches the error as if I am cancelling the call, but how can it be, because I am source.cancel() before the call.
Anyone has any idea?
I hope you should throttle your requests instead of canceling the request.
Could you please try the following if throttle does not suit your requirement?
const CancelToken = axios.CancelToken;
let source;
async fetchPartners(inputToClear) {
if(source){
source.cancel();
}
...
source = CancelToken.source();
try {
const response = await axios.get(`../partners?limit=1000${this.createRequestString()}`, {
cancelToken: source.token
});
// Here you can see I did add the cancelToken to the request
this.partners = response.data.data;
} catch (error) {
if (axios.isCancel(error)) {
console.log('Request canceled', error.message);
}
const fetchErrors = this.utilGlobalHandleErrorMessages(error);
this.utilGlobalDisplayMessage(fetchErrors.message, {
type: 'error'
});
return [];
} finally {
...
}
}

How to handle net::ERR_CONNECTION_REFUSED in Axios - Vue.js

Below is my connection request code :
doLogin(this.login).then(response => {
var token = response.data.token;
localStorage.setItem('AUTH_TOKEN', JSON.stringify(token));
this.$router.push({name: 'Devices'});
});
}).catch(error => {
console.log(error.response.data.message);
});
the catch() part works fine for http errors (like 400, 404, 403..etc). But when my server is offline this script just throws net::ERR_CONNECTION_REFUSED. Is there any way to handle this error and let the front-end user know that the server is currently offline.?
Here is the doLogin() function just in case,
function doLogin(data) {
const url = 'http://localhost:3000/authenticate';
return axios.post(url,data);
}
You can try this in the catch part:
catch(error => {
if (!error.response) {
// network error
this.errorStatus = 'Error: Network Error';
} else {
this.errorStatus = error.response.data.message;
}
})
You may use interceptors:
axios.interceptors.response.use(
response => {
return response
},
error => {
if (!error.response) {
console.log("Please check your internet connection.");
}
return Promise.reject(error)
}
)
You should do the same validation that #chithra pointed out in the .then() because i'm having a weird issue when testing requests with my servers down, the "response" comes as if it was a success.
Also, on the .then() do it with response.status instead of response.error
By using npm; a standard package manager for the JavaScript runtime environment Node.js.
With npm:
npm i axios
Next, you should import Axios in your src/App.vue file
import axios from 'axios';
you will need to call it on a lifecycle hook. Here we will use the beforeCreated() lifecycle hook, this is because we will be able to retrieve sensitive data and events that are active with the beforeCreated hook.
data() {
return {
network: false,
}; },
beforeCreate() {
axios
.get("http://localhost:13172/api/product/getproducts")
.then((response) => {
console.log(response);
this.network = true;
})
.catch((error) => {
console.log(error), (this.network = false);
}); }

Categories