NextJS getting param from request.body if it doesnt exist - javascript

I have the following code in my nextJS api:
export default async function handler(request, response) {
if (request.method === "POST") {
const type = request.body.type ?? 'body type'
const id = request.body.id ?? 34
console.log(type, id)
if(!type || !id ) {
// Not acceptable. You are missing a required parameter.
return response.status(406).end()
}
const data = await getObjects(type, id)
return response.status(200).json(data);
} else {
return response.status(405).end();
}
}
However, if the API doesnt get one of the parameters (type or id) then it causes an XML error.
XHRPOSThttp://localhost:3002/api/list-objects
[HTTP/1.1 406 Not Acceptable 262ms]
[Fast Refresh] rebuilding hot-dev-client.js:159:24
XML Parsing Error: no element found
Location: http://localhost:3002/api/list-objects
Line Number 1, Column 1:
If the params dont have a value it fails in this same way. How can I ensure it fail gracefully if the values are not present? I would have thought the ?? operator would take care of that but its not fixing the error.

If you use fetch on the client, it doesn’t handle error status codes as errors, so it’s probably trying to parse your error (empty) content.
Before parsing the result, you can check the returned status code and throw an error if it isn’t 200:
fetch('/your/api', {method: 'POST'})
.then(res => {
if (res.status !== 200) {
throw new Error('API returned an error')
}
// Do your parsing here. E.g. for JSON:
return res.json()
})
.then(data => console.log(data))
.catch(err => console.error(err))

Related

Avoid handling if error has response in Vue with Axios in every request

I use the axios interceptors to handle some errors, specially the errors without response. And in some parts of my project, I use the message contained in the error.response.data for validations and showing a messaged stored in the backend. But this interceptor is not preventing me from having to check if the error has a response.
My interceptor:
axios.interceptors.response.use(
function (response) {
...
},
function (error) {
if (!error.response) {
...
return Promise.reject(new Error(error.message))
}
An example of a request that depends on having the error.response:
this.$store.dispatch('updateField', { [this.fieldKey]: this.value ? this.value : null }).catch((error) => {
this.validateField(error.response.data)
})
But I'd have to put the validateField call inside an if(eror.response) to avoid an error in the console, and spread this if all over my code?
response can be treated as optional, because it actually is:
this.validateField(error.response?.data)
Or normalized error that contains needed properties and doesn't rely on the structure of Axios error can be created in an interceptor:
function (rawError) {
const error = new Error(error.response?.data?.myError || error.message);
error.data = error.response?.data || null;
error.headers = error.response?.headers || null;
error.status = error.response?.status || 0;
return Promise.reject(error);
}

Differentiate between redirect/JSON-data in response from fetch API request

i am trying to build a logic at front end to differentiate between the redirect and JSON response, the end goal for this is as, if the response is redirect go to that page and if the response is having data then it will render that data on the page.
Note: it is working fine if the back end send response as either res.redirect or res.json, but i am struggling (as in below code) as when i have to check first as what the response is from back end , i thought as if i can use if else statement at front end to disgusting between res.json and res.respond, i have tried like .then(res.redirect=>{…}).then(res.json=>{}) but it doesn’t look like if i am using the correct logic.
Any suggestions please, thanks :slightly_smiling_face:
Snippet from my front end code is .
const request = new Request("http://localhost:5000/api/newuser", options);
(async () => {
const incomingdata = await fetch(request)
*// below i differetiated the incoming response as if it is res.redirect or res.json data but didnt work*
.then((res.redirect) => {
window.location.href = res.url;
})
.then((res.json) => {
console.log("cannot find data");
})
.catch((err) => console.log("err"));
Snippet from my bank end code is,
connection.query("SELECT * FROM users WHERE email=?;", [x1.Email], function (
err,
results
) {
console.log("74",results, err);
console.log("75",results[0].email);
if (err) throw err;
else {
if (results[0].email && results[0].password) {
console.log("79",results[0].email);
//console.log(results[0]);
if (results[0].password == x1.password)
res.redirect("http://localhost:3000/");
else {
res.json({
data: "invalid password",
});
}
} else res.redirect("http://localhost:3000/about");
}
});
});
For redirect you can check if the HTTP code is in the 300 range, which is provided in res.status. It won't take dot notation, So, you can use
.then(res => {
if(res.status >= 300 && res.status < 400){
// redirect
} else {
return res.json();
}
})
.then(data => {
//handle your json data
});
It would be a syntax error to use a dot in the callback argument like:
.then((res.json) => {
However, it would be possible to deconstruct an object like this:
.then(({ status, json }) => {

NodeJS Package: error handling

I have some code that uses an Overwatch API to grab some data. This is what I currently have:
OWoverallStats: (playerName, mode, region) => {
mode = (typeof mode === 'undefined') ? 'competitive' : mode.toLowerCase();
region = (typeof region === 'undefined') ? 'us' : region.toLowerCase();
playerName = playerName.replace('#', '-');
return fetch(`https://owapi.net/api/v3/u/${playerName}/stats`)
.then(res => res.json())
.then(data => {
return data[region].stats[mode].overall_stats;
});
}
This works fine, providing you enter a playerName that actually exists. The code I used to test this is:
core.OWoverallStats('Calvin-1337', 'quickplay', 'eu').then(data => {
console.log(data.tier) // grandmaster
}).catch(e => {
console.log(e);
});
In the actual code, I can check if the error code is 404 (player doesn't exist) but then I don't know what I can do with that. I don't want to throw an error, or console log it as if someone implemented this say into a Discord Bot, I'd want the person using the code to say what they wanted to do with the error.
When fetch has a response, if the status is 404 Simply throw an Error. The caller of your code can then catch it and handle however he likes.
For example, your code:
return fetch(`https://owapi.net/api/v3/u/${playerName}/stats`)
.then((res, meta) => {if (meta.status ===404) throw new Error('NoPlayer')})
The caller of your code:
core.OWoverallStats('Calvin-1337', 'quickplay', 'eu').then(data => {
}).catch(e => {
//this is where he can handle the error flexibly
});
You may see other error handling practices here

How to catch and handle error response 422 with Redux/Axios?

I have an action making a POST request to the server in order to update a user's password, but I'm unable to handle the error in the chained catch block.
return axios({
method: 'post',
data: {
password: currentPassword,
new_password: newPassword
},
url: `path/to/endpoint`
})
.then(response => {
dispatch(PasswordUpdateSuccess(response))
})
.catch(error => {
console.log('ERROR', error)
switch (error.type) {
case 'password_invalid':
dispatch(PasswordUpdateFailure('Incorrect current password'))
break
case 'invalid_attributes':
dispatch(PasswordUpdateFailure('Fields must not be blank'))
break
}
})
When I log the error this is what I see:
When I check the network tab I can see the response body, but for some reason I can't access the values!
Have I unknowingly made a mistake somewhere? Because I'm handling other errors from different request fine, but can't seem to work this one out.
Example
getUserList() {
return axios.get('/users')
.then(response => response.data)
.catch(error => {
if (error.response) {
console.log(error.response);
}
});
}
Check the error object for response, it will include the object you're looking for so you can do error.response.status
https://github.com/mzabriskie/axios#handling-errors
Axios is probably parsing the response. I access the error like this in my code:
axios({
method: 'post',
responseType: 'json',
url: `${SERVER_URL}/token`,
data: {
idToken,
userEmail
}
})
.then(response => {
dispatch(something(response));
})
.catch(error => {
dispatch({ type: AUTH_FAILED });
dispatch({ type: ERROR, payload: error.data.error.message });
});
From the docs:
The response for a request contains the following information.
{
// `data` is the response that was provided by the server
data: {},
// `status` is the HTTP status code from the server response
status: 200,
// `statusText` is the HTTP status message from the server response
statusText: 'OK',
// `headers` the headers that the server responded with
headers: {},
// `config` is the config that was provided to `axios` for the request
config: {}
}
So the catch(error => ) is actually just catch(response => )
EDIT:
I still dont understand why logging the error returns that stack message. I tried logging it like this. And then you can actually see that it is an object.
console.log('errorType', typeof error);
console.log('error', Object.assign({}, error));
EDIT2:
After some more looking around this is what you are trying to print. Which is a Javascipt error object. Axios then enhances this error with the config, code and reponse like this.
console.log('error', error);
console.log('errorType', typeof error);
console.log('error', Object.assign({}, error));
console.log('getOwnPropertyNames', Object.getOwnPropertyNames(error));
console.log('stackProperty', Object.getOwnPropertyDescriptor(error, 'stack'));
console.log('messageProperty', Object.getOwnPropertyDescriptor(error, 'message'));
console.log('stackEnumerable', error.propertyIsEnumerable('stack'));
console.log('messageEnumerable', error.propertyIsEnumerable('message'));
Here is the proper way to handle the error object:
axios.put(this.apiBaseEndpoint + '/' + id, input)
.then((response) => {
// Success
})
.catch((error) => {
// Error
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
// console.log(error.response.data);
// console.log(error.response.status);
// console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
Origin url https://gist.github.com/fgilio/230ccd514e9381fafa51608fcf137253
axios.post('http://localhost:8000/api/auth/register', {
username : 'test'
}).then(result => {
console.log(result.data)
}).catch(err => {
console.log(err.response.data)
})
add in catch
geting error response ==> err.response.data
I was also stumped on this for a while. I won't rehash things too much, but I thought it would be helpful to others to add my 2 cents.
The error in the code above is of type Error. What happens is the toString method is called on the error object because you are trying to print something to the console. This is implicit, a result of writing to the console. If you look at the code of toString on the error object.
Error.prototype.toString = function() {
'use strict';
var obj = Object(this);
if (obj !== this) {
throw new TypeError();
}
var name = this.name;
name = (name === undefined) ? 'Error' : String(name);
var msg = this.message;
msg = (msg === undefined) ? '' : String(msg);
if (name === '') {
return msg;
}
if (msg === '') {
return name;
}
return name + ': ' + msg;
};
So you can see above it uses the internals to build up the string to output to the console.
There are great docs on this on mozilla.
The only thing what helped me was the following:
axios.put('/api/settings', settings, {
validateStatus: status => status >= 200 && status < 300 || status === 422
})
https://stackoverflow.com/a/66285529/5849569
You can use inline if else statement like so:
.catch(error => {
dispatch({
type: authActions.AUTH_PROCESS_ERROR,
error: error.response ? error.response.data.code.toString() : 'Something went wrong, please try again.'
});
});
I recommend handling errors via Axios interceptors, individually for each case scenario:
// interceptor to catch errors
const errorInterceptor = (error) => {
// check if it's a server error
if (!error.response) {
console.log('📡 API | Network/Server error')
return Promise.reject(error)
}
// all the error responses
switch (error.response.status) {
case 400:
console.error(error.response.status, error.message)
console.log('📡 API | Nothing to display', 'Data Not Found')
break
case 401: // authentication error, logout the user
console.log('📡 API | Please login again', 'Session Expired')
localStorage.removeItem('user')
break
case 403:
console.error(error.response.status, error.message)
console.log('📡 API | Access denied', 'Data Not Found')
break
case 404:
console.error(error.response.status, error.message)
console.log('📡 API | Dataset not found', 'Data Not Found')
break
case 422:
console.error(error.response.status, error.message, error.response.data.detail)
console.log('📡 API | Validation error', 'Unprocessable Content')
break
default:
console.error(error.response.status, error.message)
}
return Promise.reject(error)
}

Aurelia | json parse uncaughtable exception?

So i am trying to make this post request, following aurelia docs:
http://aurelia.io/hub.html#/doc/article/aurelia/fetch-client/latest/http-services/3
And this is the request:
httpClient.configure(config => {
config
.withBaseUrl(baseUrl)
});
this.client = httpClient;
this.client.fetch(`/api/Register/${userName}`, {
method: "post",
body: json(loginInformation),
headers: {
'Access-Control-Allow-Origin' : '*',
'Accept': 'application/json'
}
}) .then(response => this.safelyParseJSON(response))
.then(data => this.setup(data));
where safetyParseJSON is:
safelyParseJSON(response) {
var parsed
try {
parsed = response.json();
} catch (e) {
}
return parsed
}
but i keep receiving this error:
"uncaught (in promise) SyntaxError: Unexpected end of JSON input"
Anyone have any idea on what am i doing wrong?
Note:
I am receiving this error only when receiving 404 / 500 from the server, if the results are ok, this works.
Note2: that i am wrapping this function inside try-catch but this still doesn't work, it doesn't catch the exception.
Note3: I have tried to replace this line:
parsed = response.json();
with this line:
parsed = JSON.parse(response);
But than the response is always undefined.
check the response's status prior to calling .json():
.then(response => {
if (response.ok) {
return response.json().then(data => this.setup(data));
}
return Promise.reject(response.text());
});
I ended up using Jeremy Danyow answer, with a small change:
.then(response => {
if (response.ok && response.status === 200) {
return response.json().then(data => this.setup(data));
}
return Promise.reject(response.text());
});
adding the response.status check was necessary in my case as response.ok was true for status code 204 (No content) aswell.

Categories

Resources