How can axios get the status code in .catch()? - javascript

In the Axios document:
axios.get('/user/12345')
.catch(function (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);
});
we know we can catch the error in the .catch() method.
But when I use the Django-Rest-Framework as the backend API provider. it only provide the data, there is no status in it:
You see the error:
{username: ["A user with that username already exists."]}
but in the browser, we can know the status code:
Before asking this question, I have read How can I get the status code from an http error in Axios?
this post.
But the post seems different with mine.
EDIT-1
In my Django-Rest-Framework project:
the view:
class UserCreateAPIView(CreateAPIView):
serializer_class = UserCreateSerializer
permission_classes = [AllowAny]
queryset = User.objects.all()
the serializer:
class UserCreateSerializer(ModelSerializer):
"""
user register
"""
class Meta:
model = User
fields = [
'username',
'wechat_num',
'password',
]
extra_kwargs = {
"password":{"write_only":True}
}
def create(self, validated_data):
username=validated_data.pop('username')
wechat_num = validated_data.pop('wechat_num')
password=validated_data.pop('password')
user_obj = User(
username=username,
wechat_num=wechat_num,
)
user_obj.set_password(password)
user_obj.save()
group=getOrCreateGroupByName(USER_GROUP_CHOICES.User)
user_obj.groups.add(group)
return validated_data

I find in the interceptors configuration:
Axios.interceptors.response.use(
res => {
return res;
},
error => {
return Promise.reject(error.response.data)
}
);
I was return the error.response.data directly, I could configure it to error.response, or error.
if I configure the error.response, then in the .catch() I can console like bellow:
console.log(response.data);
console.log(response.status);
console.log(response.headers);

Related

unable to access 200 code status in angular server response

Goal: If the server response with 200 code, I want to perform some changes on the record locally.
issue: I am not able to access the response code or the 'message' attribute
this is how the server response from this http call::
// MongooseModelSchema: this is the model that uses moongose
MongooseModelSchema.updateOne({ _id: req.params.id, creator: req.userData.userId }, channel)
.then(result => {
if (result.n > 0) {
res.status(200).json({ message: "Update successful!" }); // this is what I want to capture
} else {
res.status(401).json({ message: "Not authorized!" });
}
})
.catch(error => {
console.log(error);
res.status(500).json({
message: "Couldn't udpate channel!"
});
});
I am able to hit the API no problem
I have the following http snip in my angular code::
this.http
.put(BACKEND_URL+'setState/' + id, channelData)
.subscribe(response => {
console.log('response',response);
console.log('check if response has Update successful!: ',JSON.stringify(response).search('Update successful!'));
console.log('response.message',response.message);
this.router.navigate(["/editChannel", id]);
})
this is the console.log image:
issue image: as you can see, i dont have access to the return code. I also cant access the 'message' property UNTIL i run the code, then it works.... super weird.
How do I check for the 200 code?
That makes sense. Message object is not typed, so compiler is telling you that message doesn't exist on response. Instead what you should do is the following:
myresponse.ts:
interface MyResponse {
message: string
}
this.http
.put<MyResponse>(BACKEND_URL+'setState/' + id, channelData)
.subscribe(response => {
console.log('response',response);
console.log('check if response has Update successful!: ',JSON.stringify(response).search('Update successful!'));
console.log('response.message',response.message);
this.router.navigate(["/editChannel", id]);
})
now angular will grab the response and map it to the MyResponse interface giving you ability to access the message property. Alternatively you could keep it as any or unknown not sure what the type on response by default is, but if its any just do response['message']
Hope that helps.

Error , Console log the axios network response

1.I'm working on an backend API but at some point I need to get user data from another API. I am trying to use Axios to make http request in order to do that. The request return the result in the browser as expected but the problem is that I can't display console log in the terminal. It doesn't show anything even though I asked the program to do so. Is there a problem probably with my code?
2.Error message =>>> POST http://localhost:8000/api/register 400 (Bad Request) Error: Request failed with status code 400`
const handleSubmit = async () => {
//e.preventDefault();
try
{
// console.log(name, email, password, secret);
const { data } = await axios.post("http://localhost:8000/api/register", {
name,
email,
password,
secret,
});
setOk(data.ok); //useState component
}
catch (error) {
**strong text**
console.log(error.response.data);
}
}
import User from '../models/user'
//import{ hashPassword, comparePassword } from '../helpers/auth'
export const register = async (req,res) => {
//console.log('Register endpoint =>', req.body)
//to make this work make express.json is applied in the above middleware
//console.log error to debug code
const {name, email, password, secret} = req.body;
//validation
if(!name) return res.status(400).send('Name is required')
if(!password || password.length < 6) return res.status(400).send('Password is
short
or password is not entered')
if(!secret) return res.status(400).send('Answer is required')
//The above code is for validation purpose to make sure data is correctly
entered
const exist = await User.findOne({email })
if(exist) return res.status(400).send('Email is taken')
}
.catch(error => {
console.log(error)
})
May be catching error on your axios is wrong try this

Getting error on console despite handling it (MERN + Redux)

I am sending axios get request whose end-point sends the user associated with the token stored in localStorage and then the redux state is updated with the user. When I don't have a token the end-point return a res with status 401 with message "Unauthorized" and then I handle it in the catch statement and set the "error" redux state. But even after doing this the error is displayed on the console like this:
Failed to load resource: the server responded with a status of 401 (Unauthorized) /users/auth:1
This is the function which makes api call and authorizes the user:
export function loadUser(){
return function (dispatch,getState){
dispatch(userLoading());
const token = getState().auth.token;
const config = {
headers:{
'Content-Type':'application/json'
}
}
if(token) config.headers['auth-token']=token;
axios.get('http://localhost:80/users/auth',config)
.then(user => {
dispatch(clearError())
dispatch(userLoaded(user.data))
})
.catch(error => {
dispatch(setError(error.response.status,error.response.data.msg));
dispatch(authError());
})
}
}
This is the middleware which handles the token before hitting the endpoint (In my case response is returned from here itself since there is no token sent):
function auth(req,res,next){
const token = req.header('auth-token');
if(!token) res.status(401).json({msg:"Unauthorized"})
else{
try{
const decoded = jwt.verify(token,jwt_secret);
req.user = decoded;
next();
}
catch(e){
res.status(400).json({msg:"Invalid token"})
}
}
}
I'm not able to figure out why am I getting error on console (State is getting updated as desired)
It is actually impossible to do with JavaScript. because of security concerns and a potential for a script to hide its activity from the user.
The best you can do is clearing them from your console.
console.clear();
I think it is because you are not getting the token when consulting your API.
If this is the case I recommend you use defaults.headers.common in this way
const axiosApi = axios.create({ baseURL: "http://localhost:80" });
const headerAuth = () => {
const token = getMyToken();
if (token) {
axiosApi.defaults.headers.common["Authorization"] = `Bearer ${token}`;
} else {
delete axiosApi.defaults.headers.common.Authorization;
}
};
export function loadUser(){
headerAuth(); // <-----
return function (dispatch,getState){
dispatch(userLoading());
axiosApi.get('/users/auth',config)
.then(user => {
dispatch(clearError())
dispatch(userLoaded(user.data))
})
.catch(error => {
dispatch(setError(error.response.status,error.response.data.msg));
dispatch(authError());
})
}
I recommend that you do not store the token in the REDUX but in sessionStorage

Nest.js sending custom response to client from an Exception

I'm facing a problem that i'd like to fix...
I'm working on a procject using Nest.js as Backend framework for APIs, and Nuxt.js for Client...
Everything is working fine, but when i'm trying to throw an error in a service, that is injected into the controller, i'm not able to send a custom response to the client. Those the scenarios that i've faced:
account.service.ts
async createAccount(_account: AccountEntity){
return await this.accountRepository.save(_account)
}
async _accountExists(_account: AccountEntity) {
const itExists = await this.findOne(_account)
if(itExists){
throw new ConflictException(`Username already exists!`)
}
}
account.controller.ts
#Post()
#UseFilters(new HttpExceptionFilter())
async createAccount(#Body() userAccount: createAccountDto, #Res() res: Response) {
try {
await this.accountService._accountExists(userAccount).then(async () => {
return await this.accountService.createAccount(userAccount)
})
} catch (e) {
res.status(e.status).json(e.message)
}
}
This returns me this error in the client, if the user already exists but it doesn't send the json to the client.
POST http://localhost:3000/account 409 (Conflict)
Request failed with status code 409
If i change it res.json(e), it sends me to the client the error with status 201 as you can see in the image, but the response is fine in all scenarios.
So the question is... how i can get this response with correct status code?
This is the Exception Filter:
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '#nestjs/common';
import { Request, Response } from 'express';
#Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
response
.status(status)
.json({
statusCode: status,
name: exception.name,
message: exception.message.message,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
Seems that the problem itself wasn't the server, but from client.
Loggin the errors doesnt log the object, you need to log errors.response

What is the appropriate way of handling user (action) related errors?

I'm scratching my head trying to figure out the best way to handle errors from specific user actions. I'm using Express as my web server and even though it works, for the most part, I am getting not-so-useful, generic error messages. For instance, in the code below, I get the Request failed with status code 400 error message on the client side for the first two conditions/exceptions in the try block.
How do I approach this in the following example?
Express Server-side Controller
async function voteInPoll (req, res) {
const { category, pollId } = req.params;
const { name, choiceId, voterId } = req.body;
try {
const poll = await Poll.findById(pollId);
// Check if user has already voted in poll
const hasVoted = poll.votedBy.some(voter => voter.equals(voterId));
if (!voterId) { // Check if user is authenticated
res
.sendStatus(400)
.json({ message: 'Sorry, you must be logged in to vote' });
} else if (voterId && hasVoted) {
res
.sendStatus(400)
.json({ message: 'Sorry, you can only vote once' });
} else {
const choice = await poll.choices.id(choiceId);
const votedChoice = { name, votes: choice.votes + 1 };
await choice.set(votedChoice);
await poll.votedBy.push(voterId);
poll.save();
res
.sendStatus(200)
.json({
message: 'Thank you for voting. Find other polls at: ',
poll,
});
}
} catch (error) {
throw new Error(error);
}
}
React/Redux Action
export const voteInPoll = (category, pollId, votedItem, voterId) => async dispatch => {
try {
const response = await axios.post(
`http://localhost:3050/polls/${category}/${pollId}/vote`,
{
...votedItem,
voterId,
}
);
dispatch({ type: store.polls.VOTE_SUCCESS, payload: response.data.poll });
} catch (error) {
console.log(error);
dispatch({ type: store.polls.VOTE_FAILURE, payload: error.message });
}
};
Edit
What I find rather bizarre is I get the expected error response sent, as seen below under the Network tab of Chrome's Developer tools.
You should not be using res.sendStatus(statusCode) because of the following as defined in the docs here:
Sets the response HTTP status code to statusCode and send its string representation as the response body.
The key thing about the above is:
and send its string representation as the response body.
So doing: res.sendStatus(400).json({ message: 'Oops 400!'}) will not give you a JSON response which is what you're expecting, but simply display:
Bad Request
Which is the string representation of the 400 HTTP status code: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors
What you need to do is replace all of your res.sendStatus(..).json(..) with res.status(...).json(...) like so:
if (!voterId) { // Check if user is authenticated
res
.status(400)
.json({ message: 'Sorry, you must be logged in to vote' });
} else if (voterId && hasVoted) {
res
.status(400)
.json({ message: 'Sorry, you can only vote once' });
} else {
// ...
}
and so on.

Categories