⚠️ Not ready for production

Soundify

Soundify is a lightweight and flexible library for seamless communication with Spotify API, designed to work smoothly with TypeScript, Deno, Node.js, and client-side JavaScript. It's open source and provides an easy-to-use interface for accessing Spotify's data.

Features ✨

  • 💻 Multiruntime: supports Node, Deno and Browser environment.
  • 🚀 Modern: It leverages modern web APIs like native fetch, crypto, URLSearchParams, etc.
  • 🔑 Comprehensive auth support: It can handle all Spotify Auth flows and automatically refreshes access token.
  • 📦 Lightweight and treeshakable: It is designed with care for your bundle size.
  • 🆎 Strictly typed: All entities returned by the api have exact and up to date types.
  • 📖 Great docs: The library comes with extensive documentation and lots of examples.

Installation

Soundify is split into subpackages:

  • /auth - Handles Spotify authorization
  • /api - Provides client, endpoints and entity types
  • /shared - General functions and types (used under the hood in /auth and /api)

This separation is designed to enable the use of specific package on specific platforms. For example, @soundify/web-auth is suitable for browser, while @soundify/node-auth is appropriate for nodejs. The only difference in these packages is that under the hood they use different platform api to perform the same tasks.

NPM

npm i @soundify/api
// "/api" - Can be used both in the browser and in nodejs
import { ... } from "@soudnfiy/api"

// "/web-auth" - Authorization for browser
import { ... } from "@soundify/web-auth"

// "/node-auth" - Authorization for nodejs
import { ... } from "@soundify/node-auth"

This is minified bundle size of each package without treeshaking

@soundify/api soundify/node-auth soundify/web-auth

Deno

import { ... } from "https://deno.land/x/soundify/mod.ts"

Gettings started

To get started, you need to create a SpotifyClient, the purpose of which is to create an http request to spotify. It takes an access token as the first parameter. We'll tell you how to get your token later.

import { SpotifyClient } from "@soundify/api";

const client = new SpotifyClient("ACCESS_TOKEN");

If you've used other api libraries, you can expect something like a bunch of methods on a single class, but in our case the default recommendation is to use endpoint functions that take the client as the first argument:

import { SpotifyClient, getCurrentUser } from "@soundify/api"

const client = new SpotifyClient("ACCESS_TOKEN");
const user = await getCurrentUser(client);

console.log(user)

If your Access Token is valid it will output something like this

{
  "id": "31xofk5q7l22rvsbff7yiechyx6i",
  "display_name": "Soundify",
  "type": "user",
  "uri": "spotify:user:31xofk5q7l22rvsbff7yiechyx6i",
  // etc...
}

This may be inconvenient for some users, but it was done primarily to provide a way to treeshake so that clients don't send a lot of unused code.

If you are writing a backend or don't care about the size of the library you can use the createSpotifyAPI() function which will bind all the endpoint functions to your client. That way you can use this object throughout your application and not have to worry about imports.

import { SpotifyClient, createSpotifyAPI } from "@soundify/api";

const api = createSpotifyAPI(new SpotifyClient("ACCESS_TOKEN"));
const user = await api.getCurrentUser();

console.log(user);

Authorization

If you have no experience with Spotify Auth you can read more about it in the Spotify Authorization Guide.

Auth Flows

Authorization flows are organized into separate namespaces, with each namespace containing all the necessary functions and classes to implement a specific authorization flow. This allows for easy importing of a specific flow.

For instance, the following code imports all authorization flow namespaces:

import {
  // Authorization Code flow
  AuthCode,
  // Client Credentials flow
  ClientCredentials,
  // Implicit Grant flow
  ImplicitGrant,
  // Authorization Code flow with PKCE
  PKCEAuthCode,
} from "@soundify/node-auth";

You can take a look at the examples to see how to use each authorization flow.

Auth provider and automatic tokens refreshing

As you saw earlier, you can simply pass the Access Token to SpotifyClient. But after some time (1 hour to be exact), it will expire and you'll need to deal with it yourself. Somehow get a new Access Token and set it on the client.

import { SpotifyClient } from "@soundify/api";

const client = new SpotifyClient("ACCESS_TOKEN");
// ...
// Oops, token expires :(
client.setAuthProvider("NEW_ACCESS_TOKEN");

But if you don't want to deal with all that, you can just create an AuthProvider and pass it instead of the Access Token.

import { SpotifyClient } from "@soundify/api";
import { AuthCode } from "@soundify/node-auth";

const authProvider = new AuthCode.AuthProvider({
  client_id: "YOUR_SPOTIFY_CLIENT_ID",
  client_secret: "YOUR_SPOTIFY_CLIENT_SECRET",
  refresh_token: "YOUR_REFRESH_TOKEN",
});

const client = new SpotifyClient(authProvider);

You can create an AuthProvider from AuthCode, PKCEAuthCode, ClientCredentials flows. Implicit grant does not allow you to implement such a thing.

Auth Scopes

Scopes are usually used when creating authorization url. Pay attention to them, because many fields and endpoints may not be available if the correct scopes are not specified. Read the Spotify guide to learn more.

In Soundify scopes can be used as strings or with const object SCOPES.

import { SCOPES, AuthCode } from "@soundify/node-auth";

AuthCode.getAuthURL({
  scopes: ["user-read-email"],
  // or like this
  scopes: [SCOPES.USER_READ_EMAIL]
  // or use all scopes
  scopes: Object.values(SCOPES),
})

All contributions are very welcome ❤️