Skip to content

Polldaddy's API Sucks

I've recently been doing some work involving polldaddy. It's not a bad service. Pretty straight-forward to go from the concept of a poll to putting a poll on a page. Unfortunately for me, I need to delve a little deeper and get the poll results to show up as a special visualization instead of the default bar graph.

Looking over the Polldaddy API it was immediately apparent to me that they'd missed an opportunity for a very simplified RESTful API. Instead, what they've opted for is a verbose monstrosity of sloppy XML and/or JSON.

Shared URL

The first major issue is that all requests go to the same url: https://api.polldaddy.com. What's worse is that there isn't even an embedded API version. This means that Polldaddy will be stuck supporting all v1 requests at api.polldaddy.com until v1 of the API is deprecated in favor of v2, or v13, or whatever version is the most recent when they decide to pull the plug on the original version.

No Versioning

A better choice would have been a url such as api.polldaddy.com/1/ to signify that the request uses API version 1.0. That way, when they want to roll out v2, they can continue to support api.polldaddy.com/1/ and additionally support api.polldaddy.com/2/.

The major issue with every request going to api.polldaddy.com is that each request then needs to embed the type of request that's being made as part of the message body. This means that the server doesn't know how to parse the data until the server has parsed the data. The fallout from this is that every request shares a verbose common structure so that every possible request type is supported.

For example, the message body to request poll data looks like this:

{
  "pdRequest": {
    "partnerGUID": "3F2504E0-4F89-11D3-9A0C-0305E82C3301",
    "userCode": "123456-FErKS5yu15scpSGmvip4JA==",
    "demands": {
      "demand": {
        "poll": {
          "id": "690432265"
        },
        "id": "GetPoll"
      }
    }
  }
}

Whereas the message body to request style data looks like this:

{
  "pdRequest": {
    "partnerGUID": "3F2504E0-4F89-11D3-9A0C-0305E82C3301",
    "userCode": "123456-FErKS5yu15scpSGmvip4JA==",
    "demands": {
      "demand": {
        "style": {
          "id": "123234"
        },
        "id": "GetStyle"
      }
    }
  }
}

Separation of Concerns

These requests could have been set up more elegantly as separate requests. The former, GetPoll at api.polldaddy.com/1/GetPoll, and the later, GetStyle at api.polldaddy.com/1/GetStyle. This would have significantly streamlined the request process. Instead of trying to figure out what was being requested, it quickly becomes apparent that api.polldaddy.com/1/GetPoll is requesting poll data.

What's more important is that it would no longer be necessary to wrap each request in a bundle of garbage. The GetPoll request has exactly three parameters, partnerGUID, userCode, and pollId. The JSON object for the request could then be slimmed down to simply:

{
  "partnerGUID": "3F2504E0-4F89-11D3-9A0C-0305E82C3301",
  "userCode": "123456-FErKS5yu15scpSGmvip4JA==",
  "pollId": "123234"
}

As this is now a very simple list of key-value pairs, a more appropriate encoding would be multipart/form-data (URL encoded):

partnerGUID=3F2504E0-4F89-11D3-9A0C-0305E82C3301&userCode=123456-FErKS5yu15scpSGmvip4JA%3D%3D&pollId=123234

Merge similar concepts

Now, I had previously mentioned that the GetPoll method could be located at api.polldaddy.com/1/GetPoll. This would actually be a poor choice as well. Reviewing the Polldaddy API reveals that most methods are actually CRUD groups:

Create Read Update Delete
Create Poll Get Poll Update Poll Delete Poll
n/a Get Poll Results n/a Reset Poll Results
Create Account Get Account Update Account n/a
Create Pack Get Pack Update Pack Delete Pack
Create Style Get Style Update Style Delete Style
Create Rating Get Rating Update Rating Delete Rating
n/a Get Rating Results n/a Reset Rating Results

There are a few methods I left off, which are actually plural forms of these existing methods. The important point behind all of this is that there are really a limited collection of types of requests to make, with 4 different request verbs that can be used on each.

Instead of api.polldaddy.com/1/GetPoll it should actually be:

GET: api.polldaddy.com/1/poll/[id]

Which means that /CreatePoll would be:

POST: api.polldaddy.com/1/poll

/UpdatePoll would be:

PUT: api.polldaddy.com/1/poll/[id]

…and /DeletePoll would be:

DELETE: api.polldaddy.com/1/poll/[id]

Data Types

The input should be liberally accepted, and not tied to the output format. Just because the request is in JSON doesn't mean the response can't be in XML. As all the methods are able to be significantly simplified, multipart/form-data should be accepted by default for POST, PUT, and DELETE requests, while GET requests should make good use of the query-string.

To specify which type of data is expected, the file extension may be used along with, or instead of the HTTP Accept header.

For example, requesting the (default) JSON data of a poll could be:

GET: api.polldaddy.com/1/poll/123?guid=...&code=...

or

GET: api.polldaddy.com/1/poll/123.json?guid=...&code=...

To get XML, the request would be:

GET: api.polldaddy.com/1/poll/123.xml?guid=...&code=...

All Together Now

Putting all of this together, a much more elegant API for Polldaddy.com would work as follows:

RESTful Polldaddy API Recommendation
HTTP Verb Request URL Request Parameters Response
GET /poll guid, code, id ...
POST /poll guid, code, question, multipleChoice, randomiseAnswers, otherAnswers, resultsType, blockRepeatVotersType, blockExpiration, comments, makePublic, closePoll, closeDate, styleId, packId, folderId, languageId, sharing, answer[]
PUT /poll guid, code, id, ...updated data...
DELETE /poll guid, code, id