Python REST Sample Code

View Demo / Source Code

The following code snippets are taken from the Decibel Python 2.7 REST API Sample Code.

Python 2.7 Source Code

Python 3.3 Source Code

The code snippets will guide you through some basic use case scenarios of the Decibel REST API.

Calling the API

REST requests are modelled after the way a web browser sends requests to a web server. So, when we use the Python programming language for REST requests, our Python scripts mimic the way a web browser interacts with a web server.

Python, being an extremely flexible and feature-rich language, provides a number of different modules for performing HTTP requests. The ones we recommend are:

Depending on your requirements either one of these modules may be more desirable.

urllib2

The urllib2 module is included with the Python standard library and defines functions and classes which help in opening URLs in a complex world - basic and digest authentication, redirections, cookies and more.

The following code example taken from util.py makes a request using urllib2 and stores the response.

import urllib2
import time
import datetime

# Set the request authentication headers
timestamp = datetime.datetime.fromtimestamp(time.time()).strftime('%Y%m%d %H:%M:%S')
headers = {'DecibelAppID': '<Your Application ID>',
           'DecibelAppKey': '<Your Application Key>',
           'DecibelTimestamp': timestamp}

# Send the GET request
url = 'http://api.decibel.net/v1/Albums/?artist=miles%20davis&format=json'      
req = urllib2.Request(url, None, headers)

# Read the response
resp = urllib2.urlopen(req).read()

httplib2

The httplib2 module is an easy to use and comprehensive HTTP client library that handles caching, keep-alive, compression, redirects and many kinds of authentication. It is not included in the Python standard library so you will need to download and install it separately.

The following code example makes a request using httplib2 and stores the response.

import httplib2
import time
import datetime

# Set the request authentication headers
timestamp = datetime.datetime.fromtimestamp(time.time()).strftime('%Y%m%d %H:%M:%S')
headers = {'DecibelAppID': '<Your Application ID>',
           'DecibelAppKey': '<Your Application Key>',
           'DecibelTimestamp': timestamp}

# Get the HTTP object
h = httplib2.Http(".cache")        
           
# Send the GET request
url = 'http://api.decibel.net/v1/Albums/?artist=miles%20davis&format=xml'       
resp, content = h.request(url, "GET", headers=headers)

Interpreting XML

The Decibel REST API returns data in two formats XML and JSON. To make it easier to parse the response the data can be interpreted into manageable objects.

ElementTree is a light-weight XML object model for Python. The Element type is a flexible container object, designed to store hierarchical data structures in memory. Element structures can be converted to and from XML.

The following code example requests albums by artist name, interprets the XML response and outputs the search results.

import util
import urllib
import xml.etree.ElementTree as et

# Set the request URL
url = 'http://api.decibel.net/v1/Albums/?artist=' + urllib.quote_plus(artistName) + '&format=xml'          

# Send the GET request
resp = util.request(url, applicationID, applicationKey)

# Interpret the XML response 
xml = et.fromstring(resp.decode('utf8'))

# Set the Decibel namespace
namespace = '{http://schemas.datacontract.org/2004/07/DecibelWebService}'

# Get the collection of albums from the result set
albums = xml.findall('{0}ResultSet/{0}Album'.format(namespace))

# Output the search results
for album in albums:
    print(album.find('{0}Name'.format(namespace)).text + ' - ' + album.find('{0}Artists'.format(namespace)).text)

Decoding JSON

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is like XML, but without the markup around the actual payload.

The json.loads() function takes a JSON encoded string and converts it into a Python object.

The following code example requests albums by artist name, decodes the JSON response and outputs the search results.

import util
import json
import urllib

# Set the request URL
url = 'http://api.decibel.net/v1/Albums/?artist=' + urllib.quote_plus(artistName) + '&format=json'

# Send the GET request
resp = util.request(url, applicationID, applicationKey)

# Interpret the JSON response 
data = json.loads(resp.decode('utf8'))

# Get the collection of albums from the result set
albums = data['ResultSet']

# Output the search results
for album in albums:
    print(album['Name'] + ' - ' + album['Artists'])

Albums: Search for albums by title

import util
import json
import urllib

def beginAlbumSearch(albumTitle, applicationID, applicationKey):

    # Set the request URL
    url = 'http://api.decibel.net/v1/Albums/?albumTitle=' + urllib.quote_plus(albumTitle) + '&format=json'         
        
    # Send the GET request
    resp = util.request(url, applicationID, applicationKey)

    # Interpret the JSON response 
    data = json.loads(resp.decode('utf8'))

    # Return the collection of album objects
    return data['ResultSet']

# Search for albums by title    
albumTitle = raw_input('Please enter a album title:')
result = beginAlbumSearch(albumTitle, applicationID, applicationKey)

# Output the search results
for album in result:
    print(album['Name'] + ' - ' + album['Artists'])

Albums: Retrieve Albums with Track information

import util
import json
import time

def beginAlbumRetrieve(albumID, applicationID, applicationKey):

    # Set the request URL
    depth = 'ExternalIdentifiers;Tracks;ImageThumbnail;Media;Names;Genres;Publications;Performances;'
    url = 'http://api.decibel.net/v1/Albums/?depth=' + depth + '&id=' + albumID + '&format=json'           

    # Send the GET request
    resp = util.request(url, applicationID, applicationKey)

    # Interpret the JSON response 
    data = json.loads(resp.decode('utf8'))

    # Return the album object
    return data['ResultSet'][0]

# Retrieve album with track information 
result = beginAlbumRetrieve(albumID, applicationID, applicationKey)

# Output the results
print('Name - ' + result['Name'])
print('Artists - ' + result['Artists'])
print('Disc Count - ' + str(result['DiscCount']))
print('Track Count - ' + str(result['TrackCount']))
print('Duration - ' + util.formatTime(result['TotalSeconds']))

try:
    print('Format - ' + result['Discs'][0]['MusicMedium']['Name'])
except KeyError:
    pass

try:
    externalIdentifiers = result['ExternalIdentifiers']
    for externalIdentifier in externalIdentifiers:
        if externalIdentifier['ExternalDatabase']['Name'] == 'UPC Barcode':
            print('Barcode - ' + externalIdentifier['Identifier'])
            break
except KeyError:
    pass
    
try:
    genreValues = ''
    genres = result['Genres']
    for genre in genres:
        genreValues += genre['Genre']['Name'] + ', '
    print('Genres - ' + genreValues.rstrip(', '))
except KeyError:
    pass
    
try:
    print('Track List:')
    tracks = result['Tracks']
    for track in tracks:
        print(str(track['SequenceNo']) + ') ' + 
        track['Name'] + ' (' + util.formatTime(track['TotalSeconds']) + ')')
except KeyError:
    pass

Albums: Get Album Cover Art

import util
import base64

def beginAlbumArtRetrieve(albumID, applicationID, applicationKey):

    # Set the request URL
    url = 'http://api.decibel.net/v1/Albums/' + albumID + '/Image'     

    # Send the GET request
    resp = util.request(url, applicationID, applicationKey)

    return '<img src="data:image/jpeg;base64,{0}">'.format(base64.b64encode(resp).decode('unicode_escape'))

result = beginAlbumArtRetrieve(albumID, applicationID, applicationKey)

with open('album_art_retrieve.html', 'w') as the_file:
    the_file.write(result)
    
print('Album art written to album_art_retrieve.html')

Participants: Search for participants by name

import util
import json
import urllib

def beginParticipantSearch(participantName, applicationID, applicationKey):

    # Set the request URL
    url = 'http://api.decibel.net/v1/Participants/?name=' + urllib.quote_plus(participantName) + '&format=json'        
    
    # Send the GET request
    resp = util.request(url, applicationID, applicationKey)

    # Interpret the JSON response 
    data = json.loads(resp.decode('utf8'))

    # Return the collection of participant objects
    return data['ResultSet']

# Search for participants by name   
participantName = raw_input('Please enter a participant name:')
result = beginParticipantSearch(participantName, applicationID, applicationKey)

# Output the search results
for participant in result:
    print(participant['Name'] + ' - ' + participant['DateBorn']['Name'])

Participants: Retrieve participant with associations and track appearances

import util
import json

def beginParticipantRetrieve(participantID, applicationID, applicationKey):

    # Set the request URL
    depth = 'Names;GroupMembers;Nationalities;GeographicAreas;Annotations;ChartsAwards;Relationships;'
    url = 'http://api.decibel.net/v1/Participants/?depth=' + depth + '&id=' + participantID + '&format=json'           
    
    # Send the GET request
    resp = util.request(url, applicationID, applicationKey)

    # Interpret the JSON response 
    data = json.loads(resp.decode('utf8'))

    # Return the participant object
    return data['ResultSet'][0]

def beginParticipantAssociates(participantID, applicationID, applicationKey):

    # Set the request URL
    depth = 'Names;GroupMembers;Nationalities;GeographicAreas;Annotations;ChartsAwards;Relationships;'
    url = 'http://api.decibel.net/v1/Participants/' + participantID + '/Associates?depth=' + depth + '&format=json'    

    # Send the GET request
    resp = util.request(url, applicationID, applicationKey)

    # Interpret the JSON response 
    data = json.loads(resp.decode('utf8'))

    # Return the collection of participant associate objects
    return data['ResultSet']

def beginParticipantTrackAppearances(participantID, applicationID, applicationKey):

    # Set the request URL
    depth = 'Names;GroupMembers;Nationalities;GeographicAreas;Annotations;ChartsAwards;Relationships;'
    url = 'http://api.decibel.net/v1/Participants/' + participantID + '/Tracks?depth=' + depth + '&format=json'

    # Send the GET request
    resp = util.request(url, applicationID, applicationKey)

    # Interpret the JSON response 
    data = json.loads(resp.decode('utf8'))

    # Return the collection of track appearance objects
    return data['ResultSet']

# Retreive participant with associations and track appearances  
result = beginParticipantRetrieve(participantID, settings.applicationID, settings.applicationKey)
print('Participant Name - ' + result['Name'])

result = beginParticipantAssociates(participantID, settings.applicationID, settings.applicationKey)
print('Associates:');
for associate in result:
    print(associate['Participant']['Name']);

result = beginParticipantTrackAppearances(participantID, settings.applicationID, settings.applicationKey)
print('Track Appearances:');
for trackAppearance in result:
    print(trackAppearance['TrackName'] + ' - ' + trackAppearance['AlbumName'])

Tracks: Search for tracks by title

import util
import json
import urllib

def beginTrackSearch(trackTitle, applicationID, applicationKey):

    # Set the request URL
    url = 'http://api.decibel.net/v1/Tracks/?trackTitle=' + urllib.quote_plus(trackTitle) + '&format=json'

    # Send the GET request
    resp = util.request(url, applicationID, applicationKey)

    # Interpret the JSON response 
    data = json.loads(resp.decode('utf8'))

    # Return the collection of track objects
    return data['ResultSet']

# Search for tracks by name 
trackName = raw_input('Please enter a track name:')
result = beginTrackSearch(trackName, applicationID, applicationKey)

# Output the search results
for track in result:
    print(track['Name'] + ' - ' + track['Artists'])

Tracks: Retrieve track with participations

import util
import json

def beginTrackRetrieve(trackID, applicationID, applicationKey):

    # Set the request URL
    depth = 'Names;Participations;ExternalIdentifiers;Genres;Performances;'
    url = 'http://api.decibel.net/v1/Tracks/?depth=' + depth + '&id=' + trackID + '&format=json'

    # Send the GET request
    resp = util.request(url, applicationID, applicationKey)

    # Interpret the JSON response 
    data = json.loads(resp.decode('utf8'))

    # Return the track object
    return data['ResultSet'][0]
    
# Retrieve track with participations    
result = beginTrackRetrieve(trackID, applicationID, applicationKey)

# Output the results
print('Track Information:')
print('Name - ' + result['Name'])
print('Artists - ' + result['Artists'])
print('Track Number - ' + result['TrackNumber'])
print('Disc Number - ' + result['DiscNumber'])
print('Duration - ' + util.formatTime(result['TotalSeconds']))

print('Participations:');
for participant in result['Participations']:
    print(participant['Name'])

Works: Search for works by name

import util
import json
import urllib

def beginWorkSearch(workName, applicationID, applicationKey):

    # Set the request URL
    url = 'http://api.decibel.net/v1/Works/?name=' + urllib.quote_plus(workName) + '&format=json'

    # Send the GET request
    resp = util.request(url, applicationID, applicationKey)

    # Interpret the JSON response 
    data = json.loads(resp.decode('utf8'))

    # Return the collection of work objects
    return data['ResultSet']

# Search for works by name  
workName = raw_input('Please enter a work name:')
result = beginWorkSearch(workName, applicationID, applicationKey)

# Output the search results
for work in result:
    print(work['Name'] + ' - ' + work['Composers'])

Works: Retrieve work with track appearances

import util
import json

def beginWorkRetrieve(workID, applicationID, applicationKey):

    # Set the request URL
    depth = 'Annotations;ChartsAwards;Genres;Movements;Names;Nationalities;Publications;Publishers;'
    url = 'http://api.decibel.net/v1/Works/?depth=' + depth + '&id=' + workID + '&format=json'

    # Send the GET request
    resp = util.request(url, applicationID, applicationKey)

    # Interpret the JSON response 
    data = json.loads(resp.decode('utf8'))

    # Return the work object
    return data['ResultSet'][0]

def beginWorkTrackAppearances(workID, applicationID, applicationKey):

    # Set the request URL
    depth = 'Annotations;ChartsAwards;Genres;Movements;Names;Nationalities;Publications;Publishers;'
    url = 'http://api.decibel.net/v1/Works/' + workID + '/Tracks' + '?depth=' + depth + '&format=json'

    # Send the GET request
    resp = util.request(url, applicationID, applicationKey)

    # Interpret the JSON response 
    data = json.loads(resp.decode('utf8'))

    # Return the collection of track appearances
    return data['ResultSet']
    
# Retrieve work with track appearances  
result = beginWorkRetrieve(workID, applicationID, applicationKey)
print('Name - ' + result['Name'])
print('Composers - ' + result['Composers'])
print('Catalogue - ' + result['Catalogue'])

result = beginWorkTrackAppearances(workID, applicationID, applicationKey)
print('Track Appearances:');
for trackAppearance in result:
    print(trackAppearance['TrackName'] + ' - ' + trackAppearance['TrackArtistName'] + ' - ' + trackAppearance['AlbumName'])