spotify-api-lib
Version:
A modern, TypeScript-first wrapper for the Spotify Web API with organized endpoint categories and full type safety
855 lines (832 loc) • 20.8 kB
TypeScript
import { AxiosInstance } from 'axios';
/**
* @file httpClient.ts
* @description HTTP client for making requests to Spotify API
* @author Caleb Price
* @version 1.0.0
* @date 2025-07-14
*/
interface RequestOptions {
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
data?: any;
params?: Record<string, any>;
headers?: Record<string, string>;
retries?: number;
}
declare class SpotifyHttpClient {
private client;
private accessToken;
constructor(accessToken?: string);
/**
* Set the access token for authentication
*/
setAccessToken(token: string): void;
/**
* Clear the access token
*/
clearAccessToken(): void;
/**
* Make an HTTP request to the Spotify API with improved error handling
*/
request<T = any>(endpoint: string, options?: RequestOptions): Promise<T>;
/**
* Check if an HTTP status code should be retried
*/
private isRetryableError;
/**
* Get retry delay from Retry-After header or default
*/
private getRetryAfterDelay;
/**
* Create a standardized error object
*/
private createSpotifyError;
/**
* Promise-based delay utility
*/
private delay;
/**
* Get the underlying axios instance for advanced usage
*/
getClient(): AxiosInstance;
}
/**
* @file baseEndpoint.ts
* @description Base class for API endpoint groups with convenience methods
* @author Caleb Price
* @version 1.1.0
* @date 2025-07-21
*/
declare abstract class BaseEndpoint {
protected client: SpotifyHttpClient;
constructor(client: SpotifyHttpClient);
protected makeRequest<T = any>(endpoint: string, options?: RequestOptions): Promise<T>;
protected get<T = any>(endpoint: string, params?: Record<string, any>): Promise<T>;
protected post<T = any>(endpoint: string, data?: any, params?: Record<string, any>): Promise<T>;
protected put<T = any>(endpoint: string, data?: any, params?: Record<string, any>): Promise<T>;
protected delete<T = any>(endpoint: string, params?: Record<string, any>): Promise<T>;
protected handleError(error: any, operation: string): never;
}
/**
* @file types.ts
* @description TypeScript interfaces for Spotify API responses
* @author Caleb Price
* @version 1.0.0
* @date 2025-07-14
*/
interface SpotifyImage {
url: string;
height: number | null;
width: number | null;
}
interface SpotifyArtist {
external_urls: {
spotify: string;
};
followers?: {
href: string | null;
total: number;
};
genres?: string[];
href: string;
id: string;
images?: SpotifyImage[];
name: string;
popularity?: number;
type: 'artist';
uri: string;
}
interface SpotifyAlbum {
album_type: 'album' | 'single' | 'compilation';
artists: SpotifyArtist[];
available_markets: string[];
external_urls: {
spotify: string;
};
href: string;
id: string;
images: SpotifyImage[];
name: string;
release_date: string;
release_date_precision: 'year' | 'month' | 'day';
total_tracks: number;
type: 'album';
uri: string;
popularity?: number;
label?: string;
}
interface SpotifyTrack {
album: SpotifyAlbum;
artists: SpotifyArtist[];
available_markets: string[];
disc_number: number;
duration_ms: number;
explicit: boolean;
external_ids: {
isrc?: string;
ean?: string;
upc?: string;
};
external_urls: {
spotify: string;
};
href: string;
id: string;
is_local: boolean;
name: string;
popularity: number;
preview_url: string | null;
track_number: number;
type: 'track';
uri: string;
}
interface SpotifyPlaylist {
collaborative: boolean;
description: string | null;
external_urls: {
spotify: string;
};
followers: {
href: string | null;
total: number;
};
href: string;
id: string;
images: SpotifyImage[];
name: string;
owner: {
display_name: string | null;
external_urls: {
spotify: string;
};
href: string;
id: string;
type: 'user';
uri: string;
};
primary_color: string | null;
public: boolean | null;
snapshot_id: string;
tracks: {
href: string;
total: number;
};
type: 'playlist';
uri: string;
}
interface SpotifyUser {
country?: string;
display_name: string | null;
email?: string;
explicit_content?: {
filter_enabled: boolean;
filter_locked: boolean;
};
external_urls: {
spotify: string;
};
followers: {
href: string | null;
total: number;
};
href: string;
id: string;
images: SpotifyImage[];
product?: string;
type: 'user';
uri: string;
}
interface SpotifySearchResponse {
tracks?: {
href: string;
items: SpotifyTrack[];
limit: number;
next: string | null;
offset: number;
previous: string | null;
total: number;
};
albums?: {
href: string;
items: SpotifyAlbum[];
limit: number;
next: string | null;
offset: number;
previous: string | null;
total: number;
};
artists?: {
href: string;
items: SpotifyArtist[];
limit: number;
next: string | null;
offset: number;
previous: string | null;
total: number;
};
playlists?: {
href: string;
items: SpotifyPlaylist[];
limit: number;
next: string | null;
offset: number;
previous: string | null;
total: number;
};
}
interface SpotifyPagingObject<T> {
href: string;
items: T[];
limit: number;
next: string | null;
offset: number;
previous: string | null;
total: number;
}
/**
* @file playlists.ts
* @description Playlist-related API endpoints
* @author Caleb Price
* @version 1.0.0
* @date 2025-07-14
*/
declare class PlaylistEndpoints extends BaseEndpoint {
/**
* Get current user's playlists
*/
getUserPlaylists(options?: {
limit?: number;
offset?: number;
}): Promise<SpotifyPlaylist[]>;
/**
* Create a new playlist
*/
create(name: string, options?: {
description?: string;
public?: boolean;
collaborative?: boolean;
}): Promise<SpotifyPlaylist>;
/**
* Add tracks to a playlist
*/
addTracks(playlistId: string, trackUris: string[], options?: {
position?: number;
}): Promise<{
snapshot_id: string;
}>;
/**
* Get tracks from a playlist
*/
getTracks(playlistId: string, options?: {
limit?: number;
offset?: number;
fields?: string;
}): Promise<any>;
/**
* Get a playlist by ID
*/
getById(playlistId: string, options?: {
fields?: string;
market?: string;
}): Promise<SpotifyPlaylist>;
/**
* Update playlist details
*/
update(playlistId: string, options: {
name?: string;
description?: string;
public?: boolean;
collaborative?: boolean;
}): Promise<void>;
/**
* Remove tracks from a playlist
*/
removeTracks(playlistId: string, tracks: Array<{
uri: string;
positions?: number[];
}>): Promise<{
snapshot_id: string;
}>;
}
/**
* @file tracks.ts
* @description Track-related API endpoints
* @author Caleb Price
* @version 1.0.0
* @date 2025-07-14
*/
declare class TrackEndpoints extends BaseEndpoint {
/**
* Get user's saved tracks (liked songs)
*/
getSavedTracks(options?: {
limit?: number;
offset?: number;
market?: string;
}): Promise<SpotifyPagingObject<{
added_at: string;
track: SpotifyTrack;
}>>;
/**
* Validate limit parameter
*/
private validateLimit;
/**
* Validate offset parameter
*/
private validateOffset;
/**
* Get albums from user's liked songs
*/
getLikedSongsAlbums(fetchLimit?: number): Promise<any[]>;
/**
* Get track by ID
*/
getById(trackId: string, options?: {
market?: string;
}): Promise<SpotifyTrack>;
/**
* Get multiple tracks by IDs
*/
getByIds(trackIds: string[], options?: {
market?: string;
}): Promise<{
tracks: SpotifyTrack[];
}>;
/**
* Save tracks for current user
*/
saveTracks(trackIds: string[]): Promise<void>;
/**
* Remove tracks from current user's saved tracks
*/
removeTracks(trackIds: string[]): Promise<void>;
/**
* Check if tracks are saved for current user
*/
checkSavedTracks(trackIds: string[]): Promise<boolean[]>;
/**
* Get audio features for a track
*/
getAudioFeatures(trackId: string): Promise<any>;
/**
* Get audio analysis for a track
*/
getAudioAnalysis(trackId: string): Promise<any>;
}
/**
* @file albums.ts
* @description Album-related API endpoints
* @author Caleb Price
* @version 1.0.0
* @date 2025-07-14
*/
declare class AlbumEndpoints extends BaseEndpoint {
/**
* Get album by ID
*/
getById(albumId: string, options?: {
market?: string;
}): Promise<SpotifyAlbum>;
/**
* Get multiple albums by IDs
*/
getByIds(albumIds: string[], options?: {
market?: string;
}): Promise<{
albums: SpotifyAlbum[];
}>;
/**
* Get album tracks
*/
getTracks(albumId: string, options?: {
limit?: number;
offset?: number;
market?: string;
}): Promise<SpotifyPagingObject<SpotifyTrack>>;
/**
* Get user's saved albums
*/
getSavedAlbums(options?: {
limit?: number;
offset?: number;
market?: string;
}): Promise<SpotifyPagingObject<{
added_at: string;
album: SpotifyAlbum;
}>>;
/**
* Save albums for current user
*/
saveAlbums(albumIds: string[]): Promise<void>;
/**
* Remove albums from current user's saved albums
*/
removeAlbums(albumIds: string[]): Promise<void>;
/**
* Check if albums are saved for current user
*/
checkSavedAlbums(albumIds: string[]): Promise<boolean[]>;
/**
* Get new album releases
*/
getNewReleases(options?: {
country?: string;
limit?: number;
offset?: number;
}): Promise<SpotifyPagingObject<SpotifyAlbum>>;
}
/**
* @file artists.ts
* @description Artist-related API endpoints
* @author Caleb Price
* @version 1.0.0
* @date 2025-07-14
*/
declare class ArtistEndpoints extends BaseEndpoint {
/**
* Get artist by ID
*/
getById(artistId: string): Promise<SpotifyArtist>;
/**
* Get multiple artists by IDs
*/
getByIds(artistIds: string[]): Promise<{
artists: SpotifyArtist[];
}>;
/**
* Get artist's albums
*/
getAlbums(artistId: string, options?: {
include_groups?: string[];
market?: string;
limit?: number;
offset?: number;
}): Promise<SpotifyPagingObject<SpotifyAlbum>>;
/**
* Get artist's top tracks
*/
getTopTracks(artistId: string, options?: {
market?: string;
}): Promise<{
tracks: SpotifyTrack[];
}>;
/**
* Get related artists
*/
getRelatedArtists(artistId: string): Promise<{
artists: SpotifyArtist[];
}>;
/**
* Follow artists
*/
follow(artistIds: string[]): Promise<void>;
/**
* Unfollow artists
*/
unfollow(artistIds: string[]): Promise<void>;
/**
* Check if user follows artists
*/
checkFollowing(artistIds: string[]): Promise<boolean[]>;
/**
* Get user's followed artists
*/
getFollowed(options?: {
limit?: number;
after?: string;
}): Promise<{
artists: SpotifyPagingObject<SpotifyArtist>;
}>;
}
/**
* @file search.ts
* @description Search-related API endpoints
* @author Caleb Price
* @version 1.0.0
* @date 2025-07-14
*/
declare class SearchEndpoints extends BaseEndpoint {
/**
* Search for items
*/
search(query: string, options?: {
type?: string[];
limit?: number;
offset?: number;
market?: string;
include_external?: string;
}): Promise<SpotifySearchResponse>;
/**
* Search for tracks
*/
tracks(query: string, options?: {
limit?: number;
offset?: number;
market?: string;
}): Promise<SpotifySearchResponse>;
/**
* Search for albums
*/
albums(query: string, options?: {
limit?: number;
offset?: number;
market?: string;
}): Promise<SpotifySearchResponse>;
/**
* Search for artists
*/
artists(query: string, options?: {
limit?: number;
offset?: number;
market?: string;
}): Promise<SpotifySearchResponse>;
/**
* Search for playlists
*/
playlists(query: string, options?: {
limit?: number;
offset?: number;
market?: string;
}): Promise<SpotifySearchResponse>;
/**
* Search for shows
*/
shows(query: string, options?: {
limit?: number;
offset?: number;
market?: string;
}): Promise<SpotifySearchResponse>;
/**
* Search for episodes
*/
episodes(query: string, options?: {
limit?: number;
offset?: number;
market?: string;
}): Promise<SpotifySearchResponse>;
/**
* Search for audiobooks
*/
audiobooks(query: string, options?: {
limit?: number;
offset?: number;
market?: string;
}): Promise<SpotifySearchResponse>;
/**
* Search everything
*/
all(query: string, options?: {
limit?: number;
offset?: number;
market?: string;
}): Promise<SpotifySearchResponse>;
}
/**
* @file player.ts
* @description Player-related API endpoints
* @author Caleb Price
* @version 1.0.0
* @date 2025-07-14
*/
interface SpotifyPlaybackState {
device: {
id: string;
is_active: boolean;
is_private_session: boolean;
is_restricted: boolean;
name: string;
type: string;
volume_percent: number;
};
repeat_state: 'off' | 'track' | 'context';
shuffle_state: boolean;
context: {
type: string;
href: string;
external_urls: {
spotify: string;
};
uri: string;
} | null;
timestamp: number;
progress_ms: number;
is_playing: boolean;
item: any;
currently_playing_type: 'track' | 'episode' | 'ad' | 'unknown';
actions: {
interrupting_playback?: boolean;
pausing?: boolean;
resuming?: boolean;
seeking?: boolean;
skipping_next?: boolean;
skipping_prev?: boolean;
toggling_repeat_context?: boolean;
toggling_shuffle?: boolean;
toggling_repeat_track?: boolean;
transferring_playback?: boolean;
};
}
declare class PlayerEndpoints extends BaseEndpoint {
/**
* Get currently playing track
*/
getCurrentlyPlaying(options?: {
market?: string;
additional_types?: string[];
}): Promise<any>;
/**
* Get playback state
*/
getPlaybackState(options?: {
market?: string;
additional_types?: string[];
}): Promise<SpotifyPlaybackState>;
/**
* Transfer playback to a device
*/
transferPlayback(deviceIds: string[], play?: boolean): Promise<void>;
/**
* Get available devices
*/
getDevices(): Promise<{
devices: any[];
}>;
/**
* Start/Resume playback
*/
play(options?: {
device_id?: string;
context_uri?: string;
uris?: string[];
offset?: {
position: number;
} | {
uri: string;
};
position_ms?: number;
}): Promise<void>;
/**
* Pause playback
*/
pause(device_id?: string): Promise<void>;
/**
* Skip to next track
*/
next(device_id?: string): Promise<void>;
/**
* Skip to previous track
*/
previous(device_id?: string): Promise<void>;
/**
* Seek to position in track
*/
seek(position_ms: number, device_id?: string): Promise<void>;
/**
* Set repeat mode
*/
setRepeat(state: 'track' | 'context' | 'off', device_id?: string): Promise<void>;
/**
* Set shuffle mode
*/
setShuffle(state: boolean, device_id?: string): Promise<void>;
/**
* Set volume
*/
setVolume(volume_percent: number, device_id?: string): Promise<void>;
/**
* Add item to playback queue
*/
addToQueue(uri: string, device_id?: string): Promise<void>;
/**
* Get the user's queue
*/
getQueue(): Promise<any>;
/**
* Get recently played tracks
*/
getRecentlyPlayed(options?: {
limit?: number;
after?: number;
before?: number;
}): Promise<any>;
}
/**
* @file user.ts
* @description User-related API endpoints
* @author Caleb Price
* @version 1.0.0
* @date 2025-07-14
*/
declare class UserEndpoints extends BaseEndpoint {
/**
* Get current user's profile
*/
getCurrentUser(): Promise<SpotifyUser>;
/**
* Get user's profile by ID
*/
getById(userId: string): Promise<SpotifyUser>;
/**
* Get user's top items (tracks or artists)
*/
getTopItems(type: 'tracks' | 'artists', options?: {
time_range?: 'short_term' | 'medium_term' | 'long_term';
limit?: number;
offset?: number;
}): Promise<any>;
/**
* Get user's top tracks
*/
getTopTracks(options?: {
time_range?: 'short_term' | 'medium_term' | 'long_term';
limit?: number;
offset?: number;
}): Promise<any>;
/**
* Get user's top artists
*/
getTopArtists(options?: {
time_range?: 'short_term' | 'medium_term' | 'long_term';
limit?: number;
offset?: number;
}): Promise<any>;
/**
* Follow a user
*/
followUser(userId: string): Promise<void>;
/**
* Unfollow a user
*/
unfollowUser(userId: string): Promise<void>;
/**
* Check if current user follows users
*/
checkFollowingUsers(userIds: string[]): Promise<boolean[]>;
}
/**
* @file main.ts
* @description Main Spotify API class with constructor pattern for organized API access
* @author Caleb Price
* @version 1.0.0
* @date 2025-07-14
*
* @description
* Constructor-based Spotify API wrapper that provides organized methods for
* interacting with the Spotify Web API. Supports playlists, tracks, albums, artists, search, player, and user operations.
*
* @usage
* ```javascript
* const spotify = new SpotifyApi(accessToken);
* const playlists = await spotify.playlists.getUserPlaylists();
* const album = await spotify.albums.getById(albumId);
* const tracks = await spotify.tracks.getSavedTracks();
* ```
*
* @ChangeLog
* - 1.0.0: Initial implementation with all endpoint categories
*/
declare class SpotifyApi {
private httpClient;
playlists: PlaylistEndpoints;
tracks: TrackEndpoints;
albums: AlbumEndpoints;
artists: ArtistEndpoints;
search: SearchEndpoints;
player: PlayerEndpoints;
user: UserEndpoints;
constructor(accessToken?: string);
/**
* Initialize all endpoint groups
*/
private initializeEndpoints;
/**
* Basic token format validation
*/
private isValidTokenFormat;
/**
* Set access token for API requests
*/
setAccessToken(token: string): void;
/**
* Clear the access token
*/
clearAccessToken(): void;
/**
* Make a raw API request
*/
request(endpoint: string, options?: {
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
data?: any;
params?: Record<string, any>;
}): Promise<any>;
/**
* Get the HTTP client instance for advanced usage
*/
getHttpClient(): SpotifyHttpClient;
/**
* Clean up resources and clear tokens
*/
destroy(): void;
}
export { AlbumEndpoints, ArtistEndpoints, PlayerEndpoints, PlaylistEndpoints, SearchEndpoints, type SpotifyAlbum, SpotifyApi, type SpotifyArtist, SpotifyHttpClient, type SpotifyImage, type SpotifyPagingObject, type SpotifyPlaylist, type SpotifySearchResponse, type SpotifyTrack, type SpotifyUser, TrackEndpoints, UserEndpoints, SpotifyApi as default };