How to parse a simple JSON object (accessing single elements)? - json

I'm trying to process simple JSON data in a Google-Apps-Script (a Webhook Receiver). For a test I send data from the console:
curl -d "{"result":true,"count":42,"exchange":"Kroakex"}" -H "Content-Type: application/json" -X POST https://script.google.com/macros/s/xxx/exec
... but I can't access the json elements in my processing function:
function doPost(e) {
var jsonString = JSON.stringify(e.postData.contents);
var jsonObj = JSON.parse(jsonString);
console.log(jsonObj); // ---> "{result:true,count:42,exchange:Kroakex}"
console.log(jsonObj.count); // ---> "undefined"
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = Math.max(sheet.getLastRow(),1);
sheet.insertRowAfter(lastRow);
sheet.getRange(lastRow + 1, 1).setValue(jsonObj['count']); // ---> nothing
sheet.getRange(lastRow + 1, 2).setValue(jsonObj['exchange']); // ---> nothing
sheet.getRange(lastRow + 1, 3).setValue(jsonObj); // ---> {result:true,count:42,exchange:Kroakex}
SpreadsheetApp.flush();
return HtmlService.createHtmlOutput("post request received");
}
When I instead create the JSON string manually with this line, it all works fine:
const jsonString = '{"result":true, "count":42, "exchange":"Kroakex"}';
Can anyone help?

I would like to propose the following modification.
Modification points:
I think that in your curl command, there are the modification points.
When your curl command is used, e.postData.contents is "{result:true,count:42,exchange:Kroakex}". Because at -d "{"result":true,"count":42,"exchange":"Kroakex"}", " is used in "{,,,}". In this case, your Google Apps Script cannot parse the values as JSON object. Please escape " or enclose by '. By this, e.postData.contents becomes "{\"result\":true,\"count\":42,\"exchange\":\"Kroakex\"}".
In this case, please use -L and -X POST is not required.
The modified curl command is as follows.
curl -L -d '{"result":true,"count":42,"exchange":"Kroakex"}' -H "Content-Type: application/json" https://script.google.com/macros/s/###/exec
or
curl -L -d "{\"result\":true,\"count\":42,\"exchange\":\"Kroakex\"}" -H "Content-Type: application/json" https://script.google.com/macros/s/###/exec
By above modification, your Google Apps Script becomes as follows.
Modified script:
function doPost(e) {
var jsonObj = JSON.parse(e.postData.contents); // <--- Modified
console.log(jsonObj);
console.log(jsonObj.count);
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = Math.max(sheet.getLastRow(),1);
sheet.insertRowAfter(lastRow);
sheet.getRange(lastRow + 1, 1).setValue(jsonObj['count']);
sheet.getRange(lastRow + 1, 2).setValue(jsonObj['exchange']);
sheet.getRange(lastRow + 1, 3).setValue(JSON.stringify(jsonObj)); // <--- Modified
SpreadsheetApp.flush();
return HtmlService.createHtmlOutput("post request received");
}
Note:
When you modified the script of Web Apps, please redeploy the Web Apps as new version. By this, the latest script is reflected to Web Apps. Please be careful this.
When you use the curl command, I think that the returned value might be suitable for return ContentService.createTextOutput("post request received"); instead of return HtmlService.createHtmlOutput("post request received");.
References:
Web Apps
Taking advantage of Web Apps with Google Apps Script
Added:
When you want to access to Web Apps using the URL of https://script.google.com/macros/s/###/dev, it is required to use the access token. The modified curl command is as follows.
curl -L \
-H "Authorization: Bearer ### access token ###" \
-H "Content-Type: application/json" \
-d '{"result":true,"count":42,"exchange":"Kroakex"}' \
"https://script.google.com/macros/s/#####/dev"
In this case, https://www.googleapis.com/auth/drive.readonly and https://www.googleapis.com/auth/drive can be used for the scope.
Reference:
How to use dev mode from outside

Related

How to Convert cURL POST Request in PHP to Google Apps Script

VoIP.ms offers the ability to send SMS text messages from its API. They provide the following sample code:
<?
$postfields = array(
'api_username'=>'john#domain.com',
'api_password'=>'password',
'method'=>'getServersInfo',
'server_pop'=>'1'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt($ch, CURLOPT_POST, true );
curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);
curl_setopt($ch, CURLOPT_URL, "https://voip.ms/api/v1/rest.php");
$result = curl_exec($ch);
curl_close($ch);
$data=json_decode($result,true);
echo "<pre>";
print_r($data);
echo "</pre>";
?>
When I execute the following command from the command line in Terminal, I'm able to successfully send an SMS text message from VoIP.ms:
curl -X POST -F 'api_username=john#domain.com' -F 'api_password=password' -F 'method=sendSMS' -F 'did=1234567890' -F 'dst=0987654321' -F 'message=Hello' https://voip.ms/api/v1/rest.php
By searching around on Google, I've cobbled together the following Google Apps Script:
function sendSMS() {
var formData = {
api_username : "john#domain.com",
api_password : "password",
method : "sendSMS",
did : 1234567890,
dst : 0987654321,
message : "Hello"
};
var options = {
method : "POST",
payload : formData
};
UrlFetchApp.fetch("https://voip.ms/api/v1/rest.php", options);
}
When I run the script, I get the following error:
Exception: Request failed for https://voip.ms returned code 500. Truncated server response: > xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">env:Bodyenv:Faultenv:Codeenv:Value... (use muteHttpExceptions option to examine full response)
sendSMS # Code.gs:14
Any suggestions on where I'm going wrong?
I believe your goal is as follows.
You want to convert the following curl command to Google Apps Script. And, your curl command works fine.
curl -X POST -F 'api_username=john#domain.com' -F 'api_password=password' -F 'method=sendSMS' -F 'did=1234567890' -F 'dst=0987654321' -F 'message=Hello' https://voip.ms/api/v1/rest.php
Modification points:
From your sample curl command, it seems that did : 1234567890 and dst : 0987654321 should be did : "1234567890" and dst : "0987654321". This has already been mentioned in the TheMaster's comment.
In your curl command, -F is used. In this case, the content type of the request header is multipart/form-data. Unfortunately, UrlFetchApp uses application/x-www-form-urlencoded as the default content type.
When these points are reflected in tha Google Apps Script, how about the following modification?
Modified script:
function sendSMS() {
var formData = {
api_username: "john#domain.com",
api_password: "password",
method: "sendSMS",
did: "1234567890",
dst: "0987654321",
message: "Hello"
};
var options = { payload: Object.entries(formData).reduce((o, [k, v]) => (o[k] = Utilities.newBlob(v), o), {}) };
UrlFetchApp.fetch("https://voip.ms/api/v1/rest.php", options);
}
Note:
This modified script supposes that your URL of https://voip.ms/api/v1/rest.php can be accessed from the Google side, and the values of your formData are valid values. Please be careful about this.
At UrlFetchApp, the request body of multipart/form-data is automatically created in the internal server side. But, if this request body couldn't be used to your API (There is sometimes a case that this request body cannot be used.), please test the request using FetchApp (Author: me).
Reference:
fetch(url, params)

Jenkins Multibranch Pipeline check only the new or changed files pushed to GIT

we are working with a tool where the elements are all written via .json.
Currently my GIT folder structure looks like this:
elementsfolder -> element1.json, element2.json, element3.json
scriptsfolder -> e.g. transformation.py
testfolder -> run-element.sh
Jenkinsfile
The problem I have now is that the .json files in folder elementsfolder should be tested with the bashscript from the testfolder and (if necessary) a script like transformations.py should be called. This also works so far, but all .json files are always tested (no matter if unchanged or not). But this should not be the case. Only the elements that are either changed or newly created should be tested. We have at the end of the day over 6000 elements, accordingly, the test over all elements would be too costly. Can anyone help me with this? In Jenkins the pipeline looks like this (I only post the stage build, because test and deploy are similar):
stages {
stage('Build') {
environment {
CREDS = credentials('creds')
ENDPOINT = 'automation-api'
}
steps {
sh '''
username=$USR
password=$PSW
# Login curl
login=$(curl -k -s -H "Content-Type: application/json" -X POST -d \\{\\"username\\":\\"$username\\",\\"password\\":\\"$password\\"\\} "$ENDPOINT/session/login" )
token=$(echo ${login##*token\\" : \\"} | cut -d '"' -f 1)
# Build
#1. Validation .json
curl -k -s -H "Authorization: Bearer $token" -X POST -F "definitionsFile=#element/*.json" "$ENDPOINT/build"
#2. Show Error
curl --show-error --fail -k -s -H "Authorization: Bearer $token" -X POST -F "definitionsFile=#element/*.json" "$ENDPOINT/build"
#3. Logout
curl -k -s -H "Authorization: Bearer $token" -X POST "$ENDPOINT/session/logout"
'''
}
}
If you are checking out from an SCM Jenkins will allow you to check the Changeset between the last build and the current build. So basically you can first try to find the files that really changed and then use only those files. Refer to the following example. After getting the list of files that changed you can either move them to a new directory or delete the unchanged files from the elementsfolder. The following sample getFilesChanged will return a list of all the changed/added files in the repo. You may want to tweak this function to match your requirement.
pipeline {
agent any
stages {
stage('clone') {
steps {
git branch: 'main', url: 'https://github.com/xxx/sample.git'
}
}
stage('build') {
steps {
script {
println(getFilesChanged())
// Do your cleanup here and then execute the SH block
}
}
}
}
}
def getFilesChanged() {
def filesList = []
def changeLogSets = currentBuild.changeSets
for (int i = 0; i < changeLogSets.size(); i++) {
def entries = changeLogSets[i].items
for (int j = 0; j < entries.length; j++) {
def entry = entries[j]
def files = new ArrayList(entry.affectedFiles)
for (int k = 0; k < files.size(); k++) {
def file = files[k]
filesList.add(file.path)
}
}
}
return filesList
}

Error using Octave 4.0.2 to submit Coursera assignments

This is the error:
curl: (1) Protocol "https" not supported or disabled in libcurl
!! Submission failed: unexpected error: input file does not exist
!! Please try again later.
I am using Windows 10.
I see a possibly relevant answer here, but I don't know where this code would be added within Octave.
The URL is changed. Use the new one in submissionUrl() function in lib/submitWithConfiguration.m file.
function submissionUrl = submissionUrl()
%submissionUrl = 'https://www-origin.coursera.org/api/onDemandProgrammingImmediateFormSubmissions.v1';
submissionUrl = 'https://www.coursera.org/api/onDemandProgrammingImmediateFormSubmissions.v1';
end
For check URL you can use curl in terminal.
curl -k 'https://www.coursera.org/api/onDemandProgrammingImmediateFormSubmissions.v1'
You must get something like {"message":"","statusCode":404}
With wrong URL you dose't get anything.
Try to use the patch that changes following lines in the response function of submitWithConfiguration.m:
params = {'jsonBody', body};
%responseBody = urlread(submissionUrl, 'post', params); OLD CODE
[code, responseBody] = system(sprintf('echo jsonBody=%s | curl -k -X POST -d #- %s', body, submissionUrl));
d #- takes data in a file on the current stdin (the echo fills in).
-k allows curl to perform "insecure" SSL
(see curl --help)
HTH
==================
your code is the one i have, but i'm W7.
Do another try by setting quotes around the url in :
function submissionUrl = submissionUrl()
submissionUrl =
'"https://www-origin.coursera.org/api/onDemandProgrammingImmediateFormSubmissions.v1"';
end
(caution use : ' " and " ' that will quote the "https://.." on the command line.)
If it doesn't work, do a direct call to coursera with a command line (cmd) :
curl -k "https://www-origin.coursera.org/api/onDemandProgrammingImmediateFormSubmissions.v1"
This will call coursera and, as there is no sent form , the site will respond with an html page with near the end ... Action not found ....
if this works, the pb is probably not inside curl, but somewhere else. let us know.
There was a typo in Answer #1, which was corrected in Answer #2.
The change is:
In the function,
function response = submitParts(conf, email, token, parts) Apply the following changes
Comment the line responseBody = urlread(submissionUrl, 'post', params);
Type the following in place of it,
[code, responseBody] = system(sprintf('echo jsonBody=%s | curl -k -XPOST -d #- %s', body, submissionUrl));
So the final code of the function looks like
function response = submitParts(conf, email, token, parts)
body = makePostBody(conf, email, token, parts);
submissionUrl = submissionUrl();
params = {'jsonBody', body};
#responseBody = urlread(submissionUrl, 'post', params);
[code, responseBody] = system(sprintf('echo jsonBody=%s | curl -k -XPOST -d #- %s', body, submissionUrl));
response = loadjson(responseBody);
end
Change the following in submitWithConfiguration.m:
curl -k -X POST
to
curl -k -XPOST
and try again.
I just ran into this issue on Windows 10 today. In my case the request was performing correctly but the curl command was outputting timing information by default which was throwing off the validation logic in the submission script.
The submission was succeeding, but if I printed the response string, it looked something like this:
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 1562 100 548 100 1014 548 1014 0:00:01 --:--:-- 0:00:01 2082
100 1562 100 548 100 1014 548 1014 0:00:01 --:--:-- 0:00:01 2082
{"id":"Blablablabla","courseId":"Blablabla","itemId":"Blabla",...}
I noticed that it was using the curl command to make the request, so I added the --silent flag to the code that creates the curl command to execute in submitWithConfiguration.m (in my case on line 134).
% use urlread or curl to send submit results to the grader and get a response
function response = getResponse(url, body)
% try using urlread() and a secure connection
params = {'jsonBody', body};
[response, success] = urlread(url, 'post', params);
if (success == 0)
% urlread didn't work, try curl & the peer certificate patch
if ispc
% testing note: use 'jsonBody =' for a test case
json_command = sprintf('echo jsonBody=%s | curl --silent -k -X POST -d #- %s', body, url);
% ^^^^^^^^ this right here!!
else
% it's linux/OS X, so use the other form
json_command = sprintf('echo ''jsonBody=%s'' | curl --silent -k -X POST -d #- %s', body, url);
end
% get the response body for the peer certificate patch method
[code, response] = system(json_command);
% test the success code
if (code ~= 0)
fprintf('[error] submission with curl() was not successful\n');
end
end
end
Now the response looked like a more reasonable:
{"id":"Blablablabla","courseId":"Blablabla","itemId":"Blabla",...}
And the submittion completed successfully.
I was having the same problem. All I did to overcome this problem is, I changed the path to ex2 folder and it worked for me.

Can't access JSON value from curl

I use this curl command:
curl -X POST -H "Content-Type: application/json" http://localhost:8081/creditcard -d '{"credit-card":"1234-5678-9101-1121"}'
In my js file, I have this code block to get the credit-card's value:
request.on('data', function(data) {
var cc = 'credit-card';
var a = JSON.parse(data.toString());
console.log(a[cc]);
}
For this I get:
undefined:1
'{credit-card:1234-5678-9101-1121}'
^
SyntaxError: Unexpected token '
at Object.parse (native)
at IncomingMessage.<anonymous> (<path>\ccserver.js:32:34)
at IncomingMessage.emit (events.js:107:17)
at IncomingMessage.Readable.read (_stream_readable.js:373:10)
at flow (_stream_readable.js:750:26)
at resume_ (_stream_readable.js:730:3)
at _stream_readable.js:717:7
at process._tickCallback (node.js:355:11)
So I tried to use JSON.stringify as followed:
request.on('data', function(data) {
var cc = 'credit-card';
var a = JSON.parse(JSON.stringify(data.toString()));
console.log(a[cc]);
}
But this is what I get:
undefined
undefined
However, when I try to parse a hard-coded json string, it goes ok:
var jsonString = '{"credit-card":"1234-5678-9101-1121"}';
var a = JSON.parse(jsonString);
console.log(a[cc]);
Result:
1234-5678-9101-1121
What is the correct way to do get the data out of this json?
Please advise
Thanks
Try reading from absolute path
curl -X POST
-H 'Content-Type:application/json'
-H 'Accept: application/json'
--data-binary #/full/path/to/test.json
http://server:port/xyz/abc/blah -v -s
Well, you already have String so all you need to convert it to javascript variable and get using .notation. Suggest to use firebug to see what is in variable.
obj = JSON.parse(json);
obj.cc or obj.cc[0]
should give you what you want.

Upload file in BOX using BOX API using C#

I have BOX account and in API document
curl https://upload.box.com/api/2.0/files/content \
-H "Authorization: Bearer ACCESS_TOKEN" \
-F filename=#FILE_NAME \
-F parent_id=PARENT_FOLDER_ID
I am stuck with this filename and parent_id how to pass the filename and parent_id
i have tried lots of way, but nothing is working for me.
Following is the code:
httpWReq.Method = "POST";
httpWReq.Headers.Add("Authorization", "Bearer ");
httpWReq.ContentType = "multipart/form-data";
//{\"parent_id\":\""+parentID +"\"}
//byte[] file = File.ReadAllBytes(postData);
httpWReq.ContentLength = data.Length;
using (Stream reqStream = httpWReq.GetRequestStream())
{
reqStream.Write(data, 0, data.Length);
//reqStream.Close();
}
using (HttpWebResponse response = (HttpWebResponse)httpWReq.GetResponse())
{
//Console.WriteLine("HTTP/{0} {1} {2}", response.ProtocolVersion, (int)response.StatusCode, response.StatusDescription);
response.Close();
}
Need Help
Thanks in Advance
Vaibhav,
Please see example of how official Box C# SDK is doing upload:
https://github.com/box/box-windows-sdk-v2/blob/master/Box.V2/Managers/BoxFilesManager.cs
Is there any reason why you don't want to use Box Windows SDK?