Itemize and Advise on Good APIs. Comparing Slack and HipChat from a developer’s perspective

What makes a good API, the kind that developers will jump at the chance to work with?

That’s something I’ve had plenty of time to ponder as we’ve built Lucidchart add-ons for Slack and HipChat over the past year. While both messaging apps offer similar features to users, they provide surprisingly different APIs to developers. Based on my experience developing apps for these APIs, here’s what to expect from each in terms of functionality, usability, and documentation. Your mileage may vary.

Functionality

An API needs to offer enough functionality to be useful. Exactly what an API should allow varies from product to product, but you can estimate an API’s usefulness by coming up with ideas for apps, then considering how plausible they would be to build. Ideally, an app should be able to get access to almost any action, but it may require approval to use the more sensitive ones via some sort of permission system.

HipChat

HipChat’s API involves a set of resources such as groups, rooms, and users. With the right permissions for your integration, you can manipulate all of them. Want to notify a room? Invite someone to a room? Upload a file? If a HipChat user can do it, chances are that your app can too. On top of standard actions, your app can listen to events like room creation or messages with specific keywords and use them as the basis for other actions.

HipChat also offers extended functionality and GUI elements. Web panels, for instance, allow you to iframe web pages within HipChat, resulting in greater interactivity and visual appeal, and Actions allow your app to hook into the GUI, adding menu items that bring up dialogs or open external pages. You can also let users install your integration to a specific room, giving room creators the chance to try out your app without bothering the account admin, which is a great boon for getting your app out there.

Lucidchart Glance in HipChat
Our HipChat integration uses a glance that expands into a web panel to keep track of diagrams shared in the room.

That said, HipChat’s API does lack one essential feature: the ability for an app to directly message a user. There are workarounds, but it is more difficult than it should be (more on that later).

Slack

Slack’s API is organized much like HipChat’s. It also has a set of resources and a number of API calls to read or interact with them. In fact, Slack and HipChat’s resources and functionality are nearly identical. If your app just leverages basic HipChat APIs, you’ll have no trouble recreating it in Slack.

In terms of extended functionality, Slack doesn’t allow integrations to create any custom views, instead limiting apps to plain or lightly formatted text. As a result, complex integrations generally have a pseudo-command-line interface, requiring one command to display information and yet another to act upon it. As an example, when using the memebot app, I often forget the exact name required for the meme I want, and I have to type /meme-list to go to the page that lists them. With access to GUI elements, the developers of that app would be able to create something like an autocomplete search.

On the plus side, Slack supports directly messaging users, which is something HipChat makes difficult.

The Verdict

HipChat offers a greater degree of customization and allows you to build more complex apps, but Slack is perfectly adequate for basic needs. This round to HipChat.

Usability

No matter how much of the functionality an API exposes for developers to tinker with, if it requires a confusing sequence of requests in nonsensical formats or forces you to find roundabout methods to complete simple tasks, then it’s not that useful. A good API considers and makes simple the kinds of actions developers will want to take and the data they’ll want to access. A good API also tries to follow common conventions if possible, as this helps developers quickly understand and use it.

HipChat

HipChat uses a RESTful API, where you use HTTP verbs like GET or DELETE to perform actions on a set of resources. As with other APIs, 2XX-level responses signify that things went well, 4XX responses mean that you did something wrong, and 5XX errors mean that the servers exploded. Most of HipChat’s API is fairly standard and easy to use. No surprises there. Example request:

curl -G -H "Authorization: Bearer <auth-token>" https://api.hipchat.com/v2/user/12345
{
  "created": "2015-12-15T17:36:43+00:00", 
  "email": “exampleman@example.com",
  "group": {
  "id": 476618,
  "links": {
    "self": "https://api.hipchat.com/v2/group/54321"
  },
  "name": "example-team"
  },
  "id": 12345,
  "is_deleted": false,
  "is_group_admin": false,
  "is_guest": false,
  "last_active": "2015-12-15T21:22:39+0000",
  "links": {
    "self": "https://api.hipchat.com/v2/user/12345"
  },
  "mention_name": "ExampleMan",
  "name": "Example Man",
  "photo_url": "...",
  "presence": null,
  "roles": ["user"],
  "timezone": "America/Denver",
  "title": "Hero of Examples",
  "version": "...",
  "xmpp_jid": "..."
}

Less typical, however, is how difficult HipChat’s API makes it to get detailed information from a lot of resources at once. Take the get all users API call, which only returns a user’s ID and @mention name. If you want more detailed information, such as their email addresses, you have to make an additional API call for each user, which can quickly burn through your request limit (500 per five minutes).

Added to that is the difficulty of messaging a user directly, as mentioned previously. There are only a couple of ways to do so, and none of them are attractive. First, you could get an authentication token from a user, then send someone a direct message on behalf of that user, but this won’t work if you want the message to appear as though it came from your app. You could get around this by asking the HipChat admin to create a user for your app to send messages from, but that increases the overhead to use your integration.

Alternately, you could create a private room with the recipient and then push a message or notification to that room. This solution could lead to unwanted room clutter, and if you wanted to message that same user again, you’d have to take into account the original room, which limits your options:

  1. Keep track of the private room you created and make sure they haven’t left it.
  2. Instead of tracking the room, search the rooms they belong to, then create a private room if it doesn’t exist.
  3. Deal with the fact that you create a room every time you want to message someone.

None of these options are particularly appealing. It would be much better if HipChat would automatically create a bot user for your integration to handle messaging.

Slack

In contrast with HipChat’s RESTful approach, Slack went with the method-oriented RPC style. Slack’s API includes the status of each request in its responses alongside any other data appropriate for the request, which makes it resemble some sort of mutated plushy animal. But it’s a friendly, strangely adorable plushy animal, because Slack also documents exactly what every API call is going to do, including every error and warning not related to a server meltdown. Here’s an example.

cthulhu plushie
Ia! Ia! Slack fhtagn! Source

As a result, even though it’s not RESTful, Slack makes it easy to work with its APIs and to deal with any problems that occur as you tinker. Slack also has a generous rate limit, in that you can seemingly make any API call as much as you want except for ones that are directly visible to a user, like sending a message to a room. Those requests are limited to one per second on average. Example request:

curl -G https://slack.com/api/users.list?token=xxxx-xxxxxxxxx-xxxx
[{
  "id": "U1234567890",
  "team_id": "T1234567890",
  "name": "exampleman",
  "deleted": false,
  "status": null,
  "color": "8d4b84",
  "real_name": "Example Man",
  "tz": "America/Denver",
  "tz_label": "Mountain Daylight Time",
  "tz_offset": -21600,
  "profile": {
    "first_name": "Example",
    "last_name": "Man",
    "phone": "",
    "title": "Hero of Examples",
    ...
    "real_name": "Example Man",
    "real_name_normalized": "Example Man",
    "email": "exampleman@example.com"
  },
  "is_admin": false,
  "is_owner": false,
  "is_primary_owner": false,
  "is_restricted": false,
  "is_ultra_restricted": false,
  "is_bot": false,
  "has_2fa": false
},
...
]

That said, the API does have some questionable elements. One is that you can use both GET and POST requests for any API call (which does make it easy to see the results in your browser just by navigating to an endpoint). Another is that you can mix parameters in the query string and in the request body in POST requests. This doesn’t necessarily make it difficult or confusing to use, but it could theoretically result in someone actually mixing them together, making it more difficult to determine all the parameters when looking at the code. Slack also lacks an explicit uninstallation event, so if your app tries to actively communicate with Slack (instead of just responding to events via webhooks), you’ll have to handle the “this team has uninstalled your app” error codes everywhere in your code you make a request to Slack.

The Verdict

I may be nitpicking, but Slack’s issues are fairly minor in this area, while the difficulty of messaging HipChat users is substantial. This round goes to Slack.

Documentation

Any API worth its salt needs documentation. It’s no use having a bunch of unknown endpoints lying around, and, more than that, it’s important to show how to use the API. Good APIs document everything, and great APIs provide examples for every action.

HipChat

If there’s one thing that the Atlassian team has historically struggled with, it’s documentation. Building a P2 plugin for Confluence or JIRA Server can be an exercise in frustration and trial and error. What little information you can find is buried in old tutorials or in caches of plugins hidden deep in BitBucket repositories.

Fortunately, they seem to have recognized the issue, and their newer Connect framework is refreshingly well documented. HipChat uses this framework, and every available method has its own page with the required HTTP verbs, parameters, and response fields listed. The data required by or returned by the API calls is even given explicit types and sizes to make it easier to use. The only spot of confusion in the REST API docs has to do with generating an API token. There’s no explanation of what any of the grant types means or examples showing how you request each type.

Documentation for their GUI components is similarly reasonable, with a few caveats. As an example, take the Sidebar documentation. The Behavior and Full View sections make it sound like you have access to prepackaged components that you can easily include in your view. The Behavior section even links to Actions, which are components that can be attached to the message bar or to messages in chat, based on their content. Unfortunately, web panels aren’t given any such components, though there are JavaScript hooks to access the API from within the page, which would allow you to imitate Actions.

Slack

An RPC API requires more detailed documentation than a RESTful API like HipChat’s, where you can make some basic assumptions about what kinds of errors you’re likely to get and what they mean based on HTTP statuses. Thankfully, Slack’s API is very well documented, with examples on every method. Additionally, all the normal error and warning states are explicitly documented. That way, you know what issues to expect when using each method (assuming, of course, that the Slack team keeps their documentation up to date). My only complaint is that the exact bounds of what can and can’t be done with parameters and fields is never documented. For example, in usergroups.create, we have this:

description field

Is there a character limit for the description, or is the description’s description describing its purpose rather than its bounds? The only way I’d be able to find out is through trial and error. Similarly, fields in the responses aren’t explicitly bounded in type or size, though the examples can answer most of those sorts of questions.

The Verdict

HipChat and Slack both have pretty good documentation. All I can do is nitpick at a couple of spots in each, so this is a tie.

Conclusion

  • HipChat wins in: Functionality
  • Slack wins in: Usability
  • They tie in: Documentation

This is the part where you probably expect me to say “Since both of them won a round, they’re tied overall,” but not all of these categories are equally important. The scope of what you can accomplish with HipChat’s API is greater than that of Slack’s, and if you can get away without the ability to directly message users (or are willing to jump through the hoops to do it), it allows you to build superior integrations. That said, the simplicity of Slack’s API and apps can also be appealing. Feature creep, overdesigning, or even just visual clutter are quietly but firmly discouraged by Slack’s simple tools. Having more features is only useful if app developers use them in meaningful ways. Thus, while I think HipChat has the better API, in the end, it’s not just what you have, but how you use it.

2 Comments

  1. Rich ManalangMarch 30, 2016 at 11:44 am

    Nice fair evaluation. One thing regarding HipChat’s “get all users” api… you can use expansions to expand entities so you don’t have to make multiple calls. So for getting the full user entity, all you have to do is https://api.hipchat.com/v2/user?expand=items. More on title expansions here: https://developer.atlassian.com/hipchat/guide/hipchat-rest-api/api-title-expansion

  2. Whats about Mattermost? 🙂

Your email address will not be published.