How do I use the Spotify api endpoint (the URL of the API is included below) to play a specific song from my index.js file? - spotify

I am making a Google assistant app which (1). takes the emotion of the user, (2). retrieves a song from a pre analysed database of the same emotion and (3). plays that song via Spotify.
I have finished with parts 1 and 2 but am struggling with the 3rd part. I have found on here ( https://developer.spotify.com/console/put-play ) the API for sending a POST request to Spotify which plays a certain song or album. How do I convert this information into a POST request from my index.js file?
For example, if I wanted to POST the Spotify code for Red Hot Chili Peppers' "Suck My Kiss", what would the code look like for sending the spotify track id?
3
artist:
"Red Hot Chili Peppers"
id:
"4"
maxEmotion:
"anger"
score:
"0.578864"
song:
"Suck My Kiss"
spotifyCode:
"spotify:track:0psB5QzGb4653K0uaPgEyh"
I have tried using the Webhook format but am not sure if I understand the right way to use this and also it would mean that my entire index.js file is useless (since you can only have one or the other on the Google Assistant). So I am interested to see how to do this in the index.js file if possible? I have included the most important code below:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {WebhookClient} = require('dialogflow-fulfillment');
admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: 'ws://mood-magic-four-ptwvjb.firebaseio.com/'
});
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
//4
function playAngrySong (agent) {
// Get the database collection 'dialogflow' and document 'agent'
return admin.database().ref((`3`) ).once('value').then((snapshot) => {
const song = snapshot.child('song').val();
const artist = snapshot.child('artist').val();
agent.add(`I will play ${song} by ${artist}`);
// THIS IS WHERE I NEED THE POST TO THE SPOTIFY API
});
}
// Map from Dialogflow intent names to functions to be run when the intent is matched
let intentMap = new Map();
intentMap.set('-Angry - yes', playAngrySong);
agent.handleRequest(intentMap);
});

SOLVED: Here is the code below (using the Google assistant agent to say 'Enjoy' before it plays):
function playMusic(agent){
agent.add('Enjoy!');
var request = require("request");
var options = { method: 'PUT',
url: 'https://api.spotify.com/v1/me/player/play',
headers:
{ 'cache-control': 'no-cache,no-cache',
'Content-Type': 'application/json',
Authorization: `Bearer ${Access.accessToken}`,
Accept: 'application/json' },
body: { uris: [ `${SongInfo.Spotify_uri}` ] },
json: true };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log('This is the body of the play music request ' + body);
});
}

Related

bearer token in Twilio webhook

Im setting up a Twilio Sandbox for WhatsApp
for when a message comes in I set a webhook to my application’s link.
But my application requires a bearer token.
How can I set up twilio to send our bearer token together with the request it makes to my URL?
thank you
i make all test without the bearer token and it works fine.
but to go live, we need this token autentication for security reasons.
The webhook just triggers a GET or POST request to the registered URL, as you rightfully said. To be able to add custom parameters, such as a bearer token, you need to add an intermediate step in between. This can be achieved, for example, with any Serverless function.
Naturally, using Twilio Serverless would be the easiest option to do this:
const axios = require('axios');
exports.handler = async (context, event, callback) => {
// Create a new voice response object
const twiml = new Twilio.twiml.VoiceResponse();
try {
// Open APIs From Space: http://open-notify.org
// Number of people in space
const response = await axios.request({
method: "POST",
url: `http://api.open-notify.org/astros.json`,
headers: {
"Authorization": `Bearer ${request.body.token}`,
"Content-Type": "application/json; charset=utf-8"
},
});
const { number, people } = response.data;
const names = people.map((astronaut) => astronaut.name).sort();
// Create a list formatter to join the names with commas and 'and'
// so that the played speech sounds more natural
const listFormatter = new Intl.ListFormat('en');
twiml.say(`There are ${number} people in space.`);
twiml.pause({ length: 1 });
twiml.say(`Their names are: ${listFormatter.format(names)}`);
// Return the final TwiML as the second argument to `callback`
// This will render the response as XML in reply to the webhook request
// and result in the message being played back to the user
return callback(null, twiml);
} catch (error) {
// In the event of an error, return a 500 error and the error message
console.error(error);
return callback(error);
}
};

Making a call to Stripe API (to pause payment collection) using plain fetch, getting 400 response code

I have this code:
import fetch from 'node-fetch';
test("y", async () => {
// const username = "rk_test_xyz"
const encoded = Buffer.from(`${username}:`, 'utf-8').toString('base64')
const params = new URLSearchParams();
params.append('pause_collection[behaviour]', 'void');
const response = await fetch('https://api.stripe.com/v1/subscriptions/sub_1LFkzDH2RPqITCMjvjz9RCOJ', {
method: 'POST',
body: params,
headers: {
'Authorization': `Basic ${encoded}`,
"Content-type": `application/x-www-form-urlencoded`
}
});
const status = response.status
console.log({status})
})
When I run it I get status code 400. What is wrong with this approach?
Simple spelling mistake. Should be behavior instead of behaviour.
And for anyone debugging Stripe API failures, the Stripe API dashboard gives good error messages on the Logs view at https://dashboard.stripe.com/test/logs

Trying to send a POST request using the body of a GET request

I am currently working on a project to create API routes for two third party applications to communicate with one another using NodeJS/express. The issue I am having is that I am trying to have third party application A (3PA) get a list of timeslots from a calendar in third party application B (3PB) and then send a message to a user in 3PB containing those timeslots.
The route looks like this:
router.post('/request_appointment_times', function(req, res){
**google sheets api logic**
async function gsrun(client){
**getting data from google sheet**
var request = require('request');
require('request-debug')(request);
var options = {
'method': 'GET',
'url': '3PB API URL',
'headers': {
'accept' : '*/*',
'Authorization': 'Bearer ' + apiKey,
'content-type' : 'application/json'
},
};
request(options, function (error, response) {
if (error) throw new Error(error);
//console.log(response.body);
else
res.json({"message": "It Works!",});
slotsList = new String(response.body.slots);
slotsListArr = slotsList.split(',');
var rnd = Math.random(0, slotsListArr.length);
ssn.providedSlots = slotsListArr[rnd];
ssn.providedSlots2 = slotsListArr[rnd];
if (ssn.providedSlots == ssn.providedSlots2) {
ssn.providedSlots2 = ssn.slotsListArr[rnd]
}
if (ssn.providedSlots == ssn.providedSlots2) {
ssn.providedSlots2 = ssn.slotsListArr[rnd]
}
console.log(providedSlots);
console.log(providedSlots2);
});
}
});
Currently, I can't even get the providedSlots to print as the request function won't communicate with the console. My question is, is it possible/how can I do a POST to 3PB using the response body from my GET request within this same route. I apologize if I worded this poorly or didn't provide enough information. Any help is much appreciated and if I need to provide additional information let me know!
By the looks of this you are defining gsrun in your route handler but aren't actually invoking it. Should be more like this:
function gsrun() { /* logic */ }
router.post('/request_appointment_times', function(req, res){
gsrun();
});

Handling route requests between React and Express

I am creating an app with login and registration functionality with React and Express. I am using Formik to handle the form data as well as to post it:
> const initialValues={{username:"", email:"", password:""}}
onSubmit ={ async (values, { setSubmitting }) => {
const value = values.username+'/'+values.email+'/'+values.password;
const res = await fetch(`http://localhost:5000/newuser/${value}`, {
method: 'GET',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}}).then(response => response.json());
console.log(res);
values = initialValues;
setSubmitting(false);
}
This is then sent to the express application to the following route:
> app.get('/newuser/:username/:email/:password', (req, res) => {
const username = req.params.username;
const email = req.params.email;
const password = req.params.password;
let sql = `Insert into users (username, useremail, userpass) values ('${username}', '${email}', '${password}')`;
query = db.query(sql, (err, results) => {
if(err){throw err;}
res.send("New user added you can login now");
});
});
I am able to save these users to the database however I have the following 2 questions about this code, which I was able to piece together from various different videos, tutorials, questions and docs:
With regards to this line:
app.get('/newuser/:username/:email/:password', (req, res)
This is the only way I can get the form data into express, if I do not include the semi-colons and call these values using req.params, I get a "404 not found error" because the 3 values are empty. If I try and access them via req.body they still appear to be empty. I have tried to JSON.stringify them and I am using body-parser in the express app. My question is how can I access these 3 values(username, email, password) with req.body? Also is there a specific way I should format them if I want access this route from my browser, for example http://localhost:5000/users?username&email&password
How can I send a response back to the react app to tell it for example that the user exists and the password is correct? I have already made the mysql query that checks this and updates a variable in express I just need to then send the response, perhaps the value of that variable that will then tell react to go to the index page. However res.send(variable) does not seem to be sending the variable to react and the login form stays stagnant after it is submitted.
To access the body use method:"POST" rather than GET.
let response = await fetch(`http://localhost:5000/newUser`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(values),
})
if (response.errors) {
console.error(response.errors)
}
let responseJson = await response.json()
if (responseJson['message']) {
console.log(responseJson['message'])
}
Server side use something like this:
import cors from 'cors'
...
let app = express()
.use(cors())
.post('/newUser', (req, res) => {
let {username, email, password} = req.body
...
// If all ok
res.status(200).send({message: "User created"})
// If there's an issue
res.status(500).send({message: "oups"})
})
...

Clean Instagram oauth using node.js and express and minimal middlewares

I am trying to get a clean Instagram oauth without relying on middlewares such as passport, or instagram-node to learn the process and have maximum control. I have been trying to follow instagram Server-side (Explicit) Flow, which is a 2 step operation:
request an access code
request an access token
right now my server is set up using:
express = require('express'),
app = express();
and to initiate the first step I am using :
app.get('/', function(req, res){
var url = 'https://api.instagram.com/oauth/authorize/?client_id='+CLIENT-ID+'&redirect_uri='+YOUR-REDIRECT-URI+'&response_type=code'
res.redirect(url);
});
The above step sends me properly to instagram for authentication and the redirect callback of instagram gets picked up bellow at which point the console.log does display the correct instagram code. But the res.set part is wrong and does not work.
app.get('/auth/instagram/callback', function(req, res){
console.log('/// here to keep track of how many times this is called');
console.log('Instagram code: ', req.query.code);
var url = 'https://api.instagram.com/oauth/access_token';
res.set({
'client_id' : 'CLIENT-ID',
'client_secret' : 'CLIENT-SECRET',
'grant_type' : 'authorization_code',
'redirect_uri' : 'YOUR-REDIRECT-URI',
'code' : req.query.code
}).redirect(url);
});
Unfortunately it hangs at this point and clearly does not provide back the right data back.
Instagram suggest to do the following, but I am unsure how this would translate in express:
curl \-F 'client_id=CLIENT-ID' \
-F 'client_secret=CLIENT-SECRET' \
-F 'grant_type=authorization_code' \
-F 'redirect_uri=YOUR-REDIRECT-URI' \
-F 'code=CODE' \https://api.instagram.com/oauth/access_token
Any insight on this would be most welcome!
Thank you for your help.
And here is the actual response for the second part of OAuth with Instagram! Might not
var data = {'client_id' : process.env.FANCRAWLCLIENTID,
'client_secret' : process.env.FANCRAWLCLIENTSECRET,
'grant_type' : 'authorization_code',
'redirect_uri' : process.env.INSURIREDIRECT,
'code' : req.query.code
};
// Configure the request
var options = {
uri: 'https://api.instagram.com/oauth/access_token',
method: 'POST',
form: data
}
request(options, function (error, response, body) {
// to convert the string body to a usable object
var pbody = JSON.parse(body);
// pbody should look like this:
// {"access_token":"8943851.83434d.697342341324jkfdjsf41afd784932a2e8",
// "user":
// {"username":"my_user_name",
// "bio":"blah blah...",
// "website":"http:\/\/www.something.com",
// "profile_picture":"http:\/\/images.ak.instagram.com\/profiles\/profile_851_73sq_115.jpg",
// "full_name":"Full Name",
// "id":"8943851"}
// }
});
Enjoy!!!
I would suggest studying passport code (and instagram in particular).
In any case, after getting the code back (which works for you), you need to send a request from your backend code to Instagram. So your code would look more like (top of my head):
app.get('/auth/instagram/callback', function(req, res){
console.log('/// here to keep track of how many times this is called');
console.log('Instagram code: ', req.query.code);
var data = {
'url': url
'client_id' : 'CLIENT-ID',
'client_secret' : 'CLIENT-SECRET',
'grant_type' : 'authorization_code',
'redirect_uri' : 'YOUR-REDIRECT-URI',
'code' : req.query.code
};
var url = 'https://api.instagram.com/oauth/access_token';
request.post({
method: 'POST',
url: url,
body: JSON.stringify(data),
},
function (e, r, body) {
//body will contain the access_token
});
});
Then after you get the token you can set session, etc.
Ok got it to work to do post request for specific API calls but not yet the OAUTH part.. and WITH instagram secure header.
This exemple is to follow a user when you have an access token for a user.
var crypto = require('crypto'),
request = require('request');
var hmac = crypto.createHmac('SHA256', 'INSTAGRAM_CLIENT_ID');
hmac.setEncoding('hex');
hmac.write('IP_ADDRESS_127.0.0.1_OR_12.34.56.78');
hmac.end();
var hash = hmac.read();
// Set the headers
var headers = {
'X-Insta-Forwarded-For': 'IP_ADDRESS_127.0.0.1_OR_12.34.56.78|'+hash
}
// Configure the request
var options = {
uri: 'https://api.instagram.com/v1/users/1234/relationship_ OR WHATEVER API CALL',
qs: {'access_token': 'INSTAGRAM ACCESS TOKEN'},
method: 'POST',
headers: headers,
form:{action:'follow'}
}
request(options, function (error, response, body) {
// body response is what you are interested in
// NOTE that the body info is a string response so use var your_variable = JSON.parse(body) to use it as an object.
// Some exemples bellow
// USER NOT EXISTANT
// {"meta":{"error_type":"APINotFoundError","code":400,"error_message":"this user does not exist"}}
//
// successful response from unfollow
// {"meta":{"code":200},"data":{"outgoing_status":"none","target_user_is_private":false}}
//
// NOT FOLLOWING OR FOLLOWED BY
// {"meta":{"code":200},"data":{"outgoing_status":"none","target_user_is_private":false,"incoming_status":"none"}}
//
// you are following user 1234 but not followed back by them
// {"meta":{"code":200},"data":{"outgoing_status":"follows","target_user_is_private":false,"incoming_status":"none"}}
//
// Following and followed by
// {"meta":{"code":200},"data":{"outgoing_status":"follows","target_user_is_private":true,"incoming_status":"followed_by"}}
//
// PRIVATE users
// {"meta":{"code":200},"data":{"outgoing_status":"requested","target_user_is_private":true}}
});
I hope this helps.

Resources