Add pagination

SMAPI calls with the potential for large numbers of matching items in the response employ a pagination mechanism to limit the number of items returned in a response at one time. This improves performance when the number of results matching a request is large. Your music service is responsible for determining all of the results that match a particular request and sorting them however the service deems appropriate. The sorted list of results is then accessed using a 0-based index; the first item in the list is item 0, the second is item 1, and so forth.

Pagination Syntax

API requests using pagination indicate the following:

  • The index number of the first item to return using the element
  • The number of results that should be in the response using the element

The expected syntax for requests supporting pagination is

<[soap]:Body>
  <[ns]:[callName]>
    <[ns]:index>[indexValueRequested]</[ns]:index>
    <[ns]:count>[numberRequested]</[ns]:count>
    ...
  </[ns]:callName>
</[soap]:Body>

where [callName] is the name of the method being called, [indexValueRequested] is the 0-based index number of the first item requested, and [numberRequested] is the number of items requested in the response.

The resulting response indicates the following:

  • The index number of the first item actually returned using the element
  • The number of items returned using the element
  • The total number of matching results using the element

The expected syntax for responses to those requests is

<[soap]:Body>
  <[ns]:[callName]Response> 
  <[ns]:[callName]Result>
    <[ns]:index>[indexValueReturned]</[ns]:index>
    <[ns]:count>[numberReturned]</[ns]:count>
    <[ns]:total>[totalNumberAvailable]</[ns]:total>
    ...
  </[ns]:[callName]Result>
  </[ns]:[callName]Response>
</[soap]:Body>

where [callName] is the name of the method being called, [indexValueReturned] is the 0-based index number of the first item returned in the response, [numberReturned] is the number of items returned in the response, and [totalNumberAvailable] is the number of items in the full list of available results.

Expectations and Behavior

SMAPI uses a pagination mechanism similar to the methods used in many other APIs, but there are some differences in the behavior of count (noted below).

The index value returned in the response should always match the index value in the request if pagination is correctly implemented. Be aware that if your service sends a response starting at a different index value Sonos will process the response as sent and act upon the response as if it matched the request.

The count value in the response may be less than or equal to the count value in the request. If your music service sends a response with more than the requested number of results, Sonos cannot process the response and will show an "unable to browse music" error to the user.

Sonos prefers responses that contain the number of items specified in the request provided that there are at least that many items left in the list of available results; if not, then the preference is to return the remainer of the available items. However, Sonos does allow you to send fewer items in your response as long as the count value returned equals the number of items actually sent. If you choose this option, Sonos will repeat the original request with its index value incremented by the number of items you actually returned and its count value decremented by the number of items you actually returned. Thus, if the original request had an index value of 0 and a count value of 100 and your response returned an index value of 0 and a count value of 20 (with the appropriate 20 items), a new request with an index value of 20 and a count value of 80 would automatically be sent. Assuming a consistent response count of 20, this would continue until a request with an index value of 80 and a count value of 20 was sent and your response with those same index and count values was received.

The total should remain constant for a particular request regardless of the values of index and count and total should always be equal to or greater than the returned value of count. If your music service sends a response with more than the specified total number of results available, Sonos cannot process the response and will show an "unable to browse music" error to the user. If your service changes the value sent in the element from one request to another in the same chain of pagination requests, the Sonos controller behavior may become erratic.

Examples

Consider a list of available responses with a total count of 20 items labeled 0-19. The following table indicates the expected responses for different values of the index and count elements in the request:

Request indexRequest countResponse indexResponse countResponse totalItems returned
010010200-9
025020200-19
101010102010-19
15101552014-19
301030020None

Similarly, Sonos can request the first ten items in the what's new category in your music service (analogous to the first row in the table above) using the following request:

POST http://musicservice.example.com HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "http://www.sonos.com/Services/1.1#getMetadata"
Content-Length: 1025
Host: example.com

<soap:Envelope 
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:ns="http://www.sonos.com/Services/1.1">
   <soap:Header>
     <ns:credentials>
       <ns:deviceId>DEVICE-1</ns:deviceId>
       <ns:deviceProvider>Sonos</ns:deviceProvider>
       <ns:loginToken>
         <ns:token>TOKEN</ns:token>
         <ns:key>KEY</ns:key>
         <ns:householdId>HOUSE-1</ns:householdId>
       </ns:loginToken>
     </ns:credentials>
   </soap:Header>
   <soap:Body>
     <ns:getMetadata>
       <ns:id>whatsnew</ns:id>
       <ns:index>0</ns:index>
       <ns:count>10</ns:count>
     </ns:getMetadata>
   </soap:Body>
</soap:Envelope>

and you would send the following response back:

HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: text/xml; charset=uff-8
Content-Length: 1312

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope 
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <getMetadataResponse 
    xmlns="http://www.sonos.com/Services/1.1">
      <getMetadataResult>
        <index>0</index>
        <count>10</count>
        <total>24362</total>
        <mediaCollection
        readOnly="true" 
        userContent="false"
        renameable="false">
          <id>ALB::1</id>
          <itemType>album</itemType>
          <title>Breathe In. Breathe Out.</title>
          <artist>Hilary Duff</artist>
          <artistId>ARTIST::1</artistId>
          <canScroll>false</canScroll>
          <canPlay>true</canPlay>
          <canEnumerate>true</canEnumerate>
          <albumArtURI>http://ART1</albumArtURI>
        </mediaCollection>
        <mediaCollection
        readOnly="true"
        userContent="false"
        renameable="false">
          <id>ALB::2</id>
          <itemType>album</itemType>
          <title>Pleazer</title>
          <artist>Tyga</artist>
          <artistId>ARTIST::2</artistId>
          <canScroll>false</canScroll>
          <canPlay>true</canPlay>
          <canEnumerate>true</canEnumerate>
          <albumArtURI>http://ART2</albumArtURI>
        </mediaCollection>
        ...
        <mediaCollection
        readOnly="true" 
        userContent="false" 
        renameable="false">
          <id>ALB::10</id>
          <itemType>album</itemType>
          <title>Where Are Ü Now (with Justin Bieber)</title>
          <artist>Jack Ü</artist>
          <artistId>ARTIST::10</artistId>
          <canScroll>false</canScroll>
          <canPlay>true</canPlay>
          <canEnumerate>true</canEnumerate>
          <albumArtURI>http://ART10</albumArtURI>
        </mediaCollection>
     </getMetadataResult>
   </getMetadataResponse>
  </soap:Body>
</soap:Envelope>

To get the next 10 results (analogous to the third row in the table above), Sonos would use the following request:

POST http://musicservice.example.com HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "http://www.sonos.com/Services/1.1#getMetadata"
Content-Length: 1025
Host: example.com

<soap:Envelope 
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:ns="http://www.sonos.com/Services/1.1">
  <soap:Header>
    <ns:credentials>
      <ns:deviceId>DEVICE-1</ns:deviceId>
      <ns:deviceProvider>Sonos</ns:deviceProvider>
      <ns:loginToken>
        <ns:token>TOKEN</ns:token>
        <ns:key>KEY</ns:key>
        <ns:householdId>HOUSE-1</ns:householdId>
      </ns:loginToken>
    </ns:credentials>
  </soap:Header>
  <soap:Body>
    <ns:getMetadata>
      <ns:id>whatsnew</ns:id>
      <ns:index>10</ns:index>
      <ns:count>10</ns:count>
    </ns:getMetadata>
  </soap:Body>
</soap:Envelope>

and you might send this response back:

HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: text/xml; charset=utf-8
Content-Length: 1104

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope 
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <getMetadataResponse
   xmlns="http://www.sonos.com/Services/1.1">
      <getMetadataResult>
        <index>10</index>
        <count>10</count>
        <total>24362</total>
        <mediaCollection
        readOnly="true"
        userContent="false"
        renameable="false">
          <id>ALB::11</id>
          <itemType>album</itemType>
          <title>face the sun</title>
          <artist>Miguel</artist>
          <artistId>ARTIST::11</artistId>
          <canScroll>false</canScroll>
          <canPlay>true</canPlay>
          <canEnumerate>true</canEnumerate>
          <albumArtURI>http://ART11</albumArtURI>
        </mediaCollection>
        ...
      </getMetadataResult>
    </getMetadataResponse>
  </soap:Body>
</soap:Envelope>

However, if Sonos sets the index to 1, you would send items 2-11:

POST http://musicservice.example.com HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "http://www.sonos.com/Services/1.1#getMetadata"
Content-Length: 1025
Host: example.com

<soap:Envelope 
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:ns="http://www.sonos.com/Services/1.1">
  <soap:Header>
    <ns:credentials>
      <ns:deviceId>DEVICE-1</ns:deviceId>
      <ns:deviceProvider>Sonos</ns:deviceProvider>
      <ns:loginToken>
        <ns:token>TOKEN</ns:token>
        <ns:key>KEY</ns:key>
        <ns:householdId>HOUSE-1</ns:householdId>
      </ns:loginToken>
    </ns:credentials>
  </soap:Header>
  <soap:Body>
    <ns:getMetadata>
      <ns:id>whatsnew</ns:id>
      <ns:index>1</ns:index>
      <ns:count>10</ns:count>
    </ns:getMetadata>
  </soap:Body>
</soap:Envelope>
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: text/xml; charset=utf-8
Content-Length: 1302

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope 
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <getMetadataResponse 
    xmlns="http://www.sonos.com/Services/1.1">
      <getMetadataResult>
        <index>1</index>
        <count>10</count>
        <total>24362</total>
        <mediaCollection 
        readOnly="true" 
        userContent="false" 
        renameable="false">
          <id>ALB::2</id>
          <itemType>album</itemType>
          <title>Pleazer</title>
          <artist>Tyga</artist>
          <artistId>ARTIST::2</artistId>
          <canScroll>false</canScroll>
          <canPlay>true</canPlay>
          <canEnumerate>true</canEnumerate>
          <albumArtURI>http://ART2</albumArtURI>
        </mediaCollection>
        ...
        <mediaCollection 
        readOnly="true" 
        userContent="false" 
        renameable="false">
          <id>ALB::11</id>
          <itemType>album</itemType>
          <title>face the sun</title>
          <artist>Miguel</artist>
          <artistId>ARTIST::11</artistId>
          <canScroll>false</canScroll>
          <canPlay>true</canPlay>
          <canEnumerate>true</canEnumerate>
          <albumArtURI>http://ART11</albumArtURI>
        </mediaCollection>
      </getMetadataResult>
    </getMetadataResponse>
  </soap:Body>
</soap:Envelope>

If Sonos sends a request with index set to 25000 (which is higher than the total number of results; analogous to the last row in the table above), you might send the following response:

HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: text/xml; charset=utf-8
Content-Length: 256

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope 
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <getMetadataResponse 
    xmlns="http://www.sonos.com/Services/1.1">
      <getMetadataResult>
        <index>25000</index>
        <count>0</count>
        <total>24362</total>
      </getMetadataResult>
    </getMetadataResponse>
  </soap:Body>
</soap:Envelope>

And a request for 10 items starting with item 24361 might result in this response:

HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: text/xml; charset=utf-8
Content-Length: 653

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope 
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <getMetadataResponse 
    xmlns="http://www.sonos.com/Services/1.1">
      <getMetadataResult>
        <index>24360</index>
        <count>2</count>
        <total>24362</total>
        <mediaCollection 
        readOnly="true" 
        userContent="false" 
        renameable="false">
          <id>ALB::24361</id>
          <itemType>album</itemType>
          <title>Tribute to Boney M</title>
          <artist>Dance Factory</artist>
          <artistId>ARTIST::3445</artistId>
          <canScroll>false</canScroll>
          <canPlay>true</canPlay>
          <canEnumerate>true</canEnumerate>
          <albumArtURI>http://ART432</albumArtURI>
        </mediaCollection>
        <mediaCollection 
        readOnly="true" 
        userContent="false" 
        renameable="false">
          <id>ALB::24362</id>
          <itemType>album</itemType>
          <title>Tchaikovsky - Masterpieces</title>
          <artist>St. Petersburg Radio orchestra</artist>
          <artistId>ARTIST::22221</artistId>
          <canScroll>false</canScroll>
          <canPlay>true</canPlay>
          <canEnumerate>true</canEnumerate>
          <albumArtURI>http://ART3443</albumArtURI>
        </mediaCollection>
      </getMetadataResult>
    </getMetadataResponse>
  </soap:Body>
</soap:Envelope>