Building a Spotify-like currently playing feature: Part 1 - Building the web API



When using music streaming services like Spotify, you can see realtime technology in action when you are using multiple devices. On the other devices, you can see how much playtime has elapsed.

In this series, we will take a look at how you can integrate this feature into your application with minimal fuss. We will be building a web API, a web app, and an iOS application. Both apps will consume the API we built.



To follow along in this part of the series, you must have the following requirements:

  • Node.js (any LTS version) and NPM installed locally on your machine. Install here.
  • Basic knowledge of JavaScript.
  • Basic knowledge of the command-line interface.

Setting up

The first thing you need to do is create a Pusher account. Next, create a Pusher Channels application using the dashboard.

Next, create a root directory for your Web API project. We will call it spot. When this is done, launch your terminal application and cd to the directory you just created. In this directory, run the following command:

    $ npm init -y

At the end, you should have a package.json file in the root of your application.

Let’s install some dependencies we will need for our API. In the terminal, run the following command:

    $ npm install --save express body-parser pusher cors

This will install all the dependencies we need to build the API. When the installation is complete, we can move on to building the application.

Building the web API

Now that we have everything installed, let’s create the web API. Open the project in an IDE of your choice. Create a new index.js file. This will be where we will have all our logic. Let’s start building our API.

Let’s start by importing and using all the dependencies that we installed using npm. In the file, paste the following code:

1// File: index.js
2    const express = require('express');
3    const bodyParser = require('body-parser');
4    const Pusher = require('pusher');
5    const fs = require('fs');
6    const cors = require('cors');
7    const path = require('path');
8    const app = express();

Above, we imported and created instances of the dependencies we installed using npm. Next, let’s create our API endpoints.

We will be creating three endpoints:

  • tracks - this endpoint will return all the available tracks for the music player. Since we are not building a full-fledged application, we will be mocking the data from a flat JSON file. We will create this file later on.
  • current - this endpoint will return the currently playing song. This will make it easy for other clients to know which song is currently playing when they are loaded.
  • tick - this endpoint will trigger a Pusher event. As the song plays, we will intermittently send the current position of the song playing using this endpoint. This is so that other web clients can know where the track is currently.

Let’s start implementing these endpoints.

In the index.js file, paste the following code:

1// File: index.js
2    // [...]
4    app.use(bodyParser.json());
5    app.use(bodyParser.urlencoded({ extended: true }));
7    let tracks = JSON.parse(fs.readFileSync(path.resolve(__dirname, 'data.json')));
9    app.get('/tracks', (req, res) => {
10      res.json(tracks);
11    });

As seen above, we are returning the contents of a nonexistent JSON file. This file is supposed to contain the data for our tracks. Let’s create this file.

Create a file named data.json and paste the following JSON string into the file:

1// File: data.json
2    [
3      {
4        "id": 1,
5        "duration": 195,
6        "artist": "JugHead",
7        "title": "Polly",
8        "cover": ""
9      }
10    ]

Now that we have the data file, we can continue building the API. In the index.js file, paste the following code to create the second endpoint:

1// File: index.js
2    // [...]
4    let current = {};
6    app.get('/current', (req, res) => {
7      res.json(current);
8    });

Above, the endpoint simply returns the currently playing track if there is any or an empty JSON object if nothing is playing.

Let us add the last endpoint. In the index.js file, add the following code:

1// File: index.js
2    // [...]
4    app.options('/tick', cors());
6'/tick', cors(), (req, res) => {
7      const { id, position, device } = req.body;
9      for (let index = 0; index < tracks.length; index++) {
10        if (tracks\[index\]['id'] === parseInt(id)) {
11          current = tracks[index];
12          pusher.trigger('spotmusic', 'tick', { id, position, device });
13          return res.json({ status: true });
14        }
15      }
17      res.json({ status: false });
18    });

In the endpoint above, we will receive the ID of the track currently being played, the position of the track and then we will receive the device that is sending the request. When we find a matching existing track, we will trigger the event to Pusher and save the currently playing track on the server.

Finally, let’s make sure the Node.js server is listening on port 3000 when we start the server. In the index.js file, add the following code:

1// File: index.js
2    // [...]
4    app.listen(3000, () => console.log('Listening on port 3000!'));

Now that we have the endpoints set up, let’s add realtime triggers to Pusher. Before the app variable, add the following code:

1// File: index.js
2    // [...]
4    let pusher = new Pusher({
5      appId: 'PUSHER_APP_ID',
6      key: 'PUSHER_APP_KEY',
7      secret: 'PUSHER_APP_SECRET',
8      cluster: 'PUSHER_APP_CLUSTER',
9      useTLS: true
10    });

Replace the PUSHER_APP_* placeholders with the credentials from your Pusher dashboard.

Running the application server

Now that we have built the application, we need to run the application in a server. In your terminal, run the following command to start the Node server:

    $ node index.js

Now your server is running, in the next parts, we will move on to creating the clients that will consume the API that the Node.js app provides.


In this part, we created a web API for our music application. This API will be responsible for returning the tracklist and also updating the now playing track. It will also be responsible for triggering events to Pusher.

In the next part, we will start building an iOS app that will consume the API we built in this part. The source code is available on GitHub.