Trouble returning API response leveraging fetch - javascript

Been working on a script to execute in Google Apps Scripts to pull some data from an external API and post that information into a Google Sheet. I have a script that works client side (running from the console in chrome) that is able to leverage promises and return HTTP responses correctly to execute more code on.
However, in Apps Scripts I cannot figure out how to return a native JSON object representation from the API. In normal JS, I would return the .json() method of the response and would be good to go. Since Apps Script is essentially executing a .gs file they have different classes and methods that are not specific to JS. This help doc https://developers.google.com/apps-script/guides/services/external provides the below example for working with JSON
var json = response.getContentText();
var data = JSON.parse(json);
Logger.log(data.title);
If I try to leverage that getContextText() method by itself I get a TypeError: Cannot read property '0' of undefined error. If I combine it with JSON.parse like return JSON.parse(response.getContentText()); I get a SyntaxError: Unexpected token M in JSON at position 0. Am I missing something wildly obvious? Any help would be greatly appreciated! Additionally, happy to provide more specifics from my script as well.
EDIT
Below is a snippet of script that works client side.
async function postData(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': "Basic" + ' ' + gongCreds,
'Accept': "*/*",
'Connection': "keep-alive",
'Content-Type': "application/json"
},
body: gongRequestBody,
});
return response.json();
}
Here is the returned promise object data that I want to leverage for future execution
[[PromiseResult]]: Object
records: {totalRecords: 1, currentPageSize: 1, currentPageNumber: 0}
requestId: "6w83fpcbo5ka2evast7"
usersDetailedActivities: Array(1)
0:
userDailyActivityStats: Array(1)
0:
callsAsHost: []
callsAttended: (6) ["432806286570218902", "1825323793748204011", "3193437184015561879", "4172384470445855263", "5128172192322468435", "5808052479141116583"]
callsCommentsGiven: []
callsCommentsReceived: []
callsGaveFeedback: []
callsMarkedAsFeedbackGiven: []
callsMarkedAsFeedbackReceived: []
callsReceivedFeedback: []
callsRequestedFeedback: []
callsScorecardsFilled: []
callsScorecardsReceived: []
callsSharedExternally: []
callsSharedInternally: []
fromDate: "2021-01-20T05:00:00Z"
othersCallsListenedTo: (2) ["3401282086024720458", "8098199458721511977"]

When your following Javascript is converted to Google Apps Script,
async function postData(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': "Basic" + ' ' + gongCreds,
'Accept': "*/*",
'Connection': "keep-alive",
'Content-Type': "application/json"
},
body: gongRequestBody,
});
return response.json();
}
it becomes as follows.
const response = UrlFetchApp.fetch(url, {
method: 'POST',
headers: {
'Authorization': "Basic" + ' ' + gongCreds,
'Accept': "*/*",
'Connection': "keep-alive",
},
muteHttpExceptions: true,
contentType: "application/json",
payload: gongRequestBody,
});
console.log(response.getContentText())
// I think that if above request works and the returned value is the correct value you expected, you can use console.log(JSON.parse(response.getContentText()).title)
But, there are several important points.
From your script, I cannot see the value of gongRequestBody. When 'Content-Type': "application/json" is used, JSON.stringify() is required to be used for the JSON object. So if gongRequestBody is the JSON object, please convert it to the string using JSON.stringify().
From your question, I cannot see your script for requesting to the URL. So I cannot point out the modification points of your script even when your script has the modification points.
I asked to show the sample value of response.getContentText() in your Google Apps Script. But unfortunately, I cannot find the sample value of it. So when you use console.log(JSON.parse(response.getContentText()).title) to the above sample script of Google Apps Script and an error occurs, can you provide the sample value of console.log(response.getContentText())? By this, I would like to confirm it.
Note:
In this sample script, it supposes that your Javascript works and the variables of gongCreds, gongCreds and gongRequestBody are the valid values for requesting to your URL. Please be careful this. So when above sample script didn't work as you expected, can you provide the sample value of console.log(response.getContentText())? By this, I would like to confirm your situation.
Reference:
fetch(url, params)

Related

No response from API

I have created an API call in excel to get data from a Wix database.
The call:
Dim http As Object, JSON As Object
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", "https://username.wixsite.com/mysite/_functions/Functionname", False
http.setRequestHeader "Authorization", "myauthkey"
http.Send
MsgBox (http.responseText)
The javascript http backend file on Wix:
import { ok, notFound, serverError } from 'wix-http-functions';
import wixData from 'wixdata';
export function get_Wixdata() {
let options = {
"headers": {
"content-type": "application/json"
}
};
return wixData.query("wix data collection name")
.find()
.then(results => {
if (results.items.length > 0) {
options.body ={
"items": results.items
}
return ok(options);
}
})
}
I tested the call (without authorisation) on JSON place holder and it worked fine.
Just trying to debug what's happening as I am getting "" as a response.
Even if I enter the wrong API key I still get "", even a wrong url it's still a "" response.
I take it I am clearly way off the mark with what I am trying to do..
Did you tried put both headers in your request, like the following:
let headers = new Headers({
'Content-Type': 'application/json',
'Authorization': '....'
});
The issue was with the VBA call, the header was not needed.
Dim https As Object, JSON As Object
Set https = CreateObject("MSXML2.XMLHTTP")
With CreateObject("Microsoft.XMLHTTP")
.Open "GET", "end point url", False
.send
response = .responseText
End With

Adding multiple request headers in test script (Postman)

I am running a for loop with multiple requests in order to extract information from our API. The only problem is, I get console errors saying token and client headers are required to view response. I can only add one header in postman though in the test script. Is there something I'm not seeing?
for (k = 0; k < id.length; k++) {
const emailRequest = {
url: "" + id[k] + "/products",
method: "GET",
header: [{
'key': "X-Auth-Token",
"value": "",
}
],
body:{
mode: 'application/json',
raw: JSON.stringify({
client_id: '',
})
}
};
}
The header is not an Array. It is passed as an object with one name-value pair per header. The header should be given as below
header: {
'X-AUTH-TOKEN': 'mytoken',
'Content-Type': 'application/json'
}
Why don't you use multiple headers and variable to achieve this - then you can manipulate variables with scripts as you like.
Image
Useful Links:
https://learning.getpostman.com/docs/postman/environments_and_globals/variables/
I have something which can help you:
my requirements:
key value
"X-Auth-Token" "38432904832904"
"Content-Type" "application/json"
Solution: add this script in Pre-request script
pm.request.headers.add({
key:"X-Auth-Token",
value:"38432904832904"
});
pm.request.headers.add({
key:"Content-Type",
value
})

When sending POST request to backend API via fetch(), the body has only key and no value

When I'm sending a POST request to my backend express server, the req.body contains only the key part where the entire body is the key and the value part is empty
This is the frontend fetch request
let data = {
videoUrl: "dummy text"
}
fetch("/api/getinfo", {
method:"POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
},
body: JSON.stringify(data)
})
This is how I handle it in backend (NOTE: I'm using body-parser)
app.post("/api/getinfo", (req,res) => {
console.log(req.body);
}
I expect the output to be
'{ "videoUrl":"dummy text" }'
But what I get is
{ '{"videoUrl":"dummy text"}': '' }
The entire requests body is the key, and the value is empty.
What am I doing wrong?
You are using the wrong Content-Type to send json
Try
"Content-Type": "application/json;charset=UTF-8"
I noticed an issue in your header;
fetch("/api/getinfo", {
method:"POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" //this very line
},
I guess what you meant is
fetch("/api/getinfo", {
method:"POST",
headers: {
'Content-type': 'application/json; charset=utf-8'
},
Note: Your header denotes what the content is encoded in. It is not necessarily possible to deduce the type of the content from the content itself, i.e. you can't necessarily just look at the content and know what to do with it. So you need to be sure of what you're writing in your header else you will end up with an error.
I will suggest you get to read more about What does “Content-type: application/json; charset=utf-8” really mean?
The problem is that you are stringifying the data:
body: JSON.stringify(data)
should be
body: data
That should fix it

How to parse my json object

My program sends some JSON to my API (which works fine):
var result = await fetch('http://localhost:58553/api/Foo', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(this.state)
});
var contentResult = await result.text();
var contentResultObject = JSON.parse(contentResult);
console.log(contentResult);
console.log(contentResultObject);
console.log(contentResultObject.code);
The output of console.log:
"{\"code\":1,\"probability\":0.985368549823761}"
{"code":1,"probability":0.985368549823761}
undefined
Any reason why this isn't working? My API simply returns a string:
return JsonConvert.SerializeObject(result);
Your output of contentResult looks like your payload has been double encoded. You can verify this by logging typeof contentResultObject, which should show string.
To fix the problem you will ideally address the double encoding issue on the server, but if you can't you can simply apply JSON.parse twice.

Parsing AngularJS http.post data on server side with express & body-parser

I just recently started learning MEAN stack so forgive me if this seems like a really dumb question. My problem is as follows:
On the client side (controller.js) I have,
$http({
method : 'POST',
url : '/root',
// set the headers so angular passing info as form data (not request payload)
headers : { 'Content-Type': 'application/x-www-form-urlencoded' },
data : {
type:'root',
username:$scope.rEmail,
password:$scope.rPassword
}
})
On the server side I have,
app.post('/root', function(req, res) {
console.log(req.body);
console.log(req.body.username);
});
My console log shows:
17 Nov 21:39:04 - [nodemon] starting `node server/server.js`
{ '{"type":"root","username":"testUserName","password":"testPassword"}': '' }
undefined
I would imagine req.body.username to give me testUserName but I get undefined. The JSON format I am getting is slightly weird. Can anyone help me out this one? I did some reading and tried using body-parser and went through angular js $http.post documentation but didn't find anything that would help me out.
I imagine the problem is at:
{ '{"type":"root","username":"testUserName","password":"testPassword"}': '' }
but I cant seem to figure out how I would pass the data from $http.post in my angular controller so that I would just get my request in identifier:value format.
Nevermind, I figured it out. Seems like I needed a break from coding.
headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
to
headers : { 'Content-Type': 'application/json' }
fixed the problem.
Try my source code below:
$http({
method : 'POST',
url : '/root',
// set the headers so angular passing info as form data (not request payload)
headers : { 'Content-Type': 'application/x-www-form-urlencoded' },
data : {
type:'root',
username:$scope.rEmail,
password:$scope.rPassword
},
transformRequest: function(obj) {
var str = [];
for(var p in obj){
str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
}
return str.join('&');
}
})
$http({
method : 'POST',
url : '/root',
// set the headers so angular passing info as form data (not request payload)
headers : { 'Content-Type': 'application/x-www-form-urlencoded' },
params : {
type:'root',
username:$scope.rEmail,
password:$scope.rPassword
}
})
try it with 'params', maybe it won't work but try it :P
I've tried with "params" instead of "data" and worked ok, and doesn't matter if headers are "application/x-www-form-urlencoded" or "application/json"
But using "application/json" works with request.query.param1 on node.

Categories

Resources