I have been trying to use the Spotify API in my expo app but every tutorial or wrapper I find doesn't seem to work.
I would specifically like to access the 30-second song previews and track/song searching features.
If anyone could provide some guidance or point me towards a working demo of any kind that would be awesome.
Thanks!
Found parts of the solution in https://docs.expo.dev/guides/authentication/#spotify
const discovery = {
authorizationEndpoint: 'https://accounts.spotify.com/authorize',
tokenEndpoint: 'https://accounts.spotify.com/api/token',
};
var client_id = ''; // Your client id
var client_secret = ''; // Your secret
export default function spotifyLogin(props) {
const [request, response, promptAsync] = useAuthRequest(
{
clientId: '',
scopes: ['user-read-email', 'user-read-playback-state', 'playlist-modify-public','playlist-modify-private','playlist-modify-public','playlist-read-private','user-read-recently-played'],
// In order to follow the "Authorization Code Flow" to fetch token after authorizationEndpoint
// this must be set to false
usePKCE: false,
redirectUri: makeRedirectUri({
//scheme: 'your.app'
}),
},
discovery
);
React.useEffect(() => {
if (response?.type === 'success') {
const { code } = response.params;
//save code to local storage
props.saveLogin(code)
}
}, [response]);
return (
<Button
disabled={!request}
title="Login"
onPress={() => {
promptAsync();
}}
/>
);
}
export const getFirstTokenData = async (code) => {
var dataToSend = {
code: code,
redirect_uri: makeRedirectUri(),
grant_type: 'authorization_code'};
//making data to send on server
var formBody = [];
for (var key in dataToSend) {
var encodedKey = encodeURIComponent(key);
var encodedValue = encodeURIComponent(dataToSend[key]);
formBody.push(encodedKey + '=' + encodedValue);
}
formBody = formBody.join('&');
//POST request
var response = await fetch('https://accounts.spotify.com/api/token', {
method: 'POST', //Request Type
body: formBody, //post body
headers: {
//Header Defination
'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')),
},
})
try{
return await response.json()
}catch (error){
console.log(error)
}
}
export const getRefreshTokenData = async (refreshToken) => {
console.log(refreshToken)
console.log(refreshToken + " going in for refresh")
var dataToSend = {
refresh_token : refreshToken,
grant_type: 'refresh_token'};
//making data to send on server
var formBody = [];
for (var key in dataToSend) {
var encodedKey = encodeURIComponent(key);
var encodedValue = encodeURIComponent(dataToSend[key]);
formBody.push(encodedKey + '=' + encodedValue);
}
formBody = formBody.join('&');
//POST request
var response = await fetch('https://accounts.spotify.com/api/token', {
method: 'POST', //Request Type
body: formBody, //post body
headers: {
//Header Defination
'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')),
},
})
try{
return await response.json()
}catch (error){
console.log(error)
}
}
The above takes care of auth and getting refresh tokens, below takes care of searching for a track. To get 30 second previews there is a preview property in the return data for getTrack()
const apiPrefix = 'https://api.spotify.com/v1';
export default async ({
offset,
limit,
q,
token,
}) => {
const uri = `${apiPrefix}/search?type=track&limit=${limit}&offset=${offset}&q=${encodeURIComponent(q)}`;
console.log('search begin, uri =', uri, 'token =', token);
const res = await fetch(uri, {
method: 'GET',
headers: {
Authorization: `Bearer ${token}`,
}
});
const json = await res.json();
//console.log('search got json', json);
if (!res.ok) {
return [];
}
return json
// const {
// tracks: {
// items,
// }
// } = json;
// // const items = json.tracks.items;
// return items.map(item => ({
// id: item.id,
// title: item.name,
// imageUri: item.album.images
// ? item.album.images[0].url
// : undefined
// }));
console.log('search end');
};
export const getTrack = async(trackID, token) => {
const uri = `${apiPrefix}/tracks/${trackID}?market=ES`;
const res = await fetch(uri, {
method: 'GET',
headers: {
// Accept: `application/json`,
// Content-Type: `application/json`,
Authorization: `Bearer ${token}`,
}
});
const json = await res.json();
//console.log('search got json', json);
if (!res.ok) {
return [];
}
return json
}
Once upon a time, I worked on a similar application as a test. It's a bit outdated, but I believe Spotify has not changed its API much in the meantime.
Hope this caa help
https://github.com/kubanac95/spotify-test
Related
I'm new to API and Twitter
I managed to retrieve the 'normal' 20 Tweets (Status)
Is there a way to retrieve a whole week at once?
Or do I have to write a code that permanently calls 20 Tweets and append each after the other?
You can get whole week of tweet by Get User's lookup Tweet V2 API
OR
Get timeline for user by V1.1 API
Tweet User's lookup V2
GET /2/users/{user id}/tweets
get tweet time line by V1.1 API
GET statuses/user_timeline
I will demo both with Mr. Tweet by Postman.
#1 Get access token in here
This token support both V2 and V1.1 API call.
#2 Get Tweets one week by v2
https://api.twitter.com/2/users/44196397/tweets?max_results=20&start_time=2023-01-18T00:00:01Z&end_time=2023-01-25T00:00:01Z
If you want to more detail information for each tweet.
Add attribute option in here by Adding query parameters(like a like count, create at and so on)
#3 Get timeline, 20 Tweets by v1.1
Timeline API Two methods in here
https://api.twitter.com/2/users/:id/timelines/reverse_chronological
OR
https://api.twitter.com/2/users/:id/tweets
Demo for get tweet with 2nd methods
https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=elonmusk&count=20
Both API needs access token assignment
Both API can be programming by node.js or Python languages.
const axios = require('axios')
const API_KEY = '<your API Key>'
const API_KEY_SECRET = '<your API Secret>'
const getToken = async () => {
try {
const resp = await axios.post(
url = 'https://api.twitter.com/oauth2/token',
data = '',
config = {
params: {
'grant_type': 'client_credentials'
},
auth: {
username: API_KEY,
password: API_KEY_SECRET
}
}
);
return Promise.resolve(resp.data.access_token);
} catch (err) {
console.error(err)
return Promise.reject(err)
}
};
const getUserId = async (username, token) => {
try {
const resp = await axios.get(
url = `https://api.twitter.com/2/users/by/username/${username}`,
config = {
headers: {
'Accept-Encoding': 'application/json',
'Authorization': `Bearer ${token}`,
}
}
);
// { data: { id: '44196397', name: 'Elon Musk', username: 'elonmusk' } }
return Promise.resolve(resp.data.data.id)
} catch (err) {
return Promise.reject(err)
}
};
const getTweetTimeline = async (user_id, start_date, end_date, token) => {
try {
const tweets = [];
let index = 1
let next_token = 'start'
while (next_token != null) {
let url = `https://api.twitter.com/2/users/${user_id}/tweets?start_time=${start_date}&end_time=${end_date}&tweet.fields=created_at&max_results=20`
if (next_token != 'start') {
url = `https://api.twitter.com/2/users/${user_id}/tweets?start_time=${start_date}&end_time=${end_date}&tweet.fields=created_at&max_results=20&pagination_token=${next_token}`
}
const resp = await axios.get(
url = url,
config = {
headers: {
'Accept-Encoding': 'application/json',
'Authorization': `Bearer ${token}`,
}
}
);
for(const item of resp.data.data) {
tweets.push({
index : index,
created_at: item.created_at,
text: item.text,
id : item.id
})
index = index + 1
}
next_token = resp.data.meta.next_token
}
return Promise.resolve(tweets)
} catch (err) {
console.error(err)
return Promise.reject(err)
}
}
getToken()
.then(token => {
console.log(token);
getUserId('elonmusk', token)
.then(user_id => {
getTweetTimeline(user_id,'2023-02-05T00:00:00Z','2023-02-11T23:59:59Z', token)
.then(tweets => {
for(const tweet of tweets) {
console.log(tweet)
}
})
.catch(error => {
console.log(error.message);
});
})
.catch(error => {
console.log(error.message);
});
})
.catch(error => {
console.log(error.message);
});
Result
node get-tweet.js > result.json
How do I pass a file upload as a graphql mutation variable? Submitting this test gives me a 400 bad request with this error:
Variable \"$thumbnailFile\" got invalid value {}; Upload value invalid.
I am using graphql-upload. I am sending my queries like this:
async function graphQLFetch(query, variables = {}){
const response = await fetch('/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables })
});
const body = await response.text();
const result = JSON.parse(body);
return result.data;
}
In my react component:
handleThumbnailChange(event){
const thumbnailFile = event.target.files[0];
const query = `mutation addThumbnailTest($thumbnailFile: Upload){
addThumbnailTest(thumbnailFile: $thumbnailFile){
thumbnailSrc
}
}`;
const data = await graphQLFetch(query, {
thumbnailFile
});
}
My schema:
scalar Upload
type Mutation {
addThumbnailTest(thumbnailFile: Upload): String
}
My server is setup like the following:
const { ApolloServer } = require('apollo-server-express');
const { GraphQLUpload, graphqlUploadExpress } = require('graphql-upload');
const express = require('express');
const resolvers = {
Upload: GraphQLUpload,
Mutation: {
handleThumbnailChange: handleThumbnailChange,
}
}
const server = new ApolloServer({
typeDefs: fs.readFileSync(path.join(__dirname, 'schema.graphql'), 'utf-8'),
resolvers
});
async function installHandler(app){
await server.start();
server.applyMiddleware({ app, path: '/graphql' });
}
const app = express();
(async function start(){
try{
// Install GraphQL API Handler
app.use(graphqlUploadExpress());
await installHandler(app);
I had to submit the query as form data and without the { 'Content-Type': 'application/json' } header
async function graphQLFetch(query, variables = {}, multipart = false){
let request;
if(multipart){
const data = {
operations: JSON.stringify({
query,
variables: {
...variables,
file: null
}
}),
map: JSON.stringify({
'0': [
'variables.file'
]
})
};
const requestBody = new FormData();
for(const name in data) {
requestBody.append(name, data[name]);
}
requestBody.append('0', variables.file);
request = {
method: 'POST',
body: requestBody
}
} else {
request = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables })
}
}
const response = await fetch('/graphql', request);
const responseBody = await response.text();
const result = JSON.parse(responseBody);
return result.data;
}
I should upload file in my vue.js app. When I browse a file, I make post request and until I get a response, I need to make get request every 2 seconds for example. How can I do this?
uploadFile(event) {
this.isLoadingProcess = true;
console.log(this.isLoadingProcess);
let data = new FormData();
this.file = event.target.files[0];
data.append('name', 'uploaded-file');
data.append('file', event.target.files[0]);
const options = {
headers: {
'Content-Type': event.target.files[0].type,
},
onUploadProgress: function (progressEvent) {
const {loaded, total} = progressEvent;
let percentCompleted = Math.floor((loaded * 100) / total);
//console.log(percentCompleted);
if (percentCompleted !== 100) {
axios.get(url, {data: progressId})
.then(response => {
this.progress = response.data.progress;
// console.log(this.progress);
console.log(response.data.progress);
})
}
},
};
axios.post(
url,
data,
options
)
.then(response => {
console.log(response);
})
.finally(()=> {
this.isLoadingProcess = false;
})
what about this?
It asks api about update more than every 2 seconds, but It's better for my opinion in case, when endpoint isn't available
var processTimeoutFunction = null;
function checkProgress() {
axios.get('ckeck-process', ...).then(response => {
if (response.processIsActive) {
processTimeoutFunction = setTimeout(() => checkProgress(), 2000);
} else {
clearTimeout(processTimeoutFunction);
this.isLoadingProcess = false;
})
}
I have below code
async send(user, data) {
const postData = {
'data': 'john',
'secret': 'secret'
};
const dataJson = JSON.stringify(postData);
const options = {
hostname: 'example.com',
path: '/send',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': dataJson.length
}
};
const req = https.request(options, (res) => {
let data = '';
console.log('Status Code:', res.statusCode);
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('Body: ', JSON.parse(data));
});
}).on("error", (err) => {
console.log("Error: ", err.message);
});
req.write(dataJson);
req.end();
//---------------
let postResult = // HERE I WANT TO GET WHAT HTTP POST REQUESTED (e.g dataJson.body?)
//---------------
let result;
try {
result = await this.users.collection('users').updateOne(
{
_id: user
},
{
$set: {
// I WANT TO USE THAT HERE
data1 : postResult,
data2 : data2
}
},
{ maxTimeMS: consts.DB_MAX_TIME_USERS }
);
} catch (err) {
log.error('DB', 'UPDATEFAIL id=%s error=%s', user, err.message);
err.message = 'Database Error, failed to update user';
err.code = 'InternalDatabaseError';
throw err;
}
return { success: true };
}
How to get those data to outside variable?
I almost crazy about this, been searching on google and not found anything
I am using express and native-http to make http request, are there any native-curl maybe?
thank you very much for all the help
Your current code is using callback to retrieve result, so you can initiate data variable to outside callback function
let data = '';
const req = https.request(options, (res) => {
console.log('Status Code:', res.statusCode);
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('Body: ', JSON.parse(data));
});
})
And also there are other easier way to make http request with nodejs. you can check axios that support Promise and async/await.
you can use syntax like this with axios
const response = await axios.get('/user?ID=12345');
way more easier.
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();
}