Search code examples
node.jsamazon-web-servicesapiaws-lambdaspotify

Invoking Spotify API from lambda function


I need to get data from Spotify API then send the response to the front-end. To avoid CORS issue and to hide key and secret from Spotify, I would like to use Lambda to make the API call then send back the response. To be more precise about my application:

1. FrontEnd > API Gateway
2. API Gateway > Lambda
3. Lambda > Spotify API (request their API to get token)
4. Spotify API > Lambda (token in the response)
5. Lambda > API Gateway
6. API Gateway > FrontEnd

Spotify endpoint is:

https://accounts.spotify.com/api/token?grant_type=client_credentials 

Header is:

Content-Type: 'application/x-www-form-urlencoded'
Authorization: 'Basic XXX'

So far I was able to do this using a Lambda function:

const https = require('https');
exports.handler = async (event, context) => {

    return new Promise((resolve, reject) => {
        const options = {
          hostname: 'accounts.spotify.com',
          path: '/api/token?grant_type=client_credentials',
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Authorization': 'Basic XXX'
          }
        }

        const req = https.request(options, (res) => {
          res.on('data', function (chunk) {
            console.log('BODY: ' + chunk);
          });
          resolve('Success');
        });

        req.on('error', (e) => {
          reject(e.message);
        });

        // send the request
        req.write('');
        req.end();
    });
};

But I can't get the response from the API:

{
    "access_token": "YYY",
    "token_type": "Bearer",
    "expires_in": 3600,
    "scope": ""
}

And I don't know how to send the data back to the front-end. Do you have any guidance to achieve what I'm looking for?

Edit: I also tried using axios as suggested:

const axios = require("axios");

module.exports.handler = (event, context, callback) => {
    const headers = {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Authorization': 'Basic XXX'
          }
    axios.post('https://accounts.spotify.com/api/token?grant_type=client_credentials', {}, {
      headers: headers
    })
    .then(function(response) {
        console.log(response)
        callback(null, response);
    })
    .catch(function(err) {
       console.error("Error: " + err);
       callback(err);
    });
};

But got the following error:

Response:
{
  "errorType": "Error",
  "errorMessage": "Request failed with status code 400",
  "trace": [
    "Error: Request failed with status code 400",
    "    at createError (/var/task/node_modules/axios/lib/core/createError.js:16:15)",
    "    at settle (/var/task/node_modules/axios/lib/core/settle.js:17:12)",
    "    at IncomingMessage.handleStreamEnd (/var/task/node_modules/axios/lib/adapters/http.js:237:11)",
    "    at IncomingMessage.emit (events.js:215:7)",
    "    at endReadableNT (_stream_readable.js:1183:12)",
    "    at processTicksAndRejections (internal/process/task_queues.js:80:21)"
  ]
}

Solution

  • Thanks to @jarmod and @Ashish Modi, the solution below is working for me:

    const axios = require("axios");
    const querystring = require('querystring');
    
    module.exports.handler = (event, context, callback) => {
        const headers = {
                'Content-Type': 'application/x-www-form-urlencoded',
                'Authorization': 'Basic XXX'
              }
        axios.post('https://accounts.spotify.com/api/token?grant_type=client_credentials', querystring.stringify({}), {
          headers: headers
        })
        .then(function(response) {
            const res = {
            statusCode: 200,
            body: (response.data.access_token)
        };
            callback(null, res);
        })
        .catch(function(err) {
           console.error("Error: " + err);
           callback(err);
        });
    };