I am trying to call Shopify's GraphQL API via Google App Script.
I have successfully made the call via Postman using the same body and authentication values and that has been working fine.
However, when calling the API via App Script I keep receiving a 400 response code, with the following error message {"errors":{"query":"Required parameter missing or invalid"}}
Here is the code I am using:
function shopifySync() {
var url = "https://store-name.myshopify.com/admin/api/2021-07/graphql.json";
var payloaddata = `query {orders(first: 20) { edges { node { id } } } }`;
var payload = JSON.stringify(payloaddata);
var password = "api_password"; //Private Shopify App
var response = UrlFetchApp.fetch(url, {
'method': "POST",
'muteHttpExceptions': true,
'headers': { "X-Shopify-Access-Token": password , "Content-Type": "application/json"},
'payload': payload
},
);
Logger.log(response.getContentText());
Logger.log(response.getResponseCode());
}
In Shopify's documentation the 400 HTTP response is classified as "Bad Request" and the explanation is:
The request was not understood by the server, generally due to bad syntax or because the Content-Type header was not correctly set to application/json.
This status is also returned when the request provides an invalid code parameter during the OAuth token exchange process.
Source: https://shopify.dev/api/usage/response-codes
How can I resolve this issue and successfully call Shopify's GraphQL API?
I found the solution in the GraphQL documentation of another Saas company.
The issue was how the payload was formatted
How I tried it:
'payload': payload
How it should be:
'payload': JSON.stringify({'query': payloaddata})
Final code that is working for me with the 2021-07 GraphQL API for Shopify:
var url = "https://store-name.myshopify.com/admin/api/2021-07/graphql.json";
var payloaddata = 'query {orders(first: 20) { edges { node { id } } } }';
var password = "api_password";
var response = UrlFetchApp.fetch(url, {
'method': "POST",
'muteHttpExceptions': true,
'headers': { "X-Shopify-Access-Token": password , "Content-Type": "application/json"},
'payload': JSON.stringify({'query': payloaddata})
});
Related
I'm trying to use the fetch API in vanilla JavaScript to generate a token provided by Django OAuth Toolkit. The application I've created in DOT uses the "Resource owner password-based" authorization grant type. My code looks like this (grant_type, username and password are provided through request.formData()):
const data = await request.formData();
const oauth = await fetch(`${API_ROOT}/o/token`, {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
Authorization: `Basic ${Buffer.from(CLIENT_ID + ':' + CLIENT_SECRET).toString('base64')}`
},
body: data
});
This request imitates a successful GET request I've created using Insomnia (with Multipart Form data for grant_type, username and password + CLIENT_ID and CLIENT_SECRET as the username and password in Basic Auth). In other words, I don't understand why the JavaScript fetch request does not work even though it is supposed to be identical to the Insomnia request. The JavaScript fetch request returns a 400 error. When I remove the Content-Type header, I get a 500 error. What am I doing wrong?
EDIT: It may be worth noting that I am making this fetch call within a SvelteKit application.
As it turns out, in this particular case I DID need to set Content-Type. I found this answer: Trying to get access token with django-oauth-toolkit using fetch not working while working using jquery
My code works as follows:
const data = await request.formData();
const oauth = await fetch(`${API_ROOT}/oauth/token/`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
Authorization: `Basic ${Buffer.from(CLIENT_ID + ':' + CLIENT_SECRET).toString('base64')}`,
},
body: formDataToUrlEncoded(data)
});
The formDataToUrlEncoded function roughly ressembles the one posted in the above post:
export function formDataToUrlEncoded(formData) {
var url_encoded = '';
for (var pair of formData) {
if (url_encoded != '') {
url_encoded += '&';
}
url_encoded += encodeURIComponent(pair[0]) + '=' + encodeURIComponent(pair[1]);
}
return url_encoded;
}
I have been trying to figure out how to acquire an access token from Reddit API in Google Apps Script. I have below code written so far:
function main() {
var username = 'myredditusername';
var pwd = 'myredditpassword';
var client_id = 'myredditclientid';
var client_secret = 'myredditclientsecret';
var access_token_url = 'https://www.reddit.com/api/v1/access_token';
var api_url = 'https://oauth.reddit.com/';
var user_agent = 'MySideProjectUserAgent';
var data = {
'grant_type': 'password',
'username': username,
'password': pwd
};
var options = {
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(data),
'headers': {'User-Agent': user_agent},
// what do I enter here to pass my client_id and client_secret?
};
var resp = UrlFetchApp.fetch(access_token_url, options);
console.log(resp.getContentText());
}
Running the above code receives an error like below (not surprising because I still need to figure out how to pass in my client_id and client_secret):
Exception: Request failed for https://www.reddit.com returned code 401. Truncated server response: {"message": "Unauthorized", "error": 401} (use muteHttpExceptions option to examine full response)
When using curl, I was able to acquire the token successfully with this command:
curl -X POST -A 'KeywordTrackAgent' -d "grant_type=password&username=myredditusername&password=myredditpassword" --user 'client_id:client_secret' https://www.reddit.com/api/v1/access_token
From reaching around (example post), I figured that if I were to translate this curl request to a POST request, I'd need to add Authorization field to my headers parameter with the format like below:
function main() {
var username = 'myredditusername';
var pwd = 'myredditpassword';
var client_id = 'myredditclientid';
var client_secret = 'myredditclientsecret';
var access_token_url = 'https://www.reddit.com/api/v1/access_token';
var api_url = 'https://oauth.reddit.com/';
var user_agent = 'MySideProjectUserAgent';
var data = {
'grant_type': 'password',
'username': username,
'password': pwd
};
var options = {
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(data),
'headers': {
'User-Agent': user_agent,
// Below, I decided to encode my client_id and client_secret in base64 with the prefix 'Basic '
'Authorization': 'Basic clientIdAndClientSecretInBase64',
},
};
var resp = UrlFetchApp.fetch(access_token_url, options);
console.log(JSON.parse(resp.getContentText()));
}
I'm still receiving { error: 'unsupported_grant_type' }.
Could anyone--who has successfully fetched Reddit access token using JavaScript and preferably, using Google Apps Script--share some suggestion/insight on this? Thank you in advance for your answers!
I believe your goal as follows.
You want to convert the following curl command to Google Apps Script.
curl -X POST -A 'KeywordTrackAgent' -d "grant_type=password&username=myredditusername&password=myredditpassword" --user 'client_id:client_secret' https://www.reddit.com/api/v1/access_token
This curl command sends the data as the form data. And, the basic authorization is used. When these are reflected to the Google Apps Script, it becomes as follows.
Sample script:
In this script, your values are used.
function main() {
var username = 'myredditusername';
var pwd = 'myredditpassword';
var client_id = 'myredditclientid';
var client_secret = 'myredditclientsecret';
var access_token_url = 'https://www.reddit.com/api/v1/access_token';
var data = {
'grant_type': 'password',
'username': username,
'password': pwd
};
var options = {
'method': 'post',
'payload': data,
'headers': {
'Authorization': 'Basic ' + Utilities.base64Encode(`${client_id}:${client_secret}`),
},
};
var resp = UrlFetchApp.fetch(access_token_url, options);
console.log(JSON.parse(resp.getContentText()));
}
At this script, the request is same with the curl command.
Note:
In this script, it supposes that the values for authorizating are correct. Please be careful this.
Reference:
fetch(url, params)
I am very new to APIs. I have successfully built an API in postman and got the data I wanted. I generated the code sample provided by postman in JavaScript format:
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
myHeaders.append("Authorization", "Basic ZGVhbGdwwitpflgnBvcnQ6ZldZUmZvVEU5a2hNaFZtUlBlcU1VZ3J5eFRhWXBwN0U3d1hdllBZw==");
var urlencoded = new URLSearchParams();
urlencoded.append("grant_type", "password");
urlencoded.append("username", "123456789");
urlencoded.append("password", "password123!");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
};
fetch("https://accounts.kernel.com/oidc/token", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
However, I want to build this API in google scripts using the function UrlFetchApp. So far I am doing this:
function webRelay(){
var url = 'https://accounts.autoscout24.com/oidc/token';
var username = "123456789";
var password = "password123!";
var headers =
{
"Content-Type" : "application/x-www-form-urlencoded" ,
"Authorization" : "Basic ZGVhbGdwwitpflgnBvcnQ6ZldZUmZvVEU5a2hNaFZtUlBlcU1VZ3J5eFRhWXBwN0U3d1hdllBZw=="
}
var options =
{
"grant_type" : "password",
"timeout": 0,
"method" : "post",
"headers": headers
};
// Getting "bad request" here - check the username & password
var result = UrlFetchApp.fetch(url, options);
var state=result.getContentText();
}
But I get the following error:
Request failed for https://accounts.kernel.com returned code 400.
Truncated server response: {"error":"invalid_request"} (use
muteHttpExceptions option to examine full response) (line 22, file
"api")
You want to convert the Javascript in your question to Google Apps Script.
You have already confirmed that your Javascript worked.
I could understand like above. For this, how about the following modification?
Modification points:
In options of UrlFetchApp.fetch(url, options), there are no properties ofgrant_typeandtimeout`.
When your Javascript is seen, the data is sent as the form data.
Default "Content-Type" of UrlFetchApp is application/x-www-form-urlencoded.
In your script, username is not used.
When above points are reflected to the script, it becomes as follows.
Modified script:
Before you use the modified script, please set the variables of username, password and headers.
function webRelay(){
var url = 'https://accounts.autoscout24.com/oidc/token';
var username = "123456789";
var password = "password123!";
var payload = {
"grant_type": "password",
"password": password,
"username": username
}
var headers = {"Authorization" : "Basic ###"};
var options = {
"method" : "post",
"headers": headers,
"payload": payload,
};
var result = UrlFetchApp.fetch(url, options);
var state = result.getContentText();
Logger.log(state)
}
In this modified script, your token was removed using ###. When you use this, please modify it.
Reference:
Class UrlFetchApp
Although I think that the request ob above modified script is the same with your Javascript. But unfortunately, I cannot test above script. I apologize for this. So if this didn't work for your situation, I apologize.
I would like to connect with the Stripe API using a https call using the https library.
var https = require('https');
I have gotten the secret key and publishable key and put it inside a object:
var stripe = {
secret_key: 'secret_key_given_in_the_dashboard',
publishable_key: 'publishable_key_given_in_the_dashboard'
}
I am now in the part of creating the requestDetail object:
var requestDetails = {
'protocol' : 'https:',
'hostname' : 'api.stripe.com',
'method' : 'POST', //WHICH OF POST GET PUT DELETE SHOULD I USE?
'path' : '???????????????????????',// WHICH ENDPOINT SHOULD I USE?
'auth' : '???????????????????????',// SHOULD I USE THE SECRET AND PUBLISHABLE KEY HERE?
'headers' : {
'Content-Type' : 'application/x-www-form-urlencoded',
'Content-Length' : Buffer.byteLength(stringPayload)
}
};
I plan to make use of the requestDetails object in the call using https:
var req = https.request(requestDetails, function(res){
// Grab the status of the sent request
var status = res.statusCode;
//Callback successfully if the request went through
if(status == 200 || status == 201) {
callback(false);
} else {
callback('Status code returned was ' + status);
}
});
Where and how should I use the secret key and publishable key in order to make a call to the stripe API?
Which endpoint?
Which method (POST, GET, PUT,or DELETE)?
I would like to eventually create a order and pay through the STRIPE api.
But for now just any authenticated call through the stripe api will do as I need a sample format that works....
I'm not too sure where to add the secret key and publishable key....
You should install official stripe package (source: https://github.com/stripe/stripe-node), require the package and authenticate it using your secret key ( example from the github docs):
const stripe = require('stripe')('your_stripe_secret_key');
stripe.customers.create({
email: 'customer#example.com',
})
.then(customer => console.log(customer.id))
.catch(error => console.error(error));
The package is an abstraction to make the API requests for you.
More docs: https://stripe.com/docs/api?lang=node
However, if you want to use the https directly for Stripe API requests, which is not recommended, you can check the docs and examples for using the cURL, since it shows the endpoints for each example.
https://stripe.com/docs/api/authentication?lang=curl
try using fetch, 'Authorization': 'Bearer ' + sk.
My working example of retrieving a customer based on the customer_id:
const url = `https://api.stripe.com/v1/customers/${stripe_customer_id}`;
return await fetch(url, {
method: "get",
headers: {
"Content-Type": "application/json",
'Authorization': 'Bearer ' + sk,
}
})
.then(function(response) {
return response.json();
})
.then(function(response) {
// console.log(response);
return response;
});
};
I'm trying to connect to my VSTS build 2.0 api through Node to create a new build definition. I'm getting HTTP 302 , which is an redirect. I'm not sure why this happening, I was able to submit same request, with same URL through SOAP UI without any issue. Below is the code snippet.
var Client = require('node-rest-client').Client;
var client = new Client();
var accessToken = 'MY ACCESS TOKEN';
var args = {
data: JSON.stringify(configJSON),
headers: {
"Content-Type": "application/json",
"Accept": "application/json"}
,auth: {
'bearer': accessToken
}
};
client.post("https://firstname.lastname.visualstudio.com/SampleApp/_apis/build/definitions?api-version=2.0", args, function (data, response) {
console.log(response.statusCode);
}).on('error', function (err) {
console.log('something went wrong on the request', err);
});
The reason is that the authentication is failed, so it redirects to the login page, that's why you get the 302 response code.
I modify the code to add Authorization to header and remove auth parameter, after that it works fine.
var args = {
data: JSON.stringify(configJSON),
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer " + accessToken
}
//, auth: {
// "Bearer":accessToken
//}
};
On the other hand, I suggest that you can create build definition through vsts-node-api or PowerShell.
For VSTS-node-api, there is createDefinition function in BuildApi (xxx), there is a sample about how to use it.
For PowerShell, you can use Invoke-RestMethod to call REST API, there are some samples in this article.