Trying to send a POST request using the body of a GET request - node.js

I am currently working on a project to create API routes for two third party applications to communicate with one another using NodeJS/express. The issue I am having is that I am trying to have third party application A (3PA) get a list of timeslots from a calendar in third party application B (3PB) and then send a message to a user in 3PB containing those timeslots.
The route looks like this:
router.post('/request_appointment_times', function(req, res){
**google sheets api logic**
async function gsrun(client){
**getting data from google sheet**
var request = require('request');
require('request-debug')(request);
var options = {
'method': 'GET',
'url': '3PB API URL',
'headers': {
'accept' : '*/*',
'Authorization': 'Bearer ' + apiKey,
'content-type' : 'application/json'
},
};
request(options, function (error, response) {
if (error) throw new Error(error);
//console.log(response.body);
else
res.json({"message": "It Works!",});
slotsList = new String(response.body.slots);
slotsListArr = slotsList.split(',');
var rnd = Math.random(0, slotsListArr.length);
ssn.providedSlots = slotsListArr[rnd];
ssn.providedSlots2 = slotsListArr[rnd];
if (ssn.providedSlots == ssn.providedSlots2) {
ssn.providedSlots2 = ssn.slotsListArr[rnd]
}
if (ssn.providedSlots == ssn.providedSlots2) {
ssn.providedSlots2 = ssn.slotsListArr[rnd]
}
console.log(providedSlots);
console.log(providedSlots2);
});
}
});
Currently, I can't even get the providedSlots to print as the request function won't communicate with the console. My question is, is it possible/how can I do a POST to 3PB using the response body from my GET request within this same route. I apologize if I worded this poorly or didn't provide enough information. Any help is much appreciated and if I need to provide additional information let me know!

By the looks of this you are defining gsrun in your route handler but aren't actually invoking it. Should be more like this:
function gsrun() { /* logic */ }
router.post('/request_appointment_times', function(req, res){
gsrun();
});

Related

node.js how to send multipart form data in post request

I am attempting to get data in the form of an image sent from elsewhere using multipartform, however when trying to understand this via the great sanctuary(stack overflow) there are missing elements I don't quite understand.
const options = {
method: "POST",
url: "https://api.LINK.com/file",
port: 443,
headers: {
"Authorization": "Basic " + auth,
"Content-Type": "multipart/form-data"
},
formData : {
"image" : fs.createReadStream("./images/scr1.png")
}
};
request(options, function (err, res, body) {
if(err) console.log(err);
console.log(body);
});
2 questions:
what is the variable auth, what do I initialize it to/where/how do I declare it
what is the url "api.LINK.com", is this just the site url where this code is on
After your comments I think I may be doing this wrong. The goal is to send data(an image) from somewhere else(like another website) to this node app, then the nodeapp uses the image and sends something back.
So that I would be the one creating the API endpoint

Need to get project/issues from JIRA using JIRA REST API with NodeJS

I am building a NodeJS application from where I want to get project/issues from JIRA using REST APIs provided by JIRA. My jira is running on some server ('http://example.com:8080/secure/Dashboard.jspa') and I am able to use REST APIs from POSTMAN using BASIC AUTH to get all kind of data but when I tried to log in to JIRA using REST APIs and NodeJS, I am getting some response but I am not able to understand it how I am going to use that information to call other APIs.
What I am doing is, I am passing username and password as a command-line args then I am sending those creds to login to JIRA. Then I am going to use the 'node-fetch' package to get information from REST APIs.
Below is my code:
const fetch = require("node-fetch");
const yargs = require("yargs");
var JiraClient = require("jira-connector");
var request = require("request");
const jiraBaseUrl = "http://example.com:8080/secure/Dashboard.jspa";
const loginUrl = "auth/1/session";
const username = yargs.argv.u;
const password = yargs.argv.p;
const projectName = yargs.argv.n;
var headers = {
"Content-Type": "application/json"
};
var options = {
url: "http://example.com:8080/rest/api/2/issue/createmeta",
headers: headers,
auth: {
user: username,
pass: password
}
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
}
request(options, callback);
Can somebody please tell me what I am doing wrong or what do I need to do with the data I am getting in order to use other APIs like ('http://example.com:8080/rest/api/2/issue/10008')? Or am I doing something wrong to login?
I have read the documentation on the JIRA website but was not able to understand correctly.
If you look at the Jira Rest API documentation, rest/api/2/issue/createmeta is the end point for Get create issue metadata. It "returns details of projects, issue types within projects, and, when requested, the create screen fields for each issue type for the user. " This data is supposed to be huge since it returns the details of all projects, and all issue types within projects.
If you want to use other API just change the url to the appropriate url with the correct endpoints (documentation) and follow the documentation on what to send as the body data.
Here is one example of getting the details of one issue:
Put the issueIdOrKey you want to get in the brackets
var options = {
method: 'GET',
url: 'http://example.com:8080/rest/api/latest/issue/{issueIdOrKey}',
auth: { username: username, password: password },
headers: {
'Accept': 'application/json'
}
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(
'Response: ' + response.statusCode + ' ' + response.statusMessage
);
console.log(body); //this would log all the info (in json) of the issue
// you can use a online json parser to look at this information in a formatted way
});

Mailchimp API v3.0 add email to list via NodeJS http

I'm using NodeJS to call the new MailChimp 3.0 API in order to add an email to a list. While I can get it working via POSTman, I'm having a hard time with Node's http:
var http = require('http');
var subscriber = JSON.stringify({
"email_address": "test#test.com",
"status": "subscribed",
"merge_fields": {
"FNAME": "Tester",
"LNAME": "Testerson"
}
});
var options = {
host: 'https://us11.api.mailchimp.com',
path: '/3.0/lists/<myListID>/members',
method: 'POST',
headers: {
'Authorization': 'randomUser myApiKey',
'Content-Type': 'application/json',
'Content-Length': subscriber.length
}
}
var hreq = http.request(options, function (hres) {
console.log('STATUS CODE: ' + hres.statusCode);
console.log('HEADERS: ' + JSON.stringify(hres.headers));
hres.setEncoding('utf8');
hres.on('data', function (chunk) {
console.log('\n\n===========CHUNK===============')
console.log(chunk);
res.send(chunk);
});
hres.on('end', function(res) {
console.log('\n\n=========RESPONSE END===============');
});
hres.on('error', function (e) {
console.log('ERROR: ' + e.message);
});
});
hreq.write(subscriber);
hreq.end();
Rather than getting even some sort of JSON error from Mailchimp, however, I'm getting HTML:
400 Bad Request
400 Bad Request
nginx
Is it clear at all what I"m doing wrong here? It seems pretty simple, yet nothing I've tried seems to work.
A few additional thoughts:
While http's options have an "auth" property, I'm using the headers instead to ensure the authorization is sent without the encoding (as mentioned here). Still, I've also tried with the "auth" property, and I get the same result.
I'm actually making this call from inside an ExpressJS API (my client calls the Express API, that calls the above code - I've edited all that out of this example for simplicity). That's why my variables are "hres" and "hreq", to distinguish them from the "res" and "req" in Express. Is there any reason that could be the issue?
As mentioned above, I am able to get successful results when using POSTman, so I at least know my host, path, list ID, and API key are correct.
It turns out this had a very simple solution: the "host" property of the options object needed to have only the domain name. IE, remove the "https://" protocol:
var options = {
host: 'us11.api.mailchimp.com',
path: '/3.0/lists/<myListID>/members',
method: 'POST',
headers: {
'Authorization': 'randomUser myApiKey',
'Content-Type': 'application/json',
'Content-Length': subscriber.length
}
}
Try this , its working fine for Me.
var request = require('request');
function mailchimpAddListCall(email, cb){
var subscriber = JSON.stringify({
"email_address": email,
"status": "subscribed"
});
request({
method: 'POST',
url: 'https://us13.api.mailchimp.com/3.0/lists/<Your list id>/members',
body: subscriber,
headers:
{
Authorization: 'apikey <your Mailchimp API key>',
'Content-Type': 'application/json'
}
},
function(error, response, body){
if(error) {
cb(err, null)
} else {
var bodyObj = JSON.parse(body);
console.log(bodyObj.status);
if(bodyObj.status === 400){
cb(bodyObj.detail, null);
}
var bodyObj = JSON.parse(body);
cb(null, bodyObj.email_address +" added to list.");
}
});
}
request is a node module, that you'll need to install into your package.json. npm install --save request
You can use the auth properties just fine with API v3, but if you're getting a 400, that's not the problem. The body of the 400 Error should provide more detailed information, but one thing that jumps out immediately: MailChimp doesn't allow fake or fake-looking emails to be added to lists (like test#test.com), so I'd try a real address and see if that works for you.

Why does my sailsjs service return "undefined" to the calling controller action?

I have to POST to an API that someone else has developed in order to obtain an authorization code, and as I have to do it in several different contexts I thought I'd move the code for handling the POST and getting the response to a service.
The frustrating thing at the moment is that I seem to be getting back the value that I want from the API, but can't return it from the server to the calling sails controller.
Here's the service source code:
module.exports = {
getVerifyCode: function(uuid, ip_addr) {
console.log (uuid);
console.log (ip_addr);
var http = require('http'),
querystring = require('querystring'),
// data to send
send_data = querystring.stringify({
uuid : uuid,
ip_addr : ip_addr
}),
// options for posting to api
options = {
host: sails.config.api.host,
port: sails.config.api.port,
path: '/verifyCode/update',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(send_data)
}
},
json_output = "",
// post request
post_req = http.request(options, function(post_res) {
post_res.on('data', function(chunk) {
json_output += chunk;
});
post_res.on('end', function() {
var json_data = JSON.parse(json_output),
verify_code = json_data.verify_code;
console.log("code="+verify_code);
return ('vc='+verify_code);
});
});
post_req.write(send_data);
post_req.end();
}
}
And here's two relevant lines from my controller action:
var vc = verify.getVerifyCode(req.session.uuid, req.connection.remoteAddress);
console.log('vc='+vc);
The weird thing is that the controller console log gets written before the service one does:
vc=undefined
code=YoAr3ofWRIFGpoi4cRRehP3eH+MHYo3EogvDNcrNDTc=
Any ideas? I have a much simpler service running (just some string manipulation stuff); I have a feeling the issue here relates to the asynchronous nature of the API request and response.
Jasper, your correct in your assumption that it is the " asynchronous nature of the API request and response".
When you execute your http call in your verify service, node makes that call and them moves on to the rest of the code console.log('vc='+vc); and does not wait for the http call to finish.
I'm not sure what your end result should be but you can rewrite your controller / service to include the callback (this is just one options, there are many ways to do this of course, other people should suggest others)
verify.js
getVerifyCode: function(uuid, ip_addr, cb) {
// Bunch of stuff
return post_req = http.request(options, cb(post_res});
}
then in your controller
controller.js
verify.getVerifyCode(req.session.uuid, req.connection.remoteAddress, function(resps){
// code in here to execute when http call is finished
})

Podio API addItem call

I'm trying to implement https://developers.podio.com/doc/items/add-new-item-22362 Podio API addItem call in a nodejs module. Here is the code:
var _makeRequest = function(type, url, params, cb) {
var headers = {};
if(_isAuthenticated) {
headers.Authorization = 'OAuth2 ' + _access_token ;
}
console.log(url,params);
_request({method: type, url: url, json: true, form: params, headers: headers},function (error, response, body) {
if(!error && response.statusCode == 200) {
cb.call(this,body);
} else {
console.log('Error occured while launching a request to Podio: ' + error + '; body: ' + JSON.stringify (body));
}
});
}
exports.addItem = function(app_id, field_values, cb) {
_makeRequest('POST', _baseUrl + "/item/app/" + app_id + '/',{fields: {'title': 'fgdsfgdsf'}},function(response) {
cb.call(this,response);
});
It returns the following error:
{"error_propagate":false,"error_parameters":{},"error_detail":null,"error_description":"No matching operation could be found. No body was given.","error":"not_found"}
Only "title" attribute is required in the app - I checked that in Podio GUI. I also tried to remove trailing slash from the url where I post to, then a similar error occurs, but with the URL not found message in the error description.
I'm going to setup a proxy to catch a raw request, but maybe someone just sees the error in the code?
Any help is appreciated.
Nevermind on this, I found a solution. The thing is that addItem call was my first "real"-API method implementation with JSON parameters in the body. The former calls were authentication and getApp which is GET and doesn't have any parameters.
The problem is that Podio supports POST key-value pairs for authentication, but doesn't support this for all the calls, and I was trying to utilize single _makeRequest() method for all the calls, both auth and real-API ones.
Looks like I need to implement one for auth and one for all API calls.
Anyway, if someone needs a working proof of concept for addItem call on node, here it is (assuming you've got an auth token beforehand)
_request({method: 'POST', url: "https://api.podio.com/item/app/" + app_id + '/', headers: headers, body: JSON.stringify({fields: {'title': 'gdfgdsfgds'}})},function(error, response, body) {
console.log(body);
});
You should set content-type to application/json
send the body as stringfied json.
const getHeaders = async () => {
const headers = {
Accept: 'application/json',
'Content-Type': 'application/json; charset=utf-8',
};
const token = "YOUR APP TOKEN HERE";
headers.Authorization = `Bearer ${token}`;
return headers;
}
const createItem = async (data) => {
const uri = `https://api.podio.com/item/app/${APP_ID}/`;
const payload = {
fields: {
[data.FIELD_ID]: [data.FIELD_VALUE],
},
};
const response = await fetch(uri, {
method: 'POST',
headers: await getHeaders(),
body: JSON.stringify(payload),
});
const newItem = await response.json();
return newItem;
}

Resources