passing cookie data on MeteorJS HTTP request - meteor

It already took me several hours implementing cookie on url MeteorJS. What I need to do is that, pass a cookie data n url like 'CURLOPT_COOKIE' PHP. I cant find any example code on their docs and even to forums. For now I have these functions:
/* HTTP REQUEST */
Meteor.methods({
httpRequest: function(type, uri, params){
this.unblock();
check(type, String);
check(uri, String);
check(params, Object);
try {
var result = HTTP.call(type, uri, {params: params});
return result;
} catch (e) {
// Got a network error, time-out or HTTP error in the 400 or 500 range.
return e;
}
}
});
// HTTP request with cooki
getUserDetails: function(session_id, uid){
var params = {
headers: {
Cookie: {
sessid: session_i
}
},
uid: uid
};
var response = Meteor.call('httpRequest', "POST", "http://example.com/rest/wp /alt_wp_resources/loaduser.json", params);
//res = JSON.parse(response.content);
return response;
}
// call here
Meteor.startup(function () {
// delay for 5 sec
Meteor.setTimeout(function (){
Meteor.call('getUserCredentials', 'api12345', '123qweasd', function (error, result) {
// check user authentication
var success = result.success;
console.log(result);
// user has account from lpgp site, let's save him to meteor.
if (success){
console.log('success');
var session_id = result.session_id;
//console.log(_session_id);
Meteor.call('getUserDetails', 'SESSba071091c09f79fefd66e4884dcdde50', 68558, function (error, result) {
if (!error)
console.log(result);
else
console.log(error);
});
}else
// app can't find user account from lpgp site.
console.log(error);
});
}, 5000);
});
The call is successful but, just returned a success: false.
Response:
Object {statusCode: 200, content: "{"success":false}", headers: Object, data: Object}

Meteor's HTTP module on the server side is merely a wrapper for the npm module named request. The request npm module includes support for specifying your own cookies as well as saving them into a cookie jar (just follow the link and search for 'cookie'). The default cookie jar is tough-cookie and interestingly, Meteor includes it even though I don't see any way to use it from Meteor.HTTP.
The upshot of these implementation details is that you can use request directly. I took a similar approach to wrapping request as Meteor's HTTP module but instead of the restricted sub-set of options that HTTP provides, my wrapper allows full access to all the capability of request and tough-cookie. The cool part is that you don't even need to directly add request as a dependency on your own since it's already a dependency of Meteor. The risk, of course, is that a later version of Meteor could use something besides request and your code would break.
Anyway, here is my own wrapper for request. It includes an example of JSessionID cookie support for making Jenkins API calls. Just put this into a file syncRequest.coffee under the \server folder and make sure you have added the coffeescript package (Meteor add coffeescript)... or compile my code and save it to a .js file in the \server folder.
request = Npm.require('request')
populateData = (response) ->
contentType = (response.headers["content-type"] or ";").split(";")[0]
if _.include([ "application/json", "text/javascript" ], contentType)
try
response.data = JSON.parse(response.content)
catch err
response.data = null
else
response.data = null
normalizeOptions = (uri, options, callback) ->
unless uri?
throw new Error("undefined is not a valid uri or options object.")
if (typeof options is "function") and not callback
callback = options
if options and typeof options is "object"
options.uri = uri
else if typeof uri is "string"
options = uri: uri
else
options = uri
return {options, callback}
normalizeResponse = (error, res, body) ->
response = null
unless error
response = {}
response.statusCode = res.statusCode
response.content = body
response.headers = res.headers
populateData(response)
if response.statusCode >= 400
error = makeErrorByStatus(response.statusCode, response.content)
return {error, response}
wrappedRequest = (uri, options, callback) ->
{options, callback} = normalizeOptions(uri, options, callback)
request(options, (error, res, body) ->
{error, response} = normalizeResponse(error, res, body)
callback(error, response)
)
wrappedCall = (method, uri, options, callback) ->
options.method = method
wrappedRequest(uri, options, callback)
wrappedGet = (uri, options, callback) -> wrappedCall("GET", uri, options, callback)
wrappedPost = (uri, options, callback) -> wrappedCall("POST", uri, options, callback)
wrappedPut = (uri, options, callback) -> wrappedCall("PUT", uri, options, callback)
wrappedDelete = (uri, options, callback) -> wrappedCall("DELETE", uri, options, callback)
getWithJSession = (j_username, j_password, securityCheckUri, uri, callback) ->
request = request.defaults({jar: true})
form = {j_username, j_password}
request.post({uri: securityCheckUri, form: form}, (error, response, body) ->
if error?
throw new Error(error)
else if response.statusCode isnt 302
throw new Error("Expected response code 302 (forward). Got #{response.statusCode}")
else
request.get(uri, (error, res, body) ->
{error, response} = normalizeResponse(error, res, body)
callback(error, response)
)
)
syncRequest = Meteor.wrapAsync(wrappedRequest)
syncRequest.call = Meteor.wrapAsync(wrappedCall)
syncRequest.get = Meteor.wrapAsync(wrappedGet)
syncRequest.post = Meteor.wrapAsync(wrappedPost)
syncRequest.put = Meteor.wrapAsync(wrappedPut)
syncRequest.delete = Meteor.wrapAsync(wrappedDelete)
syncRequest.del = syncRequest.delete
syncRequest.getWithJSession = Meteor.wrapAsync(getWithJSession)
syncRequest.getWithJsession = syncRequest.getWithJSession
(exports ? this).syncRequest = syncRequest

Related

How do I pass along json patch data with rest client in asp.net?

We use a rest api to get customer information. A lot of the GET request were already written by others. I was able to follow their code to create other GET request, but one of the API methods for updating a customer requires using json patch. Below I have pasted in sample code of a current GET method, a Patch method (that I don't know how to implement) and a sample function written in javascript on how to use the json-patch that came from the api creators demo documentation:
public GetCustomerResponse GetCustomerInfo(CustomerRequest request)
{
//All of this works fine the base url and token info is handled elsewhere
var restRequest = CreateRestRequest($"customer/account?id={request.id}", RestSharp.Method.GET);
var response = CreateRestClient().Execute<GetCustomerResponse>(restRequest);
if (response.StatusCode == HttpStatusCode.OK)
{
return response.Data;
}
else
{
return new GetCustomerResponse(response.Content);
}
}
public EditCustomerResponse EditCustomer(EditCustomerRequest request)
{
var restRequest = CreateRestRequest($"customer/account?id={request.id}", RestSharp.Method.PATCH);
var response = CreateRestClient().Execute<EditCustomerResponse>(restRequest);
//how do I pass along json patch data in here???
//sample json might be like:
//[{'op':'replace','path':'/FirstName','value':'John'},{'op':'replace','path':'/LastName','value':'Doe'}]
if (response.StatusCode == HttpStatusCode.OK)
{
return response.Data;
}
else
{
return new EditCustomerResponse(response.Content);
}
}
//javascript demo version that is working
function patchCustomer(acctId, patch, callback) {
var token = GetToken();
$.ajax({
method: 'PATCH',
url: BaseURI + 'customer/account?id=' + acctId,
data: JSON.stringify(patch),
timeout: 50000,
contentType: 'application/json; charset=UTF-8',
beforeSend: function (xhr) { xhr.setRequestHeader('Authorization', 'Bearer ' + token.access_token) },
}).done(function (data) {
if (typeof callback === 'function')
callback.call(data);
}).fail(function (jqXHR, textStatus, errorThrown) {
console.log("Request failed: " + textStatus);
console.error(errorThrown);
failureDisplay(jqXHR);
});
}
This was pretty simple. After viewing similar questions on stackoverflow, I initially was trying something like this:
var body = new
{
op = "replace",
path = "/FirstName",
value = "John"
};
restRequest.AddParameter("application/json-patch+json", body, ParameterType.RequestBody);
It would not work. To get it to work, I added a patchparameters class with op, path and value properties, and then added a list property of type patchparameters to my EditCustomerRequest class and used it like this:
restRequest.AddJsonBody(request.patchParams);

How do I set headers on Flutter/Dart http Request object?

I need a way to set the headers of the dart http Request object to application/JSON.
I want to build a Request object to send to my backend API. I set the body to my JSON object, but when it gets sent, it defaults the headers to text/html instead of application/json.
I have tried using the built-in method
http.post(url,dynamic body);
but unfortunately this method places the body in the parameters of the URL and I need it in the actual body of the request.
So instead I built an http Request object, and manually set the URL and body but like I said, it sets the headers to text/html.
I have read the docs for https://pub.dev/documentation/http/latest/http/Request-class.html, but unfortunately, I haven't found a way to set the headers.
postRequest(uri) async {
Uri url = Uri.tryParse("https://ptsv2.com/t/umt4a-1569012506/post");
http.Request request = new http.Request("post", url);
request.body = '{mediaItemID: 04b568fa, uri: https://www.google.com}';
var letsGo = await request.send();
print(letsGo.statusCode);
}
Much thanks for any possible solutions!
Ps. this is my first ask on Stack Overflow so I apologize if I made any errors in posting.
Solved!
postRequest(uri) async {
Uri url = Uri.tryParse("https://ptsv2.com/t/umt4a-1569012506/post");
http.Request request = new http.Request("post", url);
request.headers.clear();
request.headers.addAll({"content-type":"application/json; charset=utf-8"});
request.body = '{mediaItemID: 04b568fa, uri: https://www.google.com}';
var letsGo = await request.send();
print(letsGo.statusCode);
}
I was having some issues with the Request object default setting the encoding.
By manually specifying utf-8, the server I am contacting accepts it.
for the post or get any request you can Add Header like this -
var permAddUrl = 'your requested url';
var bodyParameters = {
'Email': email,
'MobileNo': mobileNumber,
};
await http.post(
requesturl,
headers: { 'Content-Type': 'application/x-www-form-urlencoded',
"Authorization":"$token",
},
body: bodyParameters,).then((response) {
var data = json.encode(response.body);
print(data);
setState(() {
if(response.statusCode == 200){
//var statesList = data['data'];
UtilAction.showSnackBar(context, " Details Submitted Successfully");
}
});
});

Webhook for Mailgun POST?

I am trying to store email messages as JSON (as parsed by Mailgun) in a Mongo.Collection through a Mailgun webhook. I set up an iron-router server-side route to handle the request, but this.request.body is empty. I am using Mailgun's "Send A Sample POST" to send the request, and the POST looks fine using e.g. http://requestb.in/. I was hoping that request.body would have the data, as mentioned in How do I access HTTP POST data from meteor?. What am I doing wrong?
Router.map(function () {
this.route('insertMessage', {
where: 'server',
path: '/api/insert/message',
action: function() {
var req = this.request;
var res = this.response;
console.log(req.body);
...
I'm not sure that is the right syntax. Have you tried using Router.route ?
Router.route('insertMessage',
function () {
// NodeJS request object
var request = this.request;
// NodeJS response object
var response = this.response;
console.log("========= request: =============");
console.log(request);
// EDIT: also check out this.params object
console.log("========= this.params: =============");
console.log(this.params);
// EDIT 2: close the response. oops.
return response.end();
},
{
where: 'server',
path: '/api/insert/message'
}
);
I think the issue is that Mailgun sends a multipart POST request, e.g. it sends "fields" as well as "files" (i.e. attachments) and iron-router does not set up a body parser for multipart requests. This issue is discussed here and here on iron-router's Github Issues. I found this comment particularly helpful, and now I can parse Mailgun's sample POST properly.
To get this working, in a new Meteor project, I did
$ meteor add iron:router
$ meteor add meteorhacks:npm
In a root-level packages.json I have
{
"busboy": "0.2.9"
}
which, using the meteorhacks:npm package, makes the "busboy" npm package available for use on the server via Meteor.npmRequire.
Finally, in a server/rest-api.js I have
Router.route('/restful', {where: 'server'})
.post(function () {
var msg = this.request.body;
console.log(msg);
console.log(_.keys(msg));
this.response.end('post request\n');
});
var Busboy = Meteor.npmRequire("Busboy");
Router.onBeforeAction(function (req, res, next) {
if (req.method === "POST") {
var body = {}; // Store body fields and then pass them to request.
var busboy = new Busboy({ headers: req.headers });
busboy.on("field", function(fieldname, value) {
body[fieldname] = value;
});
busboy.on("finish", function () {
// Done parsing form
req.body = body;
next();
});
req.pipe(busboy);
}
});
In this way I can ignore files (i.e., I don't have a busboy.on("file" part) and have a this.request.body available in my routes that has all the POST fields as JSON.

Setting the "Content-Type" header in HTTP.call on client side in Meteor

I'm trying to use Meteor's (v1.0) HTTP.call method to communicate with a Python-based server which accepts only application/json content type in header but I cannot set the HTTP header properly in Meteor when calling the API URL from a client side.
With a snippet like this, I get a 415 (Unsupported Media Type) error from Python server:
if (Meteor.isClient) {
Template.testing.events({
'click button': function(event, tpl) {
event.preventDefault();
var method = 'GET';
var url = 'http://localhost:6543/test';
var options = {
headers: {'Content-Type': 'application/json'}
}
HTTP.call(method, url, options, function(error, result) {
if (error) {
console.log('ERRR');
console.log(error);
} else
console.log('RESULT');
console.log(result);
});
}
});
}
However, if I call the same URL from a server side in Meteor like this:
if (Meteor.isClient) {
Template.testing.events({
'click button': function(event, tpl) {
event.preventDefault();
var method = 'GET';
var url = 'http://localhost:6543/test';
var options = {
headers: {'Content-Type': 'application/json'}
}
Meteor.call('APICall', method, url, options, function (error, result) {
if (error) {
console.log('CLIENT ERRR');
console.log(error);
} else {
console.log('CLIENT RESULT');
console.log(result);
}
});
}
});
}
if (Meteor.isServer) {
Meteor.methods({
APICall: function (method, url, options) {
HTTP.call(method, url, options, function(error, result) {
if (error) {
console.log('SERVER ERRR');
console.log(error);
} else
console.log('SERVER RESULT');
console.log(result);
});
}
});
}
I get a proper response from the server.
On Python side I enabled CORS origins for all possible requests (e.g. cors_origins=('*')).
So... Is is possible to set header on client-side or should I always call this service from server-side?
I've never had any success on the client-side either, but it is supposed to. Check out the HTTP.call client part of the meteor HTTP package:
https://github.com/meteor/meteor/blob/devel/packages/http/httpcall_client.js
Mostly it uses the browser XHR object on the client-side which can lead to a host of problems, like incompatibilities and stuff. You can even see an issue referenced on one of the code comments (around line 136)
And when you check out the server implementation you can see it uses the request library (from connect), which, in my book, is very reliable and you can generate uniform results across all users (and not dance around browser differences).
My choice and recommendation for you is obviously going to be server-side calls. Not just because it works and it's reliable, it's also 'safer' on your part as you don't have to expose more inner workings of your system to the client/end-user. Who knows? maybe you have sensitive data on your API run on your Python-based server.

Iron Router Server Side Routing callback doesn't work

I am newer for IronRouter, why readFile callback executed the response are send to client.
Router.map(
()->
this.route 'readFile',
path: '/readFile'
where: 'server'
method: 'GET'
action: ()->
self = this
fs.readFile '/tmp/a.txt', (err, data)->
if err
throw err
console.log(data.toString())
self.response.writeHead(200, {'Content-Type': 'text/plain'})
self.response.end(data)
console.log('response ...')
)
http.js:733
W2049-12:04:26.781(8)? (STDERR) throw new Error('Can\'t render headers after they are sent to the client.'
W2049-12:04:26.781(8)? (STDERR) ^
W2049-12:04:26.782(8)? (STDERR) Error: Can't render headers after they are sent to the client.
But, I use express , like this is work well.
exports.index = function(req, res){
fs.readFile('/tmp/a.txt', function (err, data) {
if (err) throw err;
console.log(data.toString());
res.send(200, data.toString());
});
console.log('response ...');
};
thanks #ChristianF #Tarang Use Meteor._wrapAsync or Future all work well . when I use self define function replace fs.readFile. It take throw ex . I Doubt My defined function has error. As follows:
#getAccounts = (callback) ->
query = "SELECT Id, Name, AccountNumber FROM Account"
queryBySoql(query, (err, result)->
if err
return console.error(err)
return callback(result)
)
I invoked link this:
# using Meteor
#data = Meteor._wrapAsync(getAccounts)()
#using Future
waiter = Future.wrap(getAccounts)()
data = waiter.wait()
this.response.writeHead 200, {'Content-Type': 'text/plain'}
this.response.end JSON.stringify(data)
thanks all.
Just today I struggled with this very issue. The answer, it seems to me, is that meteor (or at least the iron router) doesn't handle async calls the way you'd expect. The solution is to wrap the async call into a fiber, which is the mechanism meteor uses to keep the programming synchronous.
In your case try this (sorry, I don't know coffeescript very well):
var Future = Npm.require('fibers/future');
...
var waiter = Future.wrap(fs.readFile);
var data = waiter('/tmp/a.txt').wait();
response.writeHead(200, {'Content-Type': 'text/plain'})
response.end(data)
EDIT Addressing the addition to the question.
Functions wrapped in a future need to have a callback as their last argument that has the (err, result) signature. Try this:
#getAccounts = (callback) ->
query = "SELECT Id, Name, AccountNumber FROM Account"
queryBySoql(query, (err, result)->
if err
return console.error(err)
return callback(err, result)
)
You could wrap up your read file request's callback into the same fiber. It will not block other requests & comes out quite clean.
readFile = Meteor_wrapAsync(fs.readFile.bind(fs))
data = readFile("/tmp/a.txt")
console.log data
#response.writeHead(200, {'Content-Type': 'text/plain'})
#response.end data
return

Resources