Handling failed API call in fetch - redux

I have the following code that makes an API call and based on HTTP response, it dispatches certain actions in my redux reducer.
The problem is that if the API call fails, it shows it in the console even though the part of the code that handles unsuccessful calls executes fine. How can I prevent that? I'm already handling unsuccessful API calls so nothing should show up in the console.
export const someApiCall = () => {
return (dispatch) => fetch('/api/somefunction', fetchOptionsGet())
.then((response) => {
if(response.ok) {
// Success. Dispatch some actions
} else {
// Failed call. Dispatch some other actions
}
})
}

There is nothing wrong with this, don't worry. The browser still display http errors in console even though you are dealing with this errors in your http library.

As #Dherik told, It is the default functionality of the browsers.
But if you are worried about the HTTP errors displayed in the console, then you can handle this to not display in the console by making changes to your API.
So, Redesign your error flow to return a status code of 2XX with an error code and message in the response body and handle it as you do now.

Related

intercept firebase-functions response (middleware)

For my Google Assistant/Dialogflow project, I am trying to intercept every response my firebase-functions endpoint is sending back to Dialogflow. I can easily intercept the request, but the response gets built within several functions (one function for every Intent), and I don't want to include an interceptor in every function.
Is it possible to have a middleware or is there a callback provided when a response is send out, sort of a global interceptor for every response?
I have found the following in the Docs: https://firebase.google.com/docs/functions/http-events#use_middleware_modules_with
However, I am unsure where this goes. Note that I am not using a custom express setup, but I am using the native implementation on firebase directly.
serialize() method is called on conversation right before the response is sent back, so what you can do is to extend the conversation object(based on the library you are using) and overwrite the serialize method to do whatever you need to do. don't forget to call the original serialize method and return the value in your new method.
Since you are using Dialog Flow with Firebase for your fulfilment, I am expecting you are also using actions-on-google package.
serialize() is a function which is called to generate the response. You can override this function and intercept the request and response. Try this code and thank me later. 😉
app.middleware((conv) => {
const serializeCopy = conv.serialize;
conv.serialize = () => {
const response = serializeCopy.call(conv);
console.log(conv.request, response);
return response;
};
});
Cloud Functions does not expose any sort of middleware or interceptors for HTTP requests or responses. You will have to build something yourself, probably with an Express app that you build yourself. You can host an Express app on Cloud Functions.
I wanted something similar to intercept all conversations back and forth for logging purposes. I ended up writing a function that I use to send a conversation. For eg:
const intercept = (conv, sentence) => {
//My Interceptor code
conv.ask(sentence)
}
Now anytime I want to send a response, I would use:
intercept(conv, "Speak this")

Throwing Meteor.Error does not reach the client

So basically, the client calls the server using a Meteor.call. The server method then does some validations and calls a web service using a meteor package. If validation fails and a meteor error is thrown, it reaches the server. If the package response has an error, it only logs on the server. I need the error to reach the client.
Here's how the code looks like.
Client
Meteor.call('callService', (err, result) => {
if(err) {
console.log(err.reason);
}
});
Server
Meteor.methods({
'callService'(){
if (!Meteor.user()) {
// Error 1
throw new Meteor.Error('insufficient-permissions', 'You need to login first');
}
// Using an meteor package to actually call the service
package.callService(apiKey, (err, response) => {
if (response.status === 'error') {
// Error 2
throw new Meteor.Error('service-error', response.message);
}
});
},
});
In the server method, if an error is thrown at Error 1, it does reach the client, but Error 2 does not. Error 2 only logs on the server.
I guess your package.callService() is async (given that it accepts a callback).
In that case, your Meteor method starts the async task, then continues its process and returns (since there is no more instructions), while the async task is still running (actually waiting for a response from your remote web service). Therefore your client Meteor call's callback receives a "no error" response.
Once your "Error 2" happens, the Meteor call is already completed, and the error can only be logged on the server.
If you want to "hang up" your method so that it waits for the result of your package.callService() to determine whether it is a success or an error and complete the Meteor call accordingly, you could try using Meteor.wrapAsync().
By the way, if you do use synchronous task to actually wait for a remote service, you would be interested in this.unblock() to allow your server to process other tasks (methods) instead of just idling.

Router.current().route.getName() is returning an error server side

Router.current().route.getName() is returning an error when I use it in a method call (server side method). I thought they say Iron-Router is supposed to work both client and server side. The error I get is
Error invoking Method 'mySeverSideMethod': Internal server error [500]
Please help.
You are half way right, the router works on both client and server. However the server-side implementation is meant for server side routes (eg. REST endpoints). There is no "state" sharing between client/server with iron:router (when invoked inside methods), so Router.current().route.getName() is going to throw you this error, because Router.current() is undefined.
Yes, iron:router can create server side routes, but that api is client only
From the docs:
Router.route('/download/:file', function () {
// NodeJS request object
var request = this.request;
// NodeJS response object
var response = this.response;
this.response.end('file download content\n');
}, {where: 'server'});
You have access to the NodeJS request object so you should be able to find what you need there, e.g. this.request.route, this.request.path.
When calling a Method, you're not going through a 'route' as defined by Iron-Router: it's a route defined by the Meteor framework. It does not care what route the client is on.
So, if you need to know from what page the client is calling the endpoint, you should pass it as a parameter to the Method.
Meteor.methods({
"myEndPoint": function(route) {
// use route here.
return //something
}
})

Meteor client side methods

I have a Meteor.method defined on the server side (in .js in /server) and I can call it just fine (with callback) from a client-side template script.
I want to do a similar thing but would like it all to be client side so I moved the method to a client script but the result comes back as 'undefined'.
Template.showDialog.events({
'click #clickme' : function() {
Meteor.call('foo', 'ola', function(error, result) {
alert('here');
alert(result);
});
}
});
Meteor.methods({
foo: function (myarg) {
return myarg+'CLI';
}
});
See the Meteor docs, where it is explained that methods on the client are stubs, not actual methods:
If you do define a stub, when a client invokes a server method it will also run its stub in parallel. On the client, the return value of a stub is ignored. Stubs are run for their side-effects: they are intended to simulate the result of what the server's method will do, but without waiting for the round trip delay. If a stub throws an exception it will be logged to the console.
Since the result is ignored, you're seeing undefined. Don't use methods on the client for this purpose. Just use a javascript function.
From the docs:
Calling methods on the client defines stub functions associated with server methods of the same name.
Basically, you need to define the method on the server side. It's also not clear why you'd want to define a method on the client and then call it on the client as well. Would a vanilla javascript function not do the job perfectly well?
Apologies if I've misunderstood what you're trying to achieve here.

How to call external rest service from angularjs?

I am trying to call an external REST service from angular using $http service.
The thing is that I am stuck on the $http.get method, because everytime I call the rest service i get an error with status = 0 and no information in the data parameter of the error callback.So far I've tried calling a local service runnig on port 5000 : $http.get('http://localhost:5000/ping') and this is supposed to return a json object with a property and a value. Another approach was calling http://api.flickr.com/services/rest/?method=flickr.test.echo&name=test in the hope of getting an answer. For both of them I get the same error: that I mentioned earlier.The call is made from an angular controller that has injected the http service.Thanks.
Have you tried:
$http({method: 'GET', url: 'someURL'}).
success(function(data, status, headers, config) {
//set view model or do something.
}).
error(function(data, status, headers, config) {
});
Make sure that you have passed the parameters correctly if there are any.
The general syntax should be like the following :
$http.get('../link/yourApplication/searchBySomeNumber?someNum='+$scope.someNum+'&asOfDate='+asOfDate+'&status=undefined')
.success(function(data, status, headers, config) {
//your code
console.log('Data return successful');
})
.error(function(data, status, headers, config) {
$scope.status = status;
alert('Info Error');
console.log('Group Info Error');
});
As $http returns a Promise, you can use the .then() method to log your results when the promise is resolved, or log an error in case anything goes wrong:
$http.get('http://localhost:5000/ping')
.then(function(returnedJson) {
console.log(returnedJson.data);
})
.catch(console.error) // or $log.error if you are using $log from Angular
Please note that the clean JSON response is obtained by logging the .data property of the returnedJson object. As it is a Promise, it contains other information that are not relevant to consume the web service.
Also note that the web service you want to consume should also be in the same domain as your Angular app, otherwise you may incur into a Cross Domain error, unless the service allows usage from external websites by exposing a Cross Domain Policy.
(Find more info here: Can someone post a well formed crossdomain.xml sample?)
If that's the case, this post should be helpful:
jQuery AJAX cross domain
Hope this helps.

Resources