I managed to do the API POST request through Postman but once modified for Google App Script it doesn't work. I think it might be related to the body format, I can't replicate the new URLSearchParams() object in GAS (I'm sending a JSON I believe).
Thanks.
Postman (working) - JavaScript Fetch
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("client_id", "XXXX");
urlencoded.append("client_secret", "XXXX");
urlencoded.append("grant_type", "client_credentials");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
};
fetch("https://apigateway.criteo.com/oauth2/token", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
CURL
curl --location --request POST 'https://apigateway.criteo.com/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=XXXX' \
--data-urlencode 'client_secret=XXXX' \
--data-urlencode 'grant_type=client_credentials'
My faulty GAS version :(
function getCostAU() {
var myHeaders = {"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"};
var myPayload = {"client_id" : "XXXX",
"client_secret" : "XXXX",
"grant_type" : "client_credentials"};
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: myPayload,
redirect: 'follow',
};
var url = "https://apigateway.criteo.com/oauth2/token";
var result = JSON.parse(UrlFetchApp.fetch(url, requestOptions).getContentText());
var access_token = result.access_token;
};
Issues:
body is not a valid key in options argument. You should use payload instead.
redirect is not a valid key in options argument
Currently, URLSearchParams is not supported in apps script.
Solution:
Change body to payload
Re-create the payload object as a query string. For example, payload:{x:1,y:2} should be changed to x=1&y=2.
Snippet:
Payload object to query params:
function objectToQueryParams(obj) {
return (
Object.entries(obj)
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
.join('&')
);
}
const myPayload = {"client_id" : "XXXX",
"client_secret" : "XXXX",
"grant_type" : "client_credentials"};
console.log(objectToQueryParams(myPayload));
Valid requestOption:
const requestOptions = {
/**#see https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#fetch(String,Object)*/
method: 'POST',
headers: myHeaders,
payload: objectToQueryParams(myPayload),//modified
//or just payload: myPayload will work as mentioned in the comments below
//redirect: 'follow',//removed
followRedirects: true
};
Full script:
/**Mock UrlFetchApp library*/
const UrlFetchApp = {
fetch: () => ({
getContentText: () =>
'{"access_token":"jghlfdjlfwqwXjogsfshbkgetrwuguerjyrcyfxuux=="}',
}),
};
getCostAU(); //call function
//Mock end
function getCostAU() {
const myHeaders = {
Accept: 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
};
const myPayload = {
client_id: 'XXXX',
client_secret: 'XXXX',
grant_type: 'client_credentials',
};
function objectToQueryParams(obj) {
return Object.entries(obj)
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
.join('&');
}
const requestOptions = {
/**#see https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#fetch(String,Object)*/
method: 'POST',
headers: myHeaders,
payload: objectToQueryParams(myPayload), //modified
//or just payload: myPayload will work as mentioned in the comments below
//redirect: 'follow',//removed
followRedirects: true,
};
const url = 'https://apigateway.criteo.com/oauth2/token';
const result = JSON.parse(
UrlFetchApp.fetch(url, requestOptions).getContentText()
);
const access_token = result.access_token;
console.log(access_token);
}
Answer: just changing the body to payload was enough.
function objectToQueryParams(obj) {
return (
Object.entries(obj)
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
.join('&')
);
}
const myPayload = {"client_id" : "XXXX",
"client_secret" : "XXXX",
"grant_type" : "client_credentials"};
console.log(objectToQueryParams(myPayload));
Related
I want to automate the api using Cypress, but I can't access the response body.
Use this path cy.log(JSON.stringify(response.body.payload[0]
Api Response
Code
context('GET /Auth', () => {
it('should return a list with all products', () => {
cy.request({
method: 'GET',
url: 'https://auth.plus.a101.com.tr/api/homepage/punch-cards/20149126',
headers: {
'Authorization' : 'Bearer ' + access_token
}
})
.then((response) => {
expect(response.status).to.eq(200)
cy.log(JSON.stringify(response.body.payload[0]))
});
});
});
I get error
You have to convert your response object a json string and then parse it. Instead you can try the following:
cy.request({
method: 'GET',
url: 'https://auth.plus.a101.com.tr/api/homepage/punch-cards/20149126',
headers: {
'Authorization' : 'Bearer ' + access_token
}
}).then((response) => {
response = JSON.stringify(response)
var jsonData = JSON.parse(response)
cy.log(response.body.payload[0])
});
I'm trying send a post request using axios to my backend but I can't send the boolean "isActive" for some reason. Is there a way to do this?
async submit() {
const isValid = await this.$validator.validateAll()
if (isValid && !this.submitting) {
let formData = new FormData();
formData.set("city", this.formData.city)
formData.set("state", this.formData.state)
formData.set("county", this.formData.county)
formData.set("isActive", true) // <- NOT ACCEPTING THIS VALUE
axios.post("/api/v1/team/createTeam", formData, {
headers: {
'Content-Type': 'application/json'
}
})
.then(res => {
if (res.status === 200) {
this.submitting = true
this.cancelModal()
} else {
console.log(res.data.code);
}
})
.catch(function (err) {
console.log(err);
})
}
}
FormData can only contain string values. Setting a Boolean true would result in "true" for the value. The backend would have to convert that string to a Boolean.
Also, your header should not be application/json (intended for JSON payloads). If sending FormData as the payload, the header should be multipart/form-data:
axios.post("/api/v1/team/createTeam", formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
If your backend is actually expecting JSON, then you can't send FormData. Switch to a JavaScript object instead (which does accept Booleans):
const payload = {
city: this.formData.city,
state: this.formData.state,
county: this.formData.county,
isActive: true,
}
axios.post("/api/v1/team/createTeam", payload, {
headers: {
'Content-Type': 'application/json'
}
})
As i am trying to send my data in form of body in backed url as in backed i have made something if it dont receive body it will send sucess: false, msg: haven't received body else sucess: true, msg: jwt token as if i make request from post man with same data it's working but sending via. native app it fails to send.. any help will be helpfull
As 1st request is from postman and 2nd from my app
const handleLogin = (Enrno, Pass) => {
setError(null);
setIsLoaded(false);
setItems([]);
fetch(config.url + "/login", {
method: "POST",
header : {
Accept : 'application/json',
'Content-Type' : 'application/json'
},
body : JSON.stringify({
"enrno": Enrno,
"password" : Pass
})
})
.then((res) => res.json())
.then(
(result) => {
setIsLoaded(true);
setItems(result);
alert(items[0].msg);
},
(error) => {
setIsLoaded(true);
setError(error);
}
);
};
I think you need to put these to headers, not header.
Accept : 'application/json',
'Content-Type' : 'application/json'
So, it should look like this.
fetch(config.url + "/login", {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
enrno: Enrno,
password : Pass
})
})
I am waiting for successful JSON from server:
{"...."}
Actual Behavior
I get
SyntaxError: Unexpected token b in JSON at position 0
b is the first letter of word "badlogin". It responds server when sent wrong combination of userName and password. But when I use Postman with the same key values combination on the same address I get correct rosponse from the server.
Steps to Reproduce
fetch('http://....', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
userName: "react",
password: "123",
})
}).then((response) => response.json())
.then((responseJson) => {
console.log(responseJson.message);
if(responseJson.success === true) {
alert('successufuly loged');
}
else{
console.log(responseJson.message);
alert(responseJson.message);
}
})
}
}
You are trying to parse a string. This is the error. Instead of always parse the json, just add a clausule to check if the request was made with success
}).then((response) => {
if(!response.ok) {
// handle your error here and return to avoid to parse the string
return
}
return response.json()
})
.then()
Look like the response you got is not json
Try to check what is the response you are getting first:
.then((response) => response.text())
.then((responseJson) => {
console.log(responseJson);
}
I solved this issue by using FormData to prepare data for sending:
......
login = () => {
var formData = new FormData();
formData.append('username', 'react');
formData.append('password', '123');
fetch('http://......', {
method: 'POST',
body: formData
........
I am trying to obtain the access token for Yelp's API.
Yelp's API documentation:
https://www.yelp.com/developers/documentation/v3/get_started
I keep running into the error below on my terminal:
problem with request: getaddrinfo ENOTFOUND api.yelp.com/oauth2/token api.yelp.com/oauth2/token:80
Here's my NodeJS code (I took a lot of it from the Node Documentation site):
var http = require("http");
var postData = JSON.stringify({
"grant_type": "client_credentials",
"client_id": "<<client id>>",
"client_secret": "<<client secret no.>>"
});
var options = {
hostname: 'api.yelp.com/oauth2/token',
port: 80,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
var req = http.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.');
});
});
req.on('error', (e) => {
console.log(`problem with request: ${e.message}`);
});
// write data to request body
req.write(postData);
req.end();
Two items that caught my eye:
Separate the hostname and the path in your options variable.
The YELP Fusion API is HTTPS, not HTTP. Using HTTP may result in a 302 response (URL Redirection).
var https = require('https');
getYelpAccessCode(function(response) {
var responseData = JSON.parse(response);
if (responseData != null) {
var accessCode = responseData.token_type + " " + responseData.access_token;
}
});
function getYelpAccessCode(callback) {
const postData = querystring.stringify({
'client_id': YELP_CLIENT_ID,
'client_secret': YELP_CLIENT_SECRET
});
const options = {
hostname: 'api.yelp.com',
path: '/oauth2/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = https.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
var body = '';
res.setEncoding('utf8');
res.on('data', (chunk) => {
body += chunk;
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.');
callback(body);
});
});
req.on('error', (e) => {
console.error(`problem with request: ${e.message}`);
});
// write data to request body
req.write(postData);
req.end();
}