Looking for sample code for async 3rd party REST service calls


#1

Hi, I have a question about asynchroneous calls to 3rd party APIs with Meteor. This is what I’m trying to achieve:

  1. The user enters some information in the client (actually, it’s a Cordova app, but I don’t think this matters in this case; I’m sending the data from Cordova to the web client via handleOpenURL).

  2. The information the user enters shall trigger a request to a 3rd party database via a REST API. This data retrieval should happen on the server side (in order to not disclose the API keys to the
    client).

  3. After the REST API call retrieved a result, the result data should be further enriched by the server. The server will mirror the (enriched) data in its own database, so further clients will be served with this enriched data without calling the REST API again (for the same input data).

  4. Also, the server shall perform some additional calulations to prepare result data in a proper way for the client. Then, this polished result shall be returned back to the client.

  5. The client template should display the results using a Spacebars template.

In the Meteor docs I can only find “simpler” scenarios where the data is already available in the MongoDB and the client can “just” subscribe to it. But I cannot find a sample that also involves a more complex roundtrip involving 3rd party API calls.

I’m especially wondering how I can manage the asynchroneous call and how to handle the time delays caused by them in a proper way. I guess this is a case for .wrapAsync(), but I’m not quite sure, since Meteor also seems to have some API’s which hide this complexity by “imitating” synchroneous calls. I’ve read a lot of forum threads and docs I’ve found on stackoverflow, but these tend to deal with only a “part of the story” (i.e. how to call .wrapAsync() properly), they did not give me the “big picture” (i.e. do I even need .wrapAsync(), or is there a more elegant solution to my problem like the http methods provided by core?) - And how exactly to set-up the communication between client, server and the API call in a kind of “best practice” way.

BTW: I’m using FlowRouter for the routing tasks and would like to display a kind of “Loading” spinner on the client until the roundtrip has succeeded. Any hints / links to sample code would be appreciated!

Regards, Tom.


#2

This may help give food for thought. There is a small server-side app which collects data on a timer from a couple of SOAP endpoints and updates a MongoDB database. Collections (with transforms) are used to control client-side reactivity for newly collected data.

Most of the server code is concerned with decoding the XML data into something more useable. Most of the client code is concerned with setting up gauges and a Highcharts dynamic graph, but it’s still small enough to comprehend (I hope :wink:).


#3

@robfallows: Thanks a lot for your quick reply and repo link. Will dive into this sample now!


#4

Hi Rob,

I’ve now looked at your sample code, thanks again for providing it.

Although I cannot get the app to run (no gauge displays), I think I got how it should work.

Yet, this sample is not exactly what I was looking for. In your sample, all data is being fetched on startup, and the client “just” waits until the data is available.

In my use-case, data retrieval would be fetched on-demand, based on input from the client. I don’t think the synchroneous call to HTTP.get() - without any means of dealing with asynchronity - would be a good choice in my case.

But your sample was still a good starting point since it showed me at least a part of how to put my puzzle pieces together :smile:


#5

Yes, it didn’t quite fit your intended use case, but it’s not difficult to consider a refactor in which the client makes a Meteor.call to a server-side method which then makes the HTTP request on behalf of the client. The processing and synchronisation of results would continue as before.

If you are interested in making multiple, parallel, asynchronous requests which all come together, you could look at this (note it uses the deprecated Meteor.http syntax - replace with HTTP).


#6

I have an application that coordinates with a Java backend. All of the “update” actions a user takes are handled in just this way. The user initiates the update which calls through HTTP into the java web app which does some processing of the request based on business rules that I don’t have to deal with this way and then spits back to me the result of that. I then (in this case) spew those results into Mongo so that everyone who is looking at the same screen can see the updates that user does.

In another application, I have a Java backend feeding me data whenever there is an update via DDP. That way my cache is always up to date and users see the results immediately. Of course, if you don’t have any influence on the other application DDP isn’t an option.

Concept of server side code:

Meteor.methods({status: function(id, newStatus, token){
  HTTP.post('http://<pathToTomcat>/status",{
    headers: {
      'content-type':'application/json',
      'authorization':token
    },
    data: {
      newStatus:newStatus,
      user: id
    }
  },{
    npmRequestOptions: {
      timeout: 5000 //5 second timeout
    }
  });
});

#7

@lassombra: Thanks for your reply. I have a question on that: Is it really “safe” to perform an operation like HTTP.post() in a synchroneous way, like you did in your example? I would have expected that I have to wrap it in an async function to not block the server if the request takes longer. Or does HTTP.post() automatically care for setting up another fiber if called?


#8

Sorry, I should have been more clear about this.

Meteor (and more generally nodejs) is chock full of async operations. The reason for that is that instead of being threaded like say Java or .Net or even PHP, it is a single thread. It operates the same as javascript client side which is also inherently async and event driven. These properties are very helpful.

In this case, Meteor’s HTTP module automatically wraps async calls. In fact, straight from github (only showing the relevant parts:

HTTP.call = Meteor.wrapAsync(_call)

HTTP.get = function (/* varargs */) {
  return HTTP.call.apply(this, ["GET"].concat(_.toArray(arguments)));
};

HTTP.post = function (/* varargs */) {
  return HTTP.call.apply(this, ["POST"].concat(_.toArray(arguments)));
};

HTTP.put = function (/* varargs */) {
  return HTTP.call.apply(this, ["PUT"].concat(_.toArray(arguments)));
};

HTTP.del = function (/* varargs */) {
  return HTTP.call.apply(this, ["DELETE"].concat(_.toArray(arguments)));
};

So with all of that the simple answer is: yes, synchronous is safe because it will never actually block. The timeout I showed above is handy as otherwise it uses the system’s default timeout which in linux is apparently something like 38 seconds? I prefer to have more control over timeouts.


#9

Thanks a lot for the additional comments. Awesome to know that HTTP.call() is already wrapping the async for me. That’s great and makes things a lot easier.


#10

Hi @waldgeist @robfallows
how to pass basic authentication username,password values to POST request


#11

Have you tried this syntax: http://username:password@restofurl.com? This is the standard way of providing username and password to basic authentication.


#12

How can I give :

I tried in rest call HTTP.call(“POST”, {}, function)
auth: {
“abc”:“xyz”
}
: giving runtime error (httpcall_client.js:62 Uncaught TypeError: options.auth.indexOf is not a function)
and
auth: {
“abc:xyz”
}
:giving syntax error


#13

Thank you,
Issue solved.
Need to give in below format in HTTP.call() options attribute.

auth: “abc:xyz”

Can you help me how to resolve
"No Access-Control-Allow-Origin header is present on the requested resource" error.