Throwing Meteor.Error does not reach the client - meteor

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.

Related

502 bad gateway when async request hits 2 min

The issue described below doesn't happen on local development, only once I have deployed everything to test environment, which is hosted on Azure Web App.
When calling an API endpoint from Angular (where I use Observer and subscribe on the request), the request is processed and may sometimes take longer than 2 minutes to be processed. When the request hits 2 minutes, I instantly get a 502 bad gateway, while the async process continues until finished.
In the request processing I do a couple of remote powershell script executions, I made sure that both my powershell methods run asynchronously, and made sure that the API endpoint is async. In my angular frontend from where I do the request, I use observer and subscribe on the request being made.
My next step was wanting to make some sort of request that just starts the process, and then somehow be able to keep requesting until I get a response that the response has finished, to avoid the 502 error, but I don't know where or how to start, but I don't know if this approach could even work for sure.
Backend is set up using C#, .NET Core 2.2. Frontend is Angular (7?).
I want to get the expected response instead of hitting 502 Bad Gateway everytime processing hits 2 minutes.
Code:
First I call
this.objectService.processObjectsForMerge(request).subscribe(res => {});
Which, from the service, prepares following request
processObjectsForMerge(req: ProcessObjectsForMergeRequest): Observable<ProcessObjectsForMergeResponse>{
return this.http.post<ProcessObjectsForMergeResponse>(this.API_URL + '/Object/ProcessObjectsForMerge',req, {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.auth.getAccessToken()
})
});
}
And is received in the following endpoint
[HttpPost]
[Route("ProcessObjectsForMerge/")]
public async Task<IActionResult> ProcessObjectsForMerge([FromBody] ProcessMergeRequestModel request)
{
if (request == null || string.IsNullOrEmpty(request.VersionNumber) || string.IsNullOrEmpty(request.CuLevel)) return BadRequest("Failed to validate data");
var permissionGranted = DoesUserHavePermissionForRequest(request.ShortGuid);
if (!permissionGranted) return BadRequest();
var isSuccessful = await new ProcessObjectsForMergeService().Process(request);
var message = !isSuccessful ? "Failed to process objects for merge." : "Successfully processed the objects for merge.";
return Ok(new {message, log});
}
Update:
I have found a temporary solution, in web.config of the API I was able to increase the timeout time.
I feel this is bad practice though, so gonna implement a message queue (using rabbitMQ probably) to execute my initial idea on how to solve it and see if it works out the way I expect.

Handling failed API call in fetch

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.

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
}
})

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.

Signalr Exception in Browser

I am trying to create a chat application but after successful build of the web app its catching an exception when i am passing the paramaters for chat.The exception is
0x800a139e - JavaScript runtime error: SignalR: Connection must be
started before data can be sent. Call .start() before .send()
The screen shots are attached here
You need to make sure you don't try invoking server-side hub methods until start is done. Ex:
$.connection.hub.start().done(function(){
$('#submit').click(function () {
$.connection.chat.server.addMessage($('#msg').val());
})
});
Notice that the event handler isn't wired up until the connection is established.

Resources