Query for Spotify's Web API Client Credentials Flow - javascript

I'm trying to make a http request based on the documentation at https://developer.spotify.com/documentation/general/guides/authorization-guide/#client-credentials-flow Client Credentials Flow.
I've written
const BASE_URL = 'https://accounts.spotify.com/api/token';
fetch(BASE_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + base64(clientID) + ':' + base64(clientSecret)
},
body: JSON.stringify({'grant_type:client_credentials'})
})
Does this follow what it says to do? I'm confused how to write the body of the post request.

What I ended up doing which works:
async authorize(){
let myHeaders = new Headers();
myHeaders.append("Authorization", `Basic ${my_clientID:clientSecret}`);
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("grant_type", "client_credentials");
const requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
}
let res = await fetch("https://accounts.spotify.com/api/token", requestOptions);
res = await res.json();
return res.access_token;
}
async search(){
const access_token = await this.authorize();
this.setState({access_token});
const BASE_URL = 'https://api.spotify.com/v1/search';
let FETCH_URL = `${BASE_URL}?q=${this.state.query}&type=artist&limit=1`;
const ALBUM_URL = 'https://api.spotify.com/v1/artists';
let myHeaders = new Headers();
myHeaders.append("Authorization", `Bearer ${access_token}`);
const requestOptions = {
method: 'GET',
headers: myHeaders
}
let res = await fetch(FETCH_URL, requestOptions);
res = await res.json();
console.log("ARTIST", res);
}

From the link you have shared, the client credential flow is a client (server-side) that makes a request to the spotify API server. Thus, it is a server-to-server authentication flow (not authorization). You are using the fecth API which is client-side so that means that your implementation should be server-side. If you are using a node.js runtime server-side framework, just look up the http.request API to make a request server-side.
For example, this would be a pure node.js implementation:
const options = {
hostname: 'https://accounts.spotify.com/api/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + base64(clientID) + ':' + base64(clientSecret)
}
};
const req = http.request(options, (res) => {
res.setEncoding('utf8');
// process the data bit by bit or in chunks...
res.on('data', (chunk) => {});
// ...and do something with it when there is no more data in response
res.on('end', () => {
console.log('No more data in response.');
});
});
// handle the error explicitly
req.on('error', (e) => {
console.error(`problem with request: ${e.message}`);
});
req.end();

For me, I'm not sure if this is the case for anyone else, but the spotify api was refusing base64(clientID) + ":" + base64(clientKey), but accepting base64(clientID + ":" + clientKey)

Related

Spotify API returning data with Javascript/ React

I'm currently trying to incorporate Spotify's API into my project but I'm having problems fetching the data.
My token is returned in the console which is great but my call to return some data doesn't work.
I'm getting an error :
error:
message: "Only valid bearer authentication supported"
status: 400
[[Prototype]]: Object
[[Prototype]]: Object
Here's what I have so far. Maybe its a simple fix.
// Token
const CLIENT_ID = 'HIDDEN';
const CLIENT_SECRET = 'HIDDEN';
let authParameters = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'grant_type=client_credentials&client_id=' + CLIENT_ID + '&client_secret=' + CLIENT_SECRET
}
async function getToken() {
let myToken = await fetch('https://accounts.spotify.com/api/token', authParameters)
let tokenReturn = await myToken.json()
console.log(tokenReturn.access_token)
}
// Request
async function searchData() {
const baseUrl = 'https://api.spotify.com/v1/browse/new-releases';
let ArtistParameters = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + tokenReturn
},
}
let artistID = await fetch(baseUrl, ArtistParameters)
let artistList = await artistID.json()
console.log(artistList);
}
useEffect(() => {
getToken()
searchData()
}, [])

Error when using multiple fetch requests in Zapier

I tried to find a solution online and on stackoverflow but i think the answers from the other posts focus on other things.
My problem is the error when i try to fetch more then 1 Hubspot api call.
The error message:
body used already for: https://api.hubapi.com/crm/v3/objects/deals?limit=100&archived=false
(returns list of deals)
var data = [];
let Timestamp = new Date().toISOString();
let Webhook = inputData.Webhook.trim();
let Method = inputData.Method.trim();
let JSONObject = {}
let Options = {
method: Method,
headers: {
'Authorization': `Bearer Hidden Key`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(JSONObject)
}
const Request = await fetch(Webhook, Options); // HTTP POST Request
const Response = await Request.json() // HTTP POST Response
data.push(Response);
Response.push(await Request.json());
let Webhook2 = Response.paging.next.link;
if ('paging' in Response) {
for (let i = 0; i < 10; i++) {
if (Webhook2 != "") {
let Options2 = {
method: Method,
headers: {
'Authorization': `Bearer Hidden Key`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(JSONObject)
}
const Request2 = await fetch(Webhook2, Options2); // HTTP POST
const Response2 = await Request2.json();
data.push(Response2);
if ('paging' in Response2) {
let Webhook2 = Response2.paging.next.link;
} else {
let Webhook2 = "";
}
}
}
}
output = data;
If someone could help me with this error i would really appriciate it.
Thanks in advance people.

Why is axios not returning correctly

I am trying to replace a fetch with axios. I keep getting undefined in my console log.
async componentDidMount() {
console.log('app mounted');
const tokenString = sessionStorage.getItem("token");
const token = JSON.parse(tokenString);
let headers = new Headers({
"Accept": "application/json",
"Content-Type": "application/json",
'Authorization': 'Bearer ' + token.token
});
const response = await axios({
method: 'get',
url: Config.apiUrl + `/api/Orders/GetAllInvoices`,
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
'Authorization': 'Bearer ' + token.token }
});
console.log(`axios: ${response.json}`)
this.setState({ invoiceList: response.json });
//const response = await fetch(Config.apiUrl + `/api/Orders/GetAllInvoices`, {
// method: "GET",
// headers: headers
//});
//const json = await response.json();
//console.log(json);
//this.setState({ invoiceList: json });
...
... the commented out fetch is working. I just now added the .json even though axios should not need it. Neither way works. What am I doing wrong?
Did you even console.log(response) just to see whats inside of it?
I guess you dont, because response is an object witch has no json key in it. You should use response.data

Javascript node-fetch usage

I can get the data by request from this code.
let request = require('request');
let options = {
'method': 'POST',
'url': 'https://example.com/api',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
'client_id': '12345678',
'client_secret': 'abcdefg'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
However, I got '404.00.001' when I use "fetch" to access the same API. Is there any thing wrong in this code?
const fetch = require("node-fetch");
const url = "https://example.com/api";
var headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
var data = JSON.stringify( {
'client_id': '12345678',
'client_secret': 'abcdefg'
});
fetch(url, {method: 'POST', headers: headers, body: data})
.then(response => response.json())
.then((resp) => {
console.log(resp);
})
.catch(error => console.error('Unable to fetch token.', error));
'Content-Type': 'application/x-www-form-urlencoded' does not say JSON so why do you have var data = JSON.stringify?
The documentation tells you how to encode data as form parameters.
const { URLSearchParams } = require('url');
const params = new URLSearchParams();
params.append('a', 1);

How can I check a fetch response to call another one?

I trying to get a download of a json file from an API.
To do that, I need to call 3 endpoints.
http://url.com/export
it returns a json: {"exportLoading":true,"file":"export-20190618-183316.json"}
After that I should call the second endpoint and check the status of this exportation:
http://url.com/export/status
it returns true or false (while server is processing, this endpoint returns true. When it returns false the file is done to make a download.)
So, if the status === false, I can call the last endpoint
http://url.com/download/file_name (I make this request passing the file name - returned from the first request - to download the file.
My question is, how can I check if the second endpoint returns false to make the last request and download the file?
I just did it until the second endpoint.
app.get('/export', function (req, res, next) {
global.fetch = fetch
global.Headers = fetch.Headers;
const headers = new Headers();
const username = 'user';
const password = 'pass';
const URL = 'http://url.com/export'
headers.set('Authorization', 'Basic ' + base64.encode(username + ":" + password));
fetch(URL, {
method: 'GET',
headers: headers,
})
.then(res => res.json())
.then(json => {
fetch("http://url.com/exportl/status", {
method: 'GET',
headers: headers,
}).then(result => ...)
})
.catch(function (error) {
console.log(error)
})
});
You could use a while loop that will call the endpoint until the condition is met:
app.get('/export', async function(req, res, next) {
global.fetch = fetch
global.Headers = fetch.Headers;
const headers = new Headers();
const username = 'user';
const password = 'pass';
const URL = 'http://url.com/export'
headers.set('Authorization', 'Basic ' + base64.encode(username + ":" + password));
fetch(URL, {
method: 'GET',
headers: headers,
}).then(r => r.json)
.then(data => {
// use data here
var status = false
while (!status) {
status = await checkStatus()
}
// third call
})
});
function checkStatus() {
return fetch("http://url.com/exportl/status", {
method: 'GET',
headers: headers,
}).then(r => r.json)
}
Note, I do not know the response from the status, you will have to change the code to accommodate the response.

Categories