I am making a fetch api call but in case of a 500 error the following middleware kicks in and sends back a json object in response body.
app.Use(async (context, next) =>
{
try
{
await next();
}
catch (Exception ex)
{
if (context.Response.HasStarted)
{
throw;
}
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json";
var json = JToken.FromObject(ex);
await context.Response.WriteAsync(json.ToString());
}
});
On the client side I have the following code
return fetch(url, content)
.then(function(res) {
if (!res.ok) {
console.log(res, res.json())
throw Error(res.statusText);
}
return res;
})
.then(res => res.json())
.catch(e => console.log('Error fetching accounts:', e))
I am not able to access the json with error information. How can I do it ?
Working code after following the correct answer
return fetch(url, content)
.then(function(response) {
if (!response.ok) {
return response.json()
.then(function(obj) {
throw Error(obj.ErrorMessage)
})
}
else {
return response.json()
.then(json => {
/*further processing */
})
}
}).catch(/* work with the error */)
The json function of the Response object returns a Promise, not the actual parsed value.
res.json()
.then(function(object) {
// Here you have the parsed JSON object.
console.log(object);
});
Related
In the following code, you can see that I am creating an errorLink. It makes use of an observable, a subscriber and then it uses this forward() function.
Can someone explain to me what's exactly happening here. I am bit familiar with observables, but I cannot understand what's going on here.
When creating the observable, where does the observer argument come from?
I would love to dive a bit deeper.
Also, why is bind used, when creating the subscriber?
const errorLink = onError(
({ graphQLErrors, networkError, operation, forward }) => {
if (graphQLErrors) {
for (let err of graphQLErrors) {
switch (err.extensions.code) {
case "FORBIDDEN":
console.log("errs!")
// ignore 401 error for a refresh request
if (operation.operationName === "RehydrateTokens") return
const observable = new Observable<FetchResult<Record<string, any>>>(
(observer) => {
console.log(observer)
// used an annonymous function for using an async function
;(async () => {
try {
console.log("yop bin hier")
const accessToken = await refreshToken()
console.log("AT!", accessToken)
if (!accessToken) {
throw new GraphQLError("Empty AccessToken")
}
// Retry the failed request
const subscriber = {
next: observer.next.bind(observer),
error: observer.error.bind(observer),
complete: observer.complete.bind(observer),
}
forward(operation).subscribe(subscriber)
} catch (err) {
observer.error(err)
}
})()
}
)
return observable
}
}
}
if (networkError) console.log(`[Network error]: ${networkError}`)
}
)
Just so that you are understanding the context.
Iam combining mutliple apollo links.
const httpLink = createHttpLink({
uri: "http://localhost:3000/graphql",
})
// Returns accesstoken if opoeration is not a refresh token request
function returnTokenDependingOnOperation(operation: GraphQLRequest) {
if (isRefreshRequest(operation)) {
return localStorage.getItem("refreshToken")
} else return localStorage.getItem("accessToken")
}
const authLink = setContext((operation, { headers }) => {
let token = returnTokenDependingOnOperation(operation)
console.log("tk!!!", token)
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
},
}
})
const client = new ApolloClient({
link: ApolloLink.from([errorLink, authLink, httpLink]),
cache: new InMemoryCache(),
})
I am trying to handle errors in my Laravel/Vue application. As far as I can tell, I have everything in place as I am seeing what I expect. However, I am unable to get/return the status code if the response is anything other than 200.
console.log('status: ', response.status); // 200
If the response is 400 (or anything other than 200), I am unable to read it.
console.log('status: ', response.status); // undefined
Here is what I am creating for a response in my Controller:
Controller.php
...
if ($exception->getCode() === 400) {
return response()->json(['errors' =>
[
'title' => 'Bad Request',
'detail' => 'The username or password you have entered is invalid',
],
], $exception->getCode());
}
In the network tab, the response is coming back as 400, and the response object looks like this:
{"errors":{"title":"Bad Request","detail":"The username or password you have entered is invalid"}}
Awesome!
The request in my Vue component looks like this (click event handler):
...
try {
await this.$store.dispatch("user/signInWithEmailAndPassword", this.form)
.then(response => {
console.log('status: ', response.status);
switch (response.status) {
case 200:
console.log('good to go!');
break;
case 400:
console.log('400 error'); // not getting here
break;
case 401:
console.log('401 error'); // or here
break;
default:
console.log('some other error'); // end up here all the time
break;
}
})
.catch(error => {
console.log('SignInForm.authenticate error: ', error);
});
} catch (error) {
console.log("SignInForm.handleSubmit catch error:", error);
}
In my Vuex store, I am just returning the response from my service to see what I'm getting:
Vuex Store.vue
return await UserService.signInWithEmailAndPassword(credentials)
.then(response => {
return response;
...
UserService.vue
...
return await client.post('/v1/login', credentials)
.then(response => {
return response;
})
.catch(function (error) {
console.log('UserService.signInWithEmailAndPassword error: ', error); // getting here
return error;
});
So far, the only luck I'm having is seeing this in my console:
UserService.signInWithEmailAndPassword error: Error: Request failed with status code 400
How can I read the 400 error code to show the error I really want? It seems all the pieces are there. I'm not handling the error response correctly. Thank you for any suggestions!
EDIT
I have updated my code to reflect your suggestions, and I believe it stems from not returning my UserService call correctly. Here's what I'm doing now:
return await client.post('/v1/login', credentials)
.then(user => {
console.log('user: ', user);
return user;
})
.catch(function (error) {
console.log('error: ', error);
return error;
});
When I provide an invalid un/pw, I am getting into the catch, and seeing the error message which is:
error: Error: Request failed with status code 400
I am failing to properly return it though. As in, the code that calls this method is always ending up in the .then and not in the .catch block.
I feel like this is a really simple thing that I'm making incredibly difficult. Thank you for your help!
then is called when the the status is: status >= 200 && status < 300. Errors are catched in the catch method. The above code should be changed like this:
try {
await this.$store.dispatch("user/signInWithEmailAndPassword", this.form)
.then(response => {
console.log('status: ', response.status);
console.log('good to go!');
})
.catch(error => {
switch (error.response.status) {
case 400:
console.log('400 error'); // not getting here
break;
case 401:
console.log('401 error'); // or here
break;
default:
console.log('some other error'); // end up here all the time
break;
}
console.log('SignInForm.authenticate error: ', error);
});
} catch (error) {
console.log("SignInForm.handleSubmit catch error:", error);
}
Of course you can destruct the error and get the response directly
.catch(({ response }) => {
switch (response.status) {
UPDATE
You should also properly return the error from the service:
return await client.post('/v1/login', credentials)
.then(user => {
console.log('user: ', user);
return user;
})
.catch(function (error) {
console.log('error: ', error);
return Promise.reject(error);
});
You could add a const variable in your js getting the content of a file which returns an array of key->value and then accessing it from your js with the error message.
Example of config file:
return [
"200" => "Todo bien",
"201" => "Todo mal"
];
Vue file:
showItems()
{
axios.get('shopping-cart').then(response => {
if ( response.status != 200 ) return this.error = this.errors[response.status];
this.items = response.data;
}).catch(error => this.error = error);
}
I'm trying to get the response from File2.vue and pass back to File1.vue. I'm using VueJS v1.0.28, How to get response from other file request response?
File1.vue
File2.updateNotice(this,{'id':id}).then((response) => {
console.log("response from File2 :",response)
});
File2.vue
updateNotice(context,params) {
let url = staff_service.STAFF_NOTICES_READ_RESOURCE;
Vue.http.post(
url,
params
).then(response => {
return response;
})
}
Error response from File1:
Cannot read property 'then' of undefined
This is now solved, added a
return
before
Vue.http.post(
in File2.vue
File1.vue
File2.updateNotice(this,{'id':id}).then((response) => {
console.log("response from File2 :",response)
});
File2.vue
updateNotice(context,params) {
let url = staff_service.STAFF_NOTICES_READ_RESOURCE;
return Vue.http.post(
url,
params
).then(response => {
return response;
})
}
I've overridden an action in the controller that was generated from a blueprint API in Sails.JS.
I used the create action. Now I can't get a Sails.JS socket event from that action anymore, however, other actions are working fine.
io.socket.on('posts', function gotHelloMessage(data) {
console.log('Post!', data);
});
io.socket.get('/posts', function gotResponse(body, response) {
console.log('Posts: ', body);
})
What's the way to implement so that the create action also generates the event with my newly implemented actions?
create: function(req, res) {
if (
!_.has(req.body, "title") ||
!_.has(req.body, "body") ||
!_.has(req.body, "category")
) {
return res.serverError("No field should be empty.");
}
var uploadPath = "../../assets/posts";
return req
.file("thumbnail")
.upload({ dirname: uploadPath }, async function(err, uploadedFiles) {
if (err) return res.serverError(err);
let post;
try {
post = await Posts.create({
title: req.body.title,
body: req.body.body,
category: req.body.category,
thumbnail:
uploadedFiles.length === 0
? ""
: uploadedFiles[0].fd.split("/").reverse()[0]
}).fetch();
return res.json({ result: post });
} catch (err) {
return res.json({ error: err });
}
});
}
"By default, an admin-on-rest app doesn’t require authentication".
I have written an application with AOR and Loopback API, etc, and it works well. Except for one thing, I can't turn on turn on authentication. Any username/password will work, just like in the Demo.
From what I can see all required components load, AuthClient etc., Loopback is configured and is waiting for user authorization requests but never gets any.
I copy/pasted a lot of Demo's parts...
Any hints please?
I use the unchanged authClient from kimkha aor loopback
import storage from './storage';
export const authClient = (loginApiUrl, noAccessPage = '/login') => {
return (type, params) => {
if (type === 'AUTH_LOGIN') {
const request = new Request(loginApiUrl, {
method: 'POST',
body: JSON.stringify(params),
headers: new Headers({ 'Content-Type': 'application/json' }),
});
return fetch(request)
.then(response => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
})
.then(({ ttl, ...data }) => {
storage.save('lbtoken', data, ttl);
});
}
if (type === 'AUTH_LOGOUT') {
storage.remove('lbtoken');
return Promise.resolve();
}
if (type === 'AUTH_ERROR') {
const { status } = params;
if (status === 401 || status === 403) {
storage.remove('lbtoken');
return Promise.reject();
}
return Promise.resolve();
}
if (type === 'AUTH_CHECK') {
const token = storage.load('lbtoken');
if (token && token.id) {
return Promise.resolve();
} else {
storage.remove('lbtoken');
return Promise.reject({ redirectTo: noAccessPage });
}
}
return Promise.reject('Unkown method');
};
};