Why Consistency Matters Across the Media Types Offered by an API

Over on DZone -- one of my favorite app development sites -- Toyella technical director Rob Allen has published a rather opinionated post regarding the all-important "media-type" component of RESTful APIs while also delving into the religious debate of what is and what is not a RESTful API. This analysis started out as my response to the article but I exceeded DZone's maximum allowable character count for a comment and so I've decided to publish my response here on ProgrammableWeb.com.

The opinion piece raises a couple of important points regarding how and why API providers should properly apply media types in their APIs and how API providers may not be doing enough. So I decided to put Allen's theory to a little test.

First and foremost, what is a media type? If you're not familiar with APIs or the Web, this alone can be a somewhat confusing matter because conversationally, the phrase "media type" is often used interchangeably with the phrase "content type." The conversations between a Web browser and a Web server, or between an API client (like a Web or mobile app) and a Web API are typically prefaced by a preamble (known as the HTTP header) that includes a hint about the format of the data being sent from one to the other. This hint typically appears in one of the HTTP header's fields; the Content-Type field. To get a hands-on idea of how this works and to see it action for yourself, I suggest you read my 101-level article on how to use the cURL command to examine the contents of a Web API's header.

In that article, I offer an example of the HTTP header that's returned by The Weather Underground's API:

HTTP/1.1 200 OK
Server: Apache/2.2.15 (CentOS)
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
X-CreationTime: 0.154
Last-Modified: Mon, 29 Aug 2016 14:12:32 GMT
Content-Type: application/json; charset=UTF-8
Expires: Mon, 29 Aug 2016 14:12:32 GMT
Cache-Control: max-age=0, no-cache
Pragma: no-cache
Date: Mon, 29 Aug 2016 14:12:32 GMT
Connection: keep-alive

The seventh field down shows the content type. It basically says the data to follow is formatted (aka "serialized") using Javascript Object Notation (JSON).

In his post, Allen argues that "The majority of HTTP APIs out there do not reap the benefits of using media types correctly either."  He goes onto say that, "The majority seem to use application/json [as the Content Type] and call it done. The client gets absolutely no information about how to read the data, other than they'll need a JSON decoder." As best as I can tell, the source of Allen's frustration has to do with the non-standard representation of data within a subject matter domain. To see if he has a point, let's take an example like the subject matter domain of "weather reports." I decided to retrieve the current weather conditions for the Union Square area of San Francisco (area code 94107) from two different APIs; the aforementioned Weather Underground API and the OpenWeatherMap API. Here's the JSON-serialized data returned by the Weather Underground API, followed by the JSON-serialized data returned by the OpenWeatherMap API for the same zip code:

JSON from Weather Underground for area code 94107:

{
  "response": {
  "version":"0.1",
  "termsofService":"http://www.wunderground.com/weather/api/d/terms.html",
  "features": {
  "conditions": 1
  }
    },
    "current_observation": {
        "image": {
        "url":"http://icons.wxug.com/graphics/wu2/logo_130x80.png",
        "title":"Weather Underground",
        "link":"http://www.wunderground.com"
        },
        "display_location": {
        "full":"San Francisco, CA",
        "city":"San Francisco",
        "state":"CA",
        "state_name":"California",
        "country":"US",
        "country_iso3166":"US",
        "zip":"94107",
        "magic":"1",
        "wmo":"99999",
        "latitude":"37.76834106",
        "longitude":"-122.39418793",
        "elevation":"5.00000000"
        },
        "observation_location": {
        "full":"Potrero Hill, San Francisco, California",
        "city":"Potrero Hill, San Francisco",
        "state":"California",
        "country":"US",
        "country_iso3166":"US",
        "latitude":"37.769039",
        "longitude":"-122.402245",
        "elevation":"20 ft"
        },
        "estimated": {
        },
        "station_id":"KCASANFR880",
        "observation_time":"Last Updated on August 29, 7:23 AM PDT",
        "observation_time_rfc822":"Mon, 29 Aug 2016 07:23:10 -0700",
        "observation_epoch":"1472480590",
        "local_time_rfc822":"Mon, 29 Aug 2016 07:23:14 -0700",
        "local_epoch":"1472480594",
        "local_tz_short":"PDT",
        "local_tz_long":"America/Los_Angeles",
        "local_tz_offset":"-0700",
        "weather":"Overcast",
        "temperature_string":"57.9 F (14.4 C)",
        "temp_f":57.9,
        "temp_c":14.4,
        "relative_humidity":"83%",
        "wind_string":"From the West at 6.5 MPH Gusting to 9.8 MPH",
        "wind_dir":"West",
        "wind_degrees":281,
        "wind_mph":6.5,
        "wind_gust_mph":"9.8",
        "wind_kph":10.5,
        "wind_gust_kph":"15.8",
        "pressure_mb":"1019",
        "pressure_in":"30.10",
        "pressure_trend":"0",
        "dewpoint_string":"53 F (12 C)",
        "dewpoint_f":53,
        "dewpoint_c":12,
        "heat_index_string":"NA",
        "heat_index_f":"NA",
        "heat_index_c":"NA",
        "windchill_string":"NA",
        "windchill_f":"NA",
        "windchill_c":"NA",
        "feelslike_string":"57.9 F (14.4 C)",
        "feelslike_f":"57.9",
        "feelslike_c":"14.4",
        "visibility_mi":"10.0",
        "visibility_km":"16.1",
        "solarradiation":"30",
        "UV":"0.0","precip_1hr_string":"0.00 in ( 0 mm)",
        "precip_1hr_in":"0.00",
        "precip_1hr_metric":" 0",
        "precip_today_string":"0.00 in (0 mm)",
        "precip_today_in":"0.00",
        "precip_today_metric":"0",
        "icon":"cloudy",
        "icon_url":"http://icons.wxug.com/i/c/k/cloudy.gif",
        "forecast_url":"http://www.wunderground.com/US/CA/San_Francisco.html",
        "history_url":"http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=KCASANFR880",
        "ob_url":"http://www.wunderground.com/cgi-bin/findweather/getForecast?query=37.769039,-122.402245",
        "nowcast":""
    }
}

JSON from OpenWeatherMap for area code 94107:

{
"coord": {
"lon": -122.42,
"lat": 37.77
},
"weather": [
{
"id": 804,
"main": "Clouds",
"description": "overcast clouds",
"icon": "04d"
}],
"base": "cmc stations",
"main": {
"temp": 289.2,
"pressure": 1020,
"humidity": 72,
"temp_min": 285.93,
"temp_max": 299.15
},
"wind": {
"speed": 5.1,
"deg": 280
},
"clouds": {
"all": 90
},
"dt": 1472487707,
"sys": {
"type": 1,
"id": 478,
"message": 0.0141,
"country": "US",
"sunrise": 1472477898,
"sunset": 1472524884
},
"id": 5391959,
"name": "San Francisco",
"cod": 200
}

Though it's only anecdotal evidence (not scientifically representative of the entire API economy), this one small example supports Allen's theory.  These are two very different representations of the current weather at the US ZIP Code 94107. Furthermore, perhaps to Allen's point, there's an additional problem that's not readily apparent to the human eye.

David Berlind is the editor-in-chief of ProgrammableWeb.com. You can reach him at david.berlind@programmableweb.com. Connect to David on Twitter at @dberlind or on LinkedIn, put him in a Google+ circle, or friend him on Facebook.

Comments