I'm trying to make calls to Basecamp's new API through Google Apps Script. GET, I can do. POST, not so much.
Starting with the path
https://basecamp.com/xxxxxxx/api/v1/projects/xxxxxxx/todolists.json
My code:
var headers = {
'User-Agent' : BCuseragent,
'Authorization' : 'Basic ' + Utilities.base64Encode(BCuser + ':' + BCpass),
'Content-Type' : 'application/json',
'Accept' : 'application/json',
'validateHttpsCertificates' : false
}
function getBC(path) {
var url = BCurl + path;
var opt = {
'headers' : headers,
'method' : "GET"
};
var response = UrlFetchApp.fetch(url, opt);
return response;
}
function postBC(path, payload) {
var url = BCurl + path;
var opt = {
'headers' : headers,
'method' : "POST",
'payload' : JSON.stringify(payload)
};
var response = UrlFetchApp.fetch(url, opt);
return response;
}
The payload I'm passing as a parameter:
{name: "foo", description: "bar"}
The getBC function works (200 OK), the postBC function returns a 403 error. Yet I am the owner of the project, and I've used curl and a Chrome REST client to confirm I can in fact POST new todolists to this project with the same authorization.
Obviously, my headers are malformed somewhere, but I can't see how.
This is a quirk of UrlFetchApp. You can't set the Content-Type using the general "headers" parameter, instead you must use the "contentType" parameter.
See the "Advanced Parameters" table here:
https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#fetch(String,Object)
Related
I am trying to push sheets data from a quiz to an api. The put works fine in postman but I can't seem to get it to work in google scripts.
Postman
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Authorization", "Basic bmljazpuaWNr");
myHeaders.append("Cookie", "FB_ResponseHeaders=%7b%22X-XSS-Protection%22%3a%7b%22Key%22%3a%221%3b+mode%3dblock%22%2c%22Value%22%3a%225C-58-58-82-DB-E9-4D-AD-BF-23-F8-5A-65-1E-EE-7B-96-94-7C-E6%22%7d%2c%22X-Content-Type-Options%22%3a%7b%22Key%22%3a%22nosniff%22%2c%22Value%22%3a%22E9-85-E8-2B-38-74-3B-AA-71-5A-41-1D-65-49-06-A7-FF-B3-D2-57%22%7d%2c%22Strict-Transport-Security%22%3a%7b%22Key%22%3a%22max-age%3d31536000%3b+includeSubDomains%22%2c%22Value%22%3a%221D-31-04-88-80-8A-6A-27-8E-2D-72-C5-32-98-74-A9-F8-E8-0C-E7%22%7d%7d; fbd_cooked=!/muNNuj9SlbMhC0PporV/qqu1cgGGvczJaMywTIzq+9GDRYedxCjdCU9X3WnSt1ijLXqndrZJ1DCTVw=");
var raw = JSON.stringify({
"fieldName": "SingleLineText5",
"fieldValue": "question1test"
});
var requestOptions = {
method: 'PUT',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
Google Scripts
// put em in a payload
var payload = {
"fieldName": "SingleLineText7",
"fieldValue": "question1googleSheet" }
var encodedAuth = Utilities.base64Encode("nick:nick");
var headers = [{"Authorization" : "Basic " + encodedAuth},{"Content-Type":"application/json"}];
var options = {
'method': 'PUT',
'body': JSON.stringify(payload),
'headers': headers,
'redirect': 'follow'
}
response = UrlFetchApp.fetch(url, options);
//log the response
Logger.log(JSON.stringify(response));
Am receiving
Exception: Attribute provided with invalid value: headers
If i remove the "Content-Type" I get no error but send no data just returns {}
According to the documentation you are using the wrong parameter. It should be:
const options = {
method : "PUT", // this was correct
payload: JSON.stringify(payload), // correct this
followRedirects : true, // correct this
headers: headers
}
I've created a variable to hold the client ID (CLIENT_ID) but I keep getting an error message saying that the client ID is required when running this function. Anyone have any idea of what I've done wrong here?
function getAuth() {
var authBasedUrl = 'https://test-api.service.hmrc.gov.uk/oauth/authorize';
var response = UrlFetchApp.fetch(authBasedUrl, {
headers: {
'Accept' : 'application/vnd.hmrc.1.0+json',
'response_type': 'code',
'client_id' : CLIENT_ID,
'scope' : 'hello',
'redirect_uri' : 'https://www.xxxxxxx.com/'
}});
var result = JSON.parse(response.getContentText());
Logger.log(JSON.stringify(result, null, 2));
}
Based on the docs you need to make a POST request. There is a blockqoute on the page that says:
Include the request parameters in the request body, not as request
headers.
EDIT:
function getAuth() {
var authBasedUrl = 'https://test-api.service.hmrc.gov.uk/oauth/token';
var options = {
headers: {
'Accept': 'application/vnd.hmrc.1.0+json',
"Content-Type": "application/json"
},
payload: JSON.stringify({
client_id: 'RgwU6hvdxxxxxxic6LwIt',
client_secret: '9e8c9yyyyyyyyyyc2fc2ed9126',
grant_type: 'client_credentials',
scope: 'hello'
})
}
var response = UrlFetchApp.fetch(authBasedUrl, options);
var result = JSON.parse(response.getContentText());
console.log(result);
}
Hey Stackoverflow fellows!
I have been trying to writing an automation for my google sheets using an api from bit.ly to shorten my tons of link. Right now, I am at the fundamental stage and trying to log what the api return to me. Could you guys help an see what is wrong with the code? I am expecting the 200 returning back to me but it keep returning 403 forbidden to me.
var form =
{"long_url": "https://dev.bitly.com", "domain": "bit.ly", "group_guid": "MY GROUP ID" };
var option = {'header':'Authorization: Bearer{MY TOKEN}',
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(form)
};
var response = UrlFetchApp.fetch('https://api-ssl.bitly.com/v4/shorten', option);
Logger.log (response);
}
P.S. I tried to further expand the code by using adding title (succeeded) and customized link (short half // after bit.ly/ ). The second part keep return me 404. Or should I use Post/custom_bitlinks instead?
Here is my current code:
function bitlyori (i, title){
var form = {
"group_guid": "MINE",
"domain": "bit.ly",
"long_url": i,
"title" : title
};
const MY_TOKEN = "MINE";
const option = {
headers: { Authorization: `Bearer ${MY_TOKEN}` },
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(form),
};
var result = UrlFetchApp.fetch('https://api-ssl.bitly.com/v4/bitlinks', option);
return (JSON.parse(result.getContentText()));
}
function bitly(url,title,custom) {
var temp = bitlyori(url, title);
var form_2 = {
"custom_bitlinks": [temp] ,
};
const MY_TOKEN = "MINE";
const option_2 = {
headers: { Authorization: `Bearer ${MY_TOKEN}` },
method: 'patch',
payload: form_2};
var temp_link = 'https://api-ssl.bitly.com/v4/bitlinks/'+ JSON.stringify(temp)["id"];
var result_2 = UrlFetchApp.fetch(temp_link, option_2);
return (JSON.parse(result_2.getContentText()));
}
Headers should be a object with key "headers" inside options:
const MY_TOKEN = "dfjkgsa";
const option = {
headers: { Authorization: `Bearer ${MY_TOKEN}` },
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(form),
};
See:
Urlfetchapp ยง Advanced parameters
I'm setting up a api connection. I want to get informations from discord api for my app.
So I implemented OAuth2 without any problems, I have my access token. Then I tried query some endpoints (/users/#me, /users/#me/guilds,...) but every time I get the same error.
I'm sending my authorization token in headers but it's still returning error 401.
I call the script with the generated url:
https://discordapp.com/api/oauth2/authorize?client_id=XYZ&redirect_uri=https%3A%2F%2Fscript.google.com%2Fmacros%2Fs%2FAKfycbyyt9-FiVv0zXOr8p8pMfojwEs2AXvBftVN1xdWeU3UQ1xgURD%2Fexec&response_type=code&scope=identify
Here is my "authentication code":
function doGet(e){
if(typeof e.parameter.code !== 'undefined') {
var code = e.parameter.code;
getAccessToken(code);
}
return ContentService.createTextOutput('someThink..');
}
function getAccessToken(code){
var API_TOKEN_URL = 'https://discordapp.com/api/oauth2/token'
var CLIENT_ID = 'XYZ'
var CLIENT_SECRET = 'XYZ'
var REDIRECT_URI = 'https://script.google.com/macros/s/AKfycbyyt9-FiVv0zXOr8p8pMfojwEs2AXvBftVN1xdWeU3UQ1xgURD/exec'
data = {
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': REDIRECT_URI,
'scope': 'identify'
}
header = {
'method' : 'post',
'Content-Type': 'application/x-www-form-urlencoded',
'payload' : data
}
var result = UrlFetchApp.fetch(API_TOKEN_URL, header);
if (result.getResponseCode() == 200) {
var params = JSON.parse(result.getContentText());
Logger.log(params.access_token); // all is fine
getUser(params.access_token, params.token_type)
}
}
And this code is my API request:
function getUser(accessToken, token_type){
var API_USERS_URL = 'https://discordapp.com/api/users/#me';
header2 = {
'method' : 'GET',
'Authorization': token_type + ' ' + accessToken,
// I tested all of them
// 'followRedirects' : true,
// 'muteHttpExceptions': true,
// 'Content-Type': 'application/json',
// 'Content-Type': 'application/x-www-form-urlencoded',
}
var resultUsers = UrlFetchApp.fetch(API_USERS_URL, header2); // ERROR HERE !
if (resultUsers.getResponseCode() == 200) {
var paramsUser = JSON.parse(result.getContentText());
Logger.log(paramsUser);
}
}
I accept the connection with discord with the same SCOPES: identify.
I tried so hard but I don't succeed. Every time the same error:
{"code": 0, "message": "401: Unauthorized"}
You're sending the header as the params/options parameter to UrlFetchApp.fetch(). Send the header as the header parameter in options:
var resultUsers = UrlFetchApp.fetch(API_USERS_URL,{headers: header2});
I'm trying to create an issue in Redmine using Google Apps Script, the code is following:
function create_issue() {
var payload = {
'project_id': 'helpdesk',
'subject': 'This is a test ticket',
'description': 'This is just a genius test ticket',
'category_id': 1
};
var headers = {
'X-Redmine-API-Key': '<myapikey>',
'Content-Type': 'application/json'
};
var url = 'http://myredmine.com/issues.json';
var options = {
'method': 'POST',
'headers': headers,
'payload': payload,
//uteHttpExceptions': true
};
var response = UrlFetchApp.fetch(url, options);
Logger.log(response);
}
Every time I ran that script, it threw the following exception:
Execution failed: Request failed for http://myredmine.com/issues.json
returned code 422. Truncated server response: {"errors":["Subject
can't be blank"]} (use muteHttpExceptions option to examine full
response) (line 25, file "Code") [0.645 seconds total runtime]
But as you see, the "subject" parameter was passed in the payload already. What am I missing?
Thanks,
Trinh
I found the problem, I need to indicate the issue in the payload:
function create_issue() {
var issue = {
"description": "Test ticket",
"subject": "Genius ticket"
}
var payload = {
"issue": issue,
"key": "<myapikey>",
"project_id": "helpdesk",
};
payload = JSON.stringify(payload);
var headers = {
'X-Redmine-API-Key': '<myapikey>',
'Content-Type': 'application/json'
};
var url = 'http://myredmine.com/issues.json';
var options = {
'method': 'POST',
'headers': headers,
'payload': payload,
'contentType': 'application/json',
//'muteHttpExceptions': true
};
var response = UrlFetchApp.fetch(url, options);
Logger.log(response);
}
And it works!