No commit activity in last 3 years
No release in over 3 years
Soundcloud API client, with configurable HTTP backend
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 0
>= 0

Runtime

 Project Readme

Soundcloud API Client

This is a configurable client for SoundCloud, based on Faraday.

The base class is Soundcloud::API, which reflects the documented API as instance methods.

The API might be configured (at the class level) with client credentials to enable OAuth2 token retrieval, but the usage is just at the instance level when a token is available.

To be able to use persistent connections and reduce the overall time to connect the server, the connection object (Faraday::Connection) is stored in the class when possible, and each instance will use the same connection.

API configuration

To configure the API credentials and other parameters, the API.configure method must be used.

Example:

Soundcloud::API.configure(mime: "application/json",
                          host: "https://api.soundcloud.com",
                          adapter: :net_http,
                          client_id: "0123456789abcdef0123456789abcdef",
                          client_secret: "0123456789abcdef0123456789abcdef",
                          redirect_uri: "http://example.com/redirect_path"
                          )

All options are optional, where :mime and :host defaults are those specified above, and the default adapter (for Faraday) is Faraday.default_adapter, so it can be configured globally if needed.

If the client_id, client_secret or redirect_uri are missing, the API won't be able to provide the url for authorization, nor to exchange temporary user credentials with permanent ones.

API access

All documented API endpoints are mapped as methods on API instances. Thus,

@api.tracks(filter: "downloadable", offset: 50)

will retrieve the second page of downloadable tracks, while

@api.user_favorites(user)

will retrieve the first page of favorites for the specified user. To create a new object, une must use for instance

@api.create_track(title: "Track title", asset_data: some_uploadio_instance)

Positional arguments (which are required to build the request path) can be passed either as plain IDs (string or integer, it doesn't matter) or as hashes, in which case an "id" or :id key is used.

In the same way, the returned objects are hashes, representing the domain objects. Those same objects can be used again as positional arguments for parametrized queries, and also as content arguments for methods which send data to SoundCloud.

User authorization

To access user's data, one must initalize the API instance with a OAuth2 token:

@api = Soundcloud::API.new("1-12345-12345678-0123456789abcdef")

This instance will be able to retrieve user's priavte data, and also to send modifying commands, like favoriting a track, following a user, uploading a track etc.

Data retrieval

All of the following endpoints are represented as methods, with the corresponding subresources:

  • @api.users(options) => "/users"
  • @api.user(user_or_id) => "/users/id"
  • @api.user_tracks(user_or_id, options) => "/users/id/tracks"
  • @api.user_playlists(user_or_id, options) => "/users/id/playlists"
  • @api.user_web_profiles(user_or_id, options) => "/users/id/web-profiles"
  • @api.user_followings(user_or_id, options) => "/users/id/followings"
  • @api.user_followers(user_or_id, options) => "/users/id/followers"
  • @api.user_comments(user_or_id, options) => "/users/id/comments"
  • @api.user_favorites(user_or_id, options) => "/users/id/favorites"
  • @api.user_connections => "/users/me/connections"
  • @api.user_activities => "/users/me/activities"
  • @api.tracks(options) => "/tracks"
  • @api.track(track_or_id) => "/tracks/id"
  • @api.track_comments(track_or_id, options) => "/tracks/id/comments"
  • ...

and so on. Running the spec will provide a list of all the retrieval methods.

The data is returned as hashes or lists of hashes, whose keys follow strictly what provided by the SoundCloud servers. The same hashes can be used as positional arguments (so a hash retrieved in the response of @api.users() can be used as argument to @api.user_favorites(user_or_id)...).

If a hash is not available it can either be constructed on the fly (only its "id" or :id keys are used) or just the ID may pe provided.

Some methods have special names, as for tracks and playlists, where @api.track_shared_to_users(track) maps to "/tracks/id/shared-to/users", as the last slash does not separate an actual subresource.

There are a couple of boolean query methods:

  • @api.favorite?(track, user="me") will return truthy if the specified user (defaulting to the current user) has the track among its favorites.
  • @api.follow?(user, who="me") will return truthy if the specified user (defaulting to the current user) is following the given one.

Modifying data

For each of the "/playlists", "/tracks" and "/groups" resources, three additional methods are provided:

  • @api.create_track(data) => POST /tracks with the track in the request body
  • @api.update_track(data) => PUT /tracks/id with the track in the request body and the track ID in the URL
  • @api.delete_track(data) => DELETE /tracks/id with the track ID in the URL

The data parameter must be a hash of attributes, with the same form as the one returned from retrieving objects as above. In the case of POST /tracks, the "asset_data" or :asset_data key must be an instance of UploadIO (from Faraday or from multipart-post gem) or a simpler File instance if possible.

Beware that in the actual requests, the body before serialization will be similar to {"track" => data}. The serialization is done by Faraday::Utils.build_nested_query so the resulting string is exactly what expected by Soundcloud servers. Array elements are serialized as separate keys (or prefixes) with the string "[]" appended to the parameter name, and hashes are serialized as separate keys, with the bracketed key appended to te parameter name. So

@api.create_playlist(title: "My Title", tracks: [{id: 123}, {id: 124}])

will be converted (before encoding) into

playlist[title]=My Title&playlist[tracks][][id]=123&playlist[tracks][][id]=124

As for retrieval, special methods are provided for flagging objects (with respect to the current user):

  • @api.favorite!(track)
  • @api.unfavorite!(track)
  • @api.follow!(user)
  • @api.unfollow!(user)

Errors

In case of HTTP errors in the range 400-599, a corresponding error is raised, which inherits from Soundcloud::Error::Error and contains the original response data in its response attribute.

Specific errors can be rescued, for instance Soundcloud::Error::NotFound will rescue from 404 error codes (which is probably desirable in some cases).

More configuration

The API instance can be configured with more options if needed. Currently the supported options are

  • :verbose if truthy, a logging middleware is added to the stack, so details about the request and response headers, and the full response body are shown in the log file.

  • :stubs if truthy, it must act like a Faraday::Adapter::Test::Stubs instance (it can duck-type it if necessary), and in that case the conection will use a test adapter, instead of doing actual HTTP requests. All the needed requests must be declared in the stubs object, as in

      @stubs = Faraday::Adapter::Test::Stubs.new
      @api = Soundcloud::API.new("no token needed in this case...", stubs: @stubs)
      @stubs.get("/tracks") do 
        [
         200,                                                 # status code
         {"Content-Type" => "application/json"},              # response headers
         '[{"id":123,"kind":"track","title":"Track Title"}]'  # response body
        ]
      end
      @api.tracks.should == [ {"id" => 123, "kind" => "track", "title" => "Track Title"} ]