How to do Spotify Api Post Request using Axios - javascript

I'm trying to add a song to the playback queue using this endpoint:
const add = async () => {
try {
const url = `https://api.spotify.com/v1/me/player/queue?uri=${songUrl}&device_id=${deviceId}`
await axios.patch(url, {
headers: {
Authorization: `Bearer ${to}`
},
})
} catch (error) {
console.log(error);
}
}
I'm getting a status 401 error with a message that says no token provided. But when I console.log the token it shows up.

I haven't worked with the Spotify API yet, however, according to their docs, you need to send a POST request, not a PATCH, which is what you used.
Use axios.post() instead of axios.patch():
const add = async (songUrl, deviceId, token) => {
try {
const url = `https://api.spotify.com/v1/me/player/queue?uri=${songUrl}&device_id=${deviceId}`;
await axios.post(url, {
headers: {
Authorization: `Bearer ${token}`,
},
});
} catch (error) {
console.log(error);
}
};

The second param of your post request should be body and the third param should be headers. Also, you haven't added all the headers as mentioned in the documentation.
headers: {
Accept: 'application/json',
Authorization: 'Bearer ' + newAccessToken,
'Content-Type': 'application/json',
}
Get your access token from here: https://developer.spotify.com/console/post-queue/
If it still doesn't work try the curl method as mentioned in their docs and if it works, switch it to axios.

I had the exact same issue as you, what I realised was I was passing the header as data rather than as config. This code below should work for you as it works for me.
const add = async () => {
try {
const url = `https://api.spotify.com/v1/me/player/queue?uri=${songUrl}&device_id=${deviceId}`
await axios.post(url, null,{
headers: {
Authorization: `Bearer ${to}`
},
})
} catch (error) {
console.log(error);
}
}

Related

What should I do to fix this error when sending the form to the server?

have a good time! I use axios to send a post request to the api http://freerealapi.com/ I work based on the document but it gives me an error 400 What should I do?
const buildDiscount = async token => {
let data = new FormData();
data.append('title', keyCodes);
data.append('text', 'test text');
data.append('image', file);
data.append('tags', 'one,two,three');
try {
const res = await axios.post('https://api.freerealapi.com/panel/blogs/', data, {
headers: {
'Content-Type': 'multipart/form-data',
Authorization: `Bearer ${token}`,
},
})
console.log(res.data);
} catch (error) {
console.log(error.response);
}
}
This function is most probably missing those 2 extra variables ( keyCodes, file ), can you provide those inputs to the function? That's probably the reason why the request is being malformed.

Spotify Web API / Next.js: Only getting data from one end-point

I'm pretty new to working with API's, and I'm currently trying to fetch some data from the Spotify API in a Next.js website.
The problem is that the only end-point that gives me any data is the 'top-tracks': (https://api.spotify.com/v1/me/top/tracks), all the other end-points I've tried gives this error:
Request failed FetchError: invalid json response body at https://api.spotify.com/v1/me/player/recently-played reason: Unexpected token U in JSON at position 0
This is the function I'm using to fetch data from the API:
const basic = Buffer.from(`${client_id}:${client_secret}`).toString("base64");
const TOKEN_ENDPOINT = `https://accounts.spotify.com/api/token`;
export default async function handler(req, res) {
const response = await fetch(TOKEN_ENDPOINT, {
method: "POST",
headers: {
Authorization: `Basic ${basic}`,
"Content-Type": "application/x-www-form-urlencoded",
},
body: querystring.stringify({
grant_type: "refresh_token",
refresh_token,
}),
})
.then((response) => response.json())
.then((data) => {
const access_token = data.access_token;
return fetch(`https://api.spotify.com/v1/me/player/recently-played`, {
method: "GET",
headers: {
Authorization: `Bearer ${access_token}`,
},
});
})
.then((response) => response.json())
.catch((err) => {
console.error("Request failed", err);
});
return res.status(200).json(response);
}
(First getting the access token, using clientId and secret from env-variables, then fetching data from API using said token)
Any idea of what I'm doing wrong here? All help is greatly appreciated :)
Also:
I've added the necessary scopes, so I should have permisssion to get the data!

"grant_type parameter is missing": Spotify API PKCE OAuth Flow Troubles

I'm developing a React app that uses the Spotify API I can't figure out why I'm getting this error when trying to get an access token with the API's PKCE OAuth flow.
{
error: "unsupported_grant_type",
error_description: "grant_type parameter is missing"
}
I'm following the directions from the guide exactly and I'm able to obtain an auth code just fine. Here's my call trying to get the token.
let res = await axios.post("https://accounts.spotify.com/api/token", {}, {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
params: {
"grant_type": "authorization_code",
"code": data.code,
"redirect_uri": redirectUri,
"code_verifier": verifier,
"client_id": clientId
}
}).catch(err => console.error(err));
I've tried passing the params in the body of the post request and as url params and both produce the same results. As you can see, I'm clearly providing a grant_type and I'm using the value that the guide said to use.
I've tried every method I was able to find on the internet, nothing seemed to be working, but after a few hours, this succeeded:
const headers = {
Authorization:
'Basic ' +
new Buffer(CLIENT_ID + ':' + CLIENT_SECRET).toString('base64'),
}
const { data } = await axios.post(
'https://accounts.spotify.com/api/token',
'grant_type=client_credentials',
headers: { headers },
)
this.token = data.access_token
After this, you can simply use any endpoint as seen in the Spotify API examples.
Use querystring npm package to parse the data since we're using application/x-www-form-urlencoded in the header
And change the grant_type to grant_type: "client_credentials"
var querystring = require('querystring');
const headers = {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
}
};
let data = {
grant_type: "client_credentials",
code: data.code,
redirectUri: "http://localhost:8000/callback",
client_id: your_client_id,
client_secret: your_client_secret,
};
we use query.stringify() for the data because the content type is application/x-www-form-urlencoded also don't use params since its a post request
axios
.post(
"https://accounts.spotify.com/api/token",
querystring.stringify(data),
headers
)
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
This works for me:
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization:
'Basic ' +
Buffer.from(this.clientId + ':' + this.clientSecret).toString('base64'),
};
this.http.post(
'https://accounts.spotify.com/api/token',
'grant_type=client_credentials',
{ headers },
).subscribe(data => {
console.log(data);
});
I have the same issue, and it's resolved with stringfying request body data
const requestAccessToken = ({
code,
grantType = "authorization_code",
redirectUri = `${APP_BASE_URL}/callback`,
}) => {
const data = qs.stringify({ //query-string library
code,
grant_type: "client_credentials",
redirect_uri: redirectUri,
});
return axios.post(
[SPOTIFY_ACCOUNTS_BASE_URL, SPOTIFY_ACCOUNTS_TOKEN_URI].join(""),
data,
{
headers: {
Authorization: `Basic ${Buffer.from(
`${SPOTIFY_CLIENT_ID}:${SPOTIFY_CLIENT_SECRET}`,
).toString("base64")}`,
"Content-Type": "application/x-www-form-urlencoded",
},
},
);
};
Have you traced the message and verified that the request body is definitely as expected? Your OAuth fields look totally correct so I suspect this could just be an axios syntax issue.
I could be wrong but should the 'params' field be called 'data' instead, as in this class of mine.

React - GET and POST requests with axios

In my application I need to GET some data (for which I provide the native authtoken).
In the same event, however, I also need to POST a second token to be consumed by a few endpoints, for external backend api calls.
How do I POST this second token using my working code below using axios?
Should I extend Authorization bearer or simply POST Spotify Token as string data?
How so?
My code:
getData(event) {
const {token} = this.props.spotifyToken
const options = {
url: `${process.env.REACT_APP_WEB_SERVICE_URL}/endpoint`,
method: 'get',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${window.localStorage.authToken}`
}
};
return axios(options)
.then((res) => {
console.log(res.data.data)
})
.catch((error) => { console.log(error); });
};
For an async await applied to your code would look something like this.
async getData(event) {
const {token} = this.props.spotifyToken
let getRes = await axios.get(`${process.env.URL}/endpoint` {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${window.localStorage.authToken}`
}
}
let postRes = await axios.post(`${process.env.URL}/endpoint` {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${window.localStorage.authToken}`
}
}
console.log(getRes.data.data);
console.log(postRes.data.data);
};
In this specific case, where a token is needed to fetch data at backend, I found that passing token at url is more suitable, like so:
#endpoint.route('/endpoint/<select>/<user_id>/<token>', methods=['GET'])
def endpoint(name, user_id, token):
# business logic
and:
const options = {
url: `${process.env.REACT_APP_WEB_SERVICE_URL}/endpoint/${select}/${userId}/${this.props.spotifyToken}`,
method: 'get',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${window.localStorage.authToken}`
}
};
otherwise, backend code would run twice, for POST and GET, which is not desired in my case.

How to post file data to Gitlab project using JavaScript fetch [duplicate]

I'm trying to POST a JSON object using fetch.
From what I can understand, I need to attach a stringified object to the body of the request, e.g.:
fetch("/echo/json/",
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: "POST",
body: JSON.stringify({a: 1, b: 2})
})
.then(function(res){ console.log(res) })
.catch(function(res){ console.log(res) })
When using jsfiddle's JSON echo I'd expect to see the object I've sent ({a: 1, b: 2}) back, but this does not happen - chrome devtools doesn't even show the JSON as part of the request, which means that it's not being sent.
With ES2017 async/await support, this is how to POST a JSON payload:
(async () => {
const rawResponse = await fetch('https://httpbin.org/post', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({a: 1, b: 'Textual content'})
});
const content = await rawResponse.json();
console.log(content);
})();
Can't use ES2017? See #vp_art's answer using promises
The question however is asking for an issue caused by a long since fixed chrome bug.
Original answer follows.
chrome devtools doesn't even show the JSON as part of the request
This is the real issue here, and it's a bug with chrome devtools, fixed in Chrome 46.
That code works fine - it is POSTing the JSON correctly, it just cannot be seen.
I'd expect to see the object I've sent back
that's not working because that is not the correct format for JSfiddle's echo.
The correct code is:
var payload = {
a: 1,
b: 2
};
var data = new FormData();
data.append( "json", JSON.stringify( payload ) );
fetch("/echo/json/",
{
method: "POST",
body: data
})
.then(function(res){ return res.json(); })
.then(function(data){ alert( JSON.stringify( data ) ) })
For endpoints accepting JSON payloads, the original code is correct
I think your issue is jsfiddle can process form-urlencoded request only. But correct way to make json request is pass correct json as a body:
fetch('https://httpbin.org/post', {
method: 'POST',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: JSON.stringify({a: 7, str: 'Some string: &=&'})
}).then(res => res.json())
.then(res => console.log(res));
From search engines, I ended up on this topic for non-json posting data with fetch, so thought I would add this.
For non-json you don't have to use form data. You can simply set the Content-Type header to application/x-www-form-urlencoded and use a string:
fetch('url here', {
method: 'POST',
headers: {'Content-Type':'application/x-www-form-urlencoded'}, // this line is important, if this content-type is not set it wont work
body: 'foo=bar&blah=1'
});
An alternative way to build that body string, rather then typing it out as I did above, is to use libraries. For instance the stringify function from query-string or qs packages. So using this it would look like:
import queryString from 'query-string'; // import the queryString class
fetch('url here', {
method: 'POST',
headers: {'Content-Type':'application/x-www-form-urlencoded'}, // this line is important, if this content-type is not set it wont work
body: queryString.stringify({for:'bar', blah:1}) //use the stringify object of the queryString class
});
After spending some times, reverse engineering jsFiddle, trying to generate payload - there is an effect.
Please take eye (care) on line return response.json(); where response is not a response - it is promise.
var json = {
json: JSON.stringify({
a: 1,
b: 2
}),
delay: 3
};
fetch('/echo/json/', {
method: 'post',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: 'json=' + encodeURIComponent(JSON.stringify(json.json)) + '&delay=' + json.delay
})
.then(function (response) {
return response.json();
})
.then(function (result) {
alert(result);
})
.catch (function (error) {
console.log('Request failed', error);
});
jsFiddle: http://jsfiddle.net/egxt6cpz/46/ && Firefox > 39 && Chrome > 42
2021 answer: just in case you land here looking for how to make GET and POST Fetch api requests using async/await or promises as compared to axios.
I'm using jsonplaceholder fake API to demonstrate:
Fetch api GET request using async/await:
const asyncGetCall = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
const data = await response.json();
// enter you logic when the fetch is successful
console.log(data);
} catch(error) {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
}
}
asyncGetCall()
Fetch api POST request using async/await:
const asyncPostCall = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
});
const data = await response.json();
// enter you logic when the fetch is successful
console.log(data);
} catch(error) {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
}
}
asyncPostCall()
GET request using Promises:
fetch('https://jsonplaceholder.typicode.com/posts')
.then(res => res.json())
.then(data => {
// enter you logic when the fetch is successful
console.log(data)
})
.catch(error => {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
})
POST request using Promises:
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
})
.then(res => res.json())
.then(data => {
// enter you logic when the fetch is successful
console.log(data)
})
.catch(error => {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
})
GET request using Axios:
const axiosGetCall = async () => {
try {
const { data } = await axios.get('https://jsonplaceholder.typicode.com/posts')
// enter you logic when the fetch is successful
console.log(`data: `, data)
} catch (error) {
// enter your logic for when there is an error (ex. error toast)
console.log(`error: `, error)
}
}
axiosGetCall()
POST request using Axios:
const axiosPostCall = async () => {
try {
const { data } = await axios.post('https://jsonplaceholder.typicode.com/posts', {
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
// enter you logic when the fetch is successful
console.log(`data: `, data)
} catch (error) {
// enter your logic for when there is an error (ex. error toast)
console.log(`error: `, error)
}
}
axiosPostCall()
I have created a thin wrapper around fetch() with many improvements if you are using a purely json REST API:
// Small library to improve on fetch() usage
const api = function(method, url, data, headers = {}){
return fetch(url, {
method: method.toUpperCase(),
body: JSON.stringify(data), // send it as stringified json
credentials: api.credentials, // to keep the session on the request
headers: Object.assign({}, api.headers, headers) // extend the headers
}).then(res => res.ok ? res.json() : Promise.reject(res));
};
// Defaults that can be globally overwritten
api.credentials = 'include';
api.headers = {
'csrf-token': window.csrf || '', // only if globally set, otherwise ignored
'Accept': 'application/json', // receive json
'Content-Type': 'application/json' // send json
};
// Convenient methods
['get', 'post', 'put', 'delete'].forEach(method => {
api[method] = api.bind(null, method);
});
To use it you have the variable api and 4 methods:
api.get('/todo').then(all => { /* ... */ });
And within an async function:
const all = await api.get('/todo');
// ...
Example with jQuery:
$('.like').on('click', async e => {
const id = 123; // Get it however it is better suited
await api.put(`/like/${id}`, { like: true });
// Whatever:
$(e.target).addClass('active dislike').removeClass('like');
});
Had the same issue - no body was sent from a client to a server.
Adding Content-Type header solved it for me:
var headers = new Headers();
headers.append('Accept', 'application/json'); // This one is enough for GET requests
headers.append('Content-Type', 'application/json'); // This one sends body
return fetch('/some/endpoint', {
method: 'POST',
mode: 'same-origin',
credentials: 'include',
redirect: 'follow',
headers: headers,
body: JSON.stringify({
name: 'John',
surname: 'Doe'
}),
}).then(resp => {
...
}).catch(err => {
...
})
This is related to Content-Type. As you might have noticed from other discussions and answers to this question some people were able to solve it by setting Content-Type: 'application/json'. Unfortunately in my case it didn't work, my POST request was still empty on the server side.
However, if you try with jQuery's $.post() and it's working, the reason is probably because of jQuery using Content-Type: 'x-www-form-urlencoded' instead of application/json.
data = Object.keys(data).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(data[key])).join('&')
fetch('/api/', {
method: 'post',
credentials: "include",
body: data,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
The top answer doesn't work for PHP7, because it has wrong encoding, but I could figure the right encoding out with the other answers. This code also sends authentication cookies, which you probably want when dealing with e.g. PHP forums:
julia = function(juliacode) {
fetch('julia.php', {
method: "POST",
credentials: "include", // send cookies
headers: {
'Accept': 'application/json, text/plain, */*',
//'Content-Type': 'application/json'
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" // otherwise $_POST is empty
},
body: "juliacode=" + encodeURIComponent(juliacode)
})
.then(function(response) {
return response.json(); // .text();
})
.then(function(myJson) {
console.log(myJson);
});
}
It might be useful to somebody:
I was having the issue that formdata was not being sent for my request
In my case it was a combination of following headers that were also causing the issue and the wrong Content-Type.
So I was sending these two headers with the request and it wasn't sending the formdata when I removed the headers that worked.
"X-Prototype-Version" : "1.6.1",
"X-Requested-With" : "XMLHttpRequest"
Also as other answers suggest that the Content-Type header needs to be correct.
For my request the correct Content-Type header was:
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
So bottom line if your formdata is not being attached to the Request then it could potentially be your headers. Try bringing your headers to a minimum and then try adding them one by one to see if your problem is resolved.
If your JSON payload contains arrays and nested objects, I would use URLSearchParams and jQuery's param() method.
fetch('/somewhere', {
method: 'POST',
body: new URLSearchParams($.param(payload))
})
To your server, this will look like a standard HTML <form> being POSTed.
You could do it even better with await/async.
The parameters of http request:
const _url = 'https://jsonplaceholder.typicode.com/posts';
let _body = JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1,
});
const _headers = {
'Content-type': 'application/json; charset=UTF-8',
};
const _options = { method: 'POST', headers: _headers, body: _body };
With clean async/await syntax:
const response = await fetch(_url, _options);
if (response.status >= 200 && response.status <= 204) {
let data = await response.json();
console.log(data);
} else {
console.log(`something wrong, the server code: ${response.status}`);
}
With old fashion fetch().then().then():
fetch(_url, _options)
.then((res) => res.json())
.then((json) => console.log(json));
**//POST a request**
const createTodo = async (todo) => {
let options = {
method: "POST",
headers: {
"Content-Type":"application/json",
},
body: JSON.stringify(todo)
}
let p = await fetch("https://jsonplaceholder.typicode.com/posts", options);
let response = await p.json();
return response;
}
**//GET request**
const getTodo = async (id) => {
let response = await fetch('https://jsonplaceholder.typicode.com/posts/' + id);
let r = await response.json();
return r;
}
const mainFunc = async () => {
let todo = {
title: "milan7",
body: "dai7",
userID: 101
}
let todor = await createTodo(todo);
console.log(todor);
console.log(await getTodo(5));
}
mainFunc()
I think that, we don't need parse the JSON object into a string, if the remote server accepts json into they request, just run:
const request = await fetch ('/echo/json', {
headers: {
'Content-type': 'application/json'
},
method: 'POST',
body: { a: 1, b: 2 }
});
Such as the curl request
curl -v -X POST -H 'Content-Type: application/json' -d '#data.json' '/echo/json'
In case to the remote serve not accept a json file as the body, just send a dataForm:
const data = new FormData ();
data.append ('a', 1);
data.append ('b', 2);
const request = await fetch ('/echo/form', {
headers: {
'Content-type': 'application/x-www-form-urlencoded'
},
method: 'POST',
body: data
});
Such as the curl request
curl -v -X POST -H 'Content-type: application/x-www-form-urlencoded' -d '#data.txt' '/echo/form'
You only need to check if response is ok coz the call not returning anything.
var json = {
json: JSON.stringify({
a: 1,
b: 2
}),
delay: 3
};
fetch('/echo/json/', {
method: 'post',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: 'json=' + encodeURIComponent(JSON.stringify(json.json)) + '&delay=' + json.delay
})
.then((response) => {if(response.ok){alert("the call works ok")}})
.catch (function (error) {
console.log('Request failed', error);
});
// extend FormData for direct use of js objects
Object.defineProperties(FormData.prototype, {
load: {
value: function (d) {
for (var v in d) {
this.append(v, typeof d[v] === 'string' ? d[v] : JSON.stringify(d[v]));
}
}
}
})
var F = new FormData;
F.load({A:1,B:2});
fetch('url_target?C=3&D=blabla', {
method: "POST",
body: F
}).then( response_handler )
you can use fill-fetch, which is an extension of fetch. Simply, you can post data as below:
import { fill } from 'fill-fetch';
const fetcher = fill();
fetcher.config.timeout = 3000;
fetcher.config.maxConcurrence = 10;
fetcher.config.baseURL = 'http://www.github.com';
const res = await fetcher.post('/', { a: 1 }, {
headers: {
'bearer': '1234'
}
});

Categories