How to handle api errors using aws-amplify? - reactjs

I'm currently trying to POST data to my aws lambda functions triggered by aws api-gateway using the aws-amplify react lib.
Here is the code :
API.post("snippets","snippets/", {
body: data,
}).then(response => response).catch(console.log(err))
In the main case, everything is OK.
But my lambda function is design to validate the input data and return a status code 400 with a returned payload looking like that :
{
"errors": [
{
"field": "title",
"message": "This field is required"
}
]
}
I would like to catch those errors in order to display them in the frontend but aws-amplify seems to have an undocumented behavior.
By default, status code 400 returned are throw with a default error message :
Error: Request failed with status code 400
at createError (createError.js:16)
at settle (settle.js:18)
at XMLHttpRequest.handleLoad (xhr.js:77)
Is there a way to get the returned payload instead of this magical error?

It turns out that under the hood, aws-amplifyuse Axios to make http calls.
When using Axios, you have to console.log(error.response): https://github.com/axios/axios/issues/960
Here is the fix I've made :
API.post("snippets","snippets/", {
body: data,
}).then(response => response).catch(error => console.log(error.response.data))
A Pull Request on the aws-amplify documentation is open : https://github.com/aws/aws-amplify/pull/633

I also faced the similar issues, It showed the default error message "Request failed with status code 400", instead of the message that is returned from API.
I logged the Error object and it did not show the response attribute in it. But we do have response attribute. I tried logging the Error.response and it did contain the response sent from the API.

Just figured out this by going through the 'Cancel API requests' Amplify docs.
From what I can see this is the contents of the error object returned by the API call:
Heres what I am doing to just print out the error, obviously you would do a lot more here but its a good start.
async uploadUser(state, payload) {
const promise = API.graphql({
query: createUser,
variables: { input: payload },
});
try {
await promise;
} catch (error) {
// Print out the actual error given back to us.
console.log(error.errors[0].message);
// If the error is because the request was cancelled we can confirm here.
if (API.isCancel(error)) {
// handle user cancellation logic.
console.log(error.message);
}
}
Hope that helps 😃

Related

Getting status 400 as an error instead of json response

I have a front-end connected to back-end, using http requests.
I'm experiencing this thing where if I return res.status(200) I get a response which I can send with that response a message. But when I'm sending res.status(400). I'm getting an red error on console rather than a parsable response.
app.post('/new', (req, res) => {
const { fullname, phone, country, img } = req.body
return res.status(200).json({
title: 'Ok, we got you!'
})
})
// If I'm changing that status to 400 I get that red error on console and I cannot parse from it anything (anything atleast that I want)
Yes, and that's the correct behaviour with HTTP requests. HTTP 400 Bad Request indicates an error rather then a successful response from your web server. So you need to catch the error thrown by the server with either a .catch() clause or a try/catch block in order to access the data returned on your client side. You're server code is absolutely fine. Just add the code below to your client side application.
Using .catch approach
axios.get('/foo')
.catch(function(error) {
console.log(error.response.data);
console.log(error.response.data.title); // your title
console.log(error.response.status);
console.log(error.response.headers);
});
Using try/catch approach
try {
const resp = await axios.get('/foo');
} catch (error) {
console.log(error.response.data);
console.log(error.response.data.title); // your title
console.log(error.response.status);
console.log(error.response.headers);
}
For more information visit this link

react-jsonp giving a CORB error in a React App

Edit
based on suggestions tried doing it with fetch, now I am getting this
I am trying to get data from gnews.io/api in a simple react app.I am learning React and the solution might have been to easy but I am stuck here and cant figure out what is wrong and I keep getting this error
fetch-jsonp.js:88 Cross-Origin Read Blocking (CORB) blocked cross-origin response https://gnews.io/api/v4/top-headlines?country=us&token=myapi with MIME type application/json.
funny thing is that if I copy this url https://gnews.io/api/v4/top-headlines?country=us&token=MYAPI&callback=jsonp_1642257010280_37644
and paste it in the browser I am getting the desired response.
Would really appreciate any sort of help
this is the useEffect function that is making this api call
React.useEffect(()=> {
async function getNewsdata(country){
try {
let url = `https://www.gnews.io/api/v4/top-headlines?country=pk&token=${API2}`
let response = await fetchJsonp(url)
let result = await response.json()
console.log("News Data:", result)
} catch (error) {
console.log("error loading news data: ", error)
}
}
getNewsdata(props.country.trim())
},[])
Resorting to JSONP is frowned upon nowadays; there are safer alternatives, such as CORS, for cross-origin communication. As the response's content type is application/json, using JSONP will not work anyway because it causes Chrome's CORB feature to kick in.
Why not try to solve whatever CORS issue you seem to be having? I'd be very surprised if the API you're using weren't configured for CORS... A casual inspection of their documentation reveals that you're using the wrong domain, www.gnews.io, instead of gnews.io. The former redirects to the latter, but is not configured for CORS, which explains your CORS troubles.
Once you use the right domain (gnews.io), all your CORS troubles go away. And because there's no longer any need to reach for dirty tricks like JSONP, you can use good old reliable fetch rather than some third-party tool.
React.useEffect(()=> {
async function getNewsdata(country){
try {
let url = `https://gnews.io/api/v4/top-headlines?country=pk&token=${API2}` // gnews.io, not www.gnews.io
let response = await fetch(url) // fetch, not fetchJsonp
let result = await response.json()
console.log("News Data:", result)
} catch (error) {
console.log("error loading news data: ", error)
}
}
getNewsdata(props.country.trim())
},[])

React.js: Accessing the Retry-After header in an API response

I'm a newer programmer using React.js and the Spotify API for a music app. I’m trying to access the Retry-After header in a 429 rate-limiting error response (Spotify docs here). This is my code currently, which I loosely copied from this article.
async getArtistArt (artistID) {
let url = `https://api.spotify.com/v1/artists?ids=${artistID}`
let response = await fetch(url, {
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('accessToken')
},
});
let data = await response.json();
if (Object.keys(data)[0] === "error" && data.error.status === 429) { // Handle rate limiting
console.log('Error!');
console.log(data);
for (var pair of data.headers.entries()) {
console.log(pair);
console.log(pair[0]);
}
}
return data;
}
This is what I see in the console:
screenshot here
console.log('Error!'); // Logs 'Error!'
console.log(data); // Logs error object, but not the header
console.log(pair) // Error that says 'Uncaught (in promise) TypeError: Cannot read property 'entries' of undefined'
I've tried not putting the response into json but that seemed to have no effect.
I've tried to avoid try/catch error statements as I’ve heard they’re somewhat outdated and not usually recommended, but would I need them to access the response header?
I would be grateful for any advice. A big thank you in advance!
I think I found where your error is. The code is almost correct except that you are checking for the headers in the json of the response.
Try to do for (var pair of response.headers.entries()) {...}, so that you are taking the response rather than its json content.

How to get error body using React Apollo Link Rest

I am creating an React app using Apollo Graphql and I am having some trouble with the Apollo Link Rest. The problem is that in the middle of my app I have to make a REST request, however this request can be sucessful and return a status code = 200 or it can fail, returning a status code = 400.
It is important for my app to show the end user an error message that is returned in this request's body in case of a 400 error. However when an error happens the Apollo Link Rest just throws an exception, but it doesn't return response body back to me.
Is there a way for me to get the response body, when there is an error with the Apollo Link Rest? I thought that I could get it from the result variable, but since the Apollo throws an exception, this variable never changes.
Here is my code:
const result = await context.client.query<MyQuery>({
query: MyQuery,
variables: {
input: {
companyId: variables.companyId,
},
},
});
query MyQuery($input: MyQueryInput!) {
myQuery(input: $input) #rest(
type: "QueryResponse",
method: "POST"
path: "v1/my-query"
) {
id
minimumPreparationTime
maximumPreparationTime
extras {
id
optional
key
}
warning
error {
id
type
message
}
}
}
Extending Greg comment and apollo-link-error, you can retrieve the error body from networkError.result.message.
You can use apollo-link-error to catch and handle server errors, network errors, and GraphQL errors. You should be able to conditionally set response.errors if needed.
import { onError } from "apollo-link-error";
const link = onError(({ graphQLErrors, networkError, response, operation }) =>
{
if (graphQLErrors)
graphQLErrors.map(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path:
${path}`,
),
);
if (networkError) console.log(`[Network error]: ${networkError}`);
response.error = // set error property here
});
It may also be worth noting Apollo exposes an errorPolicy option, for which the default is none. The policy can be modified to all which, according to the docs,
is the best way to notify your users of potential issues while still
showing as much data as possible from your server. It saves both data
and errors into the Apollo Cache so your UI can use them.

How to hide console status error message while fetching in React js?

In my React app, I'm using fetch() to get data from my API, _callAPI() function gets domain parameter and call API if a website of the domain exists in my DB. If it exists, it returns the website's object, otherwise it returns 500. So, I can't figure out if the website exists until I use fetch(). The problem is that every time fetch() doesn't find anything, it throws the following:
container.jsx:25 GET
http://localhost:3000/boutiques/detail/?q=testdomain.com
500 (Internal Server Error)
When it doesn't doesn't find a lot of websites, the console log is packed with that error message. Is there a way to ignore that sort of message while fetching?
fetch()
_callApi = () => {
const { domain } = this.props;
return fetch(`/boutiques/detail/?q=${domain}`)
.then(response => {
if (response.status === 500) {
return 500;
}
return response.json();
})
.then(json => json)
.catch(err => console.log(err));
};
If you want to mute the browser error:
Unfortunately, this cannot be done, as this type of message in the
console is printed by chrome itself. Repressing this type of message
has been debated for years, but the consensus seems to be that this
message is desirable
Credits.
If you want to mute the Unhandled error in the console:
You can always mute the error on front-end, as follows:
.catch(err => { const mute = err })
But it would be better to notify somehow the user about the error and not doing such workarounds.
Also it would better your server to return an error message in the response and on the front-end side you will proceed it.
Looking into your case, it may be better the server to response with status code 400. Here are the HTTP error codes and their purpose:
4xx (Client Error): The request contains bad syntax or cannot be
fulfilled
5xx (Server Error): The server failed to fulfill an
apparently valid request

Resources