Sending CSV data to BigQuery REST API via POST - google-apps-script

I've been trying to upload a *.csv blob via POST request to BigQuery, but I'm having trouble determining where should I put the blob file (i.e. byte data) in the request.
If I use a client library, this code does what I need:
var job = {
configuration: {
load: {
destinationTable: {
projectId: projectId,
datasetId: datasetId,
tableId: tableId
},
skipLeadingRows: 1,
allowQuotedNewlines: true,
quote: "'",
sourceFormat: 'CSV'
}
}
};
var job = BigQuery.Jobs.insert(job, projectId, csv);
This works perfectly, but while searching through the REST API, I don't see declared anywhere where to set the *.csv data in order to work like this, with no client library:
var job = {
configuration: {
load: {
destinationTable: {
projectId: projectId,
datasetId: datasetId,
tableId: tableId
},
skipLeadingRows: 1,
allowQuotedNewlines: true,
quote: "'",
sourceFormat: 'CSV'
}
}
};
var url = "https://www.googleapis.com/bigquery/v2/projects/" + projectId + "/jobs/";
var urlParams = {
"method": "POST",
"muteHttpExceptions": true,
"contentType": "application/json",
"headers": {"Authorization": "Bearer " + getBQToken()},
"responseType": "json",
payload: job,
};
var resp = UrlFetchApp.fetch(url, urlParams).getContentText();
var result = JSON.parse(resp);
How can I include my CSV data and the job configuration when using the REST API approach?

There are two ways to make upload requests: multipart upload and resumable upload. Multipart upload is “for quick transfer of smaller files and metadata; transfers the file along with metadata that describes it, all in a single request”. Resumable upload is “for reliable transfer, especially important with larger files” as described here (as #Elliott Brossard pointed). Find in the same documentation the resumable upload request for the Google BigQuery API example below:
POST /upload/bigquery/v2/projects/<projectId>/jobs?uploadType=resumable HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer your_auth_token
Content-Length: 38
Content-Type: application/json; charset=UTF-8
X-Upload-Content-Type: */*
X-Upload-Content-Length: 2000000
{
"configuration": {
"load": {
"sourceFormat": "NEWLINE_DELIMITED_JSON",
"schema": {
"fields": [
{"name": "f1", "type": "STRING"},
{"name": "f2", "type": "INTEGER"}
]
},
"destinationTable": {
"projectId": "projectId",
"datasetId": "datasetId",
"tableId": "tableId"
}
}
}
}

Related

How to make GET requests works in Postman and Google Apps script

The following works in Postman:
GET https://mainnet.incognito.org/fullnode
with Body -> raw of:
{
"id": 1,
"jsonrpc": "1.0",
"method": "getbeaconbeststatedetail",
"params": []
}
The following doesn't work in Google app scripts:
function getBeaconState() {
const mainnet = "https://mainnet.incognito.org/fullnode";
var raw = JSON.stringify({ "id": 1,"jsonrpc": "1.0","method": "getbeaconbeststatedetail","params": []});
var requestOptions = {
"method": "get",
"headers": {"Content-Type": "application/json"},
"body": raw,
"redirect": "follow"
};
var beaconState = UrlFetchApp.fetch(mainnet, requestOptions);
Logger.log("I set the beaconState variable.");
}
It gets a 400 error, so it must be something I'm doing wrong but poking around hasn't gotten me very far.

Cloud build API deploy:run on Google Apps Script doesn't work

I confirmed authorization with service account on GAS. "list" is work, but "run" method never work. Error msg is "source must not be empty". What kind of json should I attach?
This is on standalone GAS using GSApp library. (Apps-Script-GSApp-Library : MJ5317VIFJyKpi9HCkXOfS0MLm9v2IJHf)
function deploy() {
var jsonKey = JSON.parse(PropertiesService.getScriptProperties().getProperty("jsonKey"));
var serverToken = new GSApp.init(jsonKey.private_key, ["https://www.googleapis.com/auth/cloud-platform"], jsonKey.client_email);
var tokens = serverToken.addUser(jsonKey.client_email).requestToken().getTokens();
var url = "https://cloudbuild.googleapis.com/v1/projects/{ProjectId}/triggers/{TriggerId}:run";
var options = {
"muteHttpExceptions": true,
"method": "POST",
"headers": {
"Authorization":"Bearer "+tokens[jsonKey.client_email].token,
},
"source": {
"projectId": "{ProjectId}",
"branchName": "master",
"repoName": "repo"
}
}
Logger.log(UrlFetchApp.fetch(url,options));
}
{
"error": {
"code": 400,
"message": "source must not be empty",
"status": "INVALID_ARGUMENT"
}
}
UrlFetchApp.fetch() does not recognize "source" as a valid property. Use "payload" instead. Also you'll need to JSON.stringify() your payload and set the contentType property as application/json as follows:
var options = {
"muteHttpExceptions": true,
"method": "POST",
"contentType":"application/json",
"headers": {
"Authorization":"Bearer "+tokens[jsonKey.client_email].token,
},
"payload": JSON.stringify({
"projectId": "{ProjectId}",
"branchName": "master",
"repoName": "repo"
})
};

Google Apps Script to Create Confluence Page -- Results in Status Code 500

Note: I also posted this question on the Atlassian forum here:
https://community.atlassian.com/t5/Confluence-questions/Google-Apps-Script-to-Create-Confluence-Page-HTTP-500-Error/qaq-p/1039040#M66094
I'm reaching out to a larger audience here on SO.
I'm using the following google apps script code in a Google Sheet to create a Confluence page:
headers = {"Authorization" : "Basic " + Utilities.base64Encode(user + ':' +
pswd), "Content-Type": "application/json"};
url = "https://confluence.asdf.com/rest/api/content/";
var params = {
"method":"POST",
"headers":headers,
"muteHttpExceptions": false,
"type":"page",
"title":newTitle,
"space":{"key":"DOC"},
"body":{"storage":{"value": "<p>This is <br/> a new page</p>" },
"representation":"storage"}
};
var createResponse = UrlFetchApp.fetch(url, params);
However, when I submit the request, I receive this response:
Request failed for https://confluence.atlas.asdf.com/rest/api/content/
returned code 500.
Truncated server response: {"statusCode":500,"
message":"<?> No content to map to Object due to end of
input","reason":"Internal Server Error"} (use muteHttpExceptions option to
examine full response)
I realize there are curl samples out there which I've seen but do not help me.
What am I doing wrong?
Edit: 25-March
#Tanaike
I modified the code as you suggested:
headers = {"Authorization" : "Basic " + Utilities.base64Encode(user + ':' + pswd) };
var payload = {
"type": "page",
"title": newTitle,
"space": {"key": "DOC"},
"body": {
"storage": {
"value": "<p>This is <br/> a new page</p>"
},
"representation": "storage"
}
};
var params = {
"method": "POST",
"headers": headers,
"muteHttpExceptions": false,
"payload": JSON.stringify(payload),
"contentType": "application/json"
};
var createResponse = UrlFetchApp.fetch(url, params);
I receive the same error as before.
How about this modification?
Modified script:
Please modify params as follows and test again. From the error message in your question, the request body was put in the property of payload.
var payload = {
"type": "page",
"title": newTitle,
"space": {"key": "DOC"},
"body": {
"storage": {
"value": "<p>This is <br/> a new page</p>"
},
"representation": "storage"
}
};
var params = {
"method": "POST",
"headers": headers,
"muteHttpExceptions": false,
"payload": JSON.stringify(payload)
};
Note:
This modification supposes that each value in payload and headers is correct.
"Content-Type": "application/json" in headers can be also put in params as "contentType": "application/json".
References:
UrlFetchApp
Confluence REST API examples
I cannot test this modification. So if this didn't work, can you provide the error message? I would like to think of about the issue.
Edit:
From the official document, it seems that the property of body is "body":{"storage":{"value":"<p>This is a new page</p>","representation":"storage"}}}. So please modify as follows.
Modified script:
headers = {"Authorization" : "Basic " + Utilities.base64Encode(user + ':' + pswd) };
var payload = {
"type": "page",
"title": newTitle,
"space": {"key": "DOC"},
"body": {
"storage": {
"value": "<p>This is <br/> a new page</p>",
"representation": "storage" // Modified
}
}
};
var params = {
"method": "POST",
"headers": headers,
"muteHttpExceptions": false,
"payload": JSON.stringify(payload),
"contentType": "application/json"
};
var createResponse = UrlFetchApp.fetch(url, params);
Note:
In my environment, I could confirm that the result was the same with the result from the official sample script. If this didn't work, please confirm each value of payload and headers, again.

GMB API Insights Invalid JSON Payload received

I am trying to get some insights of our locations using Google Apps Script and the Google My Business Api.
Getting Reviews and stuff was no big deal.
The code worked out well in the OAuth2 Playground.
Here is the request:
var myBusinessService = getMyBusinessService();
var payload ={
"locationNames":["accounts/116447162401331885225/locations/10722475831894877870"],
"basicRequest": {
"metricRequests": [{
"metric": "ALL"
}],
"timeRange": {
"startTime": "2017-01-01T00:00:01.045123456Z",
"endTime": "2017-01-31T23:59:59.045123476Z"
}
}
};
var options = {
"headers":{
"Authorization": 'Bearer ' + myBusinessService.getAccessToken()
},
"method": "POST",
"payload": payload,
"muteHttpExceptions": true
};
var response = UrlFetchApp.fetch('https://mybusiness.googleapis.com/v4/accounts/116447162401331885225/locations:reportInsights', options);
The response:
{error={code=400, details=[Ljava.lang.Object;#3116fd89, message=Invalid JSON payload received. Unknown name "basicRequest": Cannot bind query parameter. 'basicRequest' is a message type. Parameters can only be bound to primitive types., status=INVALID_ARGUMENT}}
Hope someone might help me with this.
Regards
Thies
You're sending payload as a JavaScript object. As per the error message ("message=Invalid JSON payload received."), you need to send it as JSON. Use JSON.stringify() to make payload a JSON string.
var options = {
"headers":{
"Authorization": 'Bearer ' + myBusinessService.getAccessToken()
},
"method": "POST",
"payload": JSON.stringify(payload),
"muteHttpExceptions": true
};

How to Retrieve (not create) Tasks from Asana using Apps Script & Personal Access Token

I am attempting to retrieve, but not create, tasks from Asana using Google Apps Script.
Using the Asana API Explore, I have constructed a URL that returns the data I desire: https://app.asana.com/api/1.0/tasks?opt_fields=name,assignee_status&assignee=987654321987654&completed_since=2018-02-22&limit=100&workspace=456789123456
This URL returns the desired data, in the following format:
{
"data": [
{
"id": 147258369147258,
"assignee_status": "inbox",
"name": "An example task name"
},
{
"id": 963852741963852,
"assignee_status": "upcoming",
"name": "And second example task name."
},
//etc...
]
}
With that URL as a model, I have created a Personal Access Token and executed the following function within Apps Script:
function getTasks5() {
// Asana Personal Token
var bearerToken = "Bearer " + "asdf123456789asdf456789456asdf";
//Request
var request = {
data: {
opt_fields: ["name", "assignee_status"],
assignee: "987654321987654",
completed_since: "2018-02-22",
limit: "100",
workspace: "456789123456"
}
};
// Request options
var options = {
method: "GET",
headers: {
"Authorization": bearerToken
},
contentType: "application/json",
payload: JSON.stringify(request)
};
var url = "https://app.asana.com/api/1.0/tasks";
var result = UrlFetchApp.fetch(url, options);
var reqReturn = result.getContentText();
Logger.log(reqReturn);
}
Instead of returning the desired data as the aforementioned URL does, the function creates an unnamed task in Asana, which is undesirable. It also returns this response containing undesired data:
{
"data": {
"id": 123456789123456,
"created_at": "2018-02-22T20:59:49.642Z",
"modified_at": "2018-02-22T20:59:49.642Z",
"name": "",
"notes": "",
"assignee": {
"id": 987654321987654,
"name": "My Name Here"
},
"completed": false,
"assignee_status": "inbox",
"completed_at": null,
"due_on": null,
"due_at": null,
"projects": [],
"memberships": [],
"tags": [],
"workspace": {
"id": 456789123456,
"name": "Group Name Here"
},
"num_hearts": 0,
"num_likes": 0,
"parent": null,
"hearted": false,
"hearts": [],
"followers": [
{
"id": 987654321987654,
"name": "My Name Here"
}
],
"liked": false,
"likes": []
}
}
Is it possible to simply GET a list of tasks in the manner exemplified by my first JSON example above without creating a task, and without resorting to using OAuth? If so, what changes to the Apps Script function need to be made?
Alright, the problem was with the approach I was taking. Rather than format the request with a payload (which infers a POST request), I needed to structure it more traditionally as a GET request, like so:
var requestUrl = "https://app.asana.com/api/1.0/tasks?opt_fields=name,assignee_status&assignee=123456789123&completed_since=2018-02-22&limit=100&workspace=987654321987";
var headers = {
"Authorization" : "Bearer " + AUTH_TOKEN
};
var reqParams = {
method : "GET",
headers : headers,
muteHttpExceptions: true
};
Then I was able to perform:
UrlFetchApp.fetch(requestUrl, reqParams);
And obtain the data I was after.