How to create a Web API

no one wants to use

By Karoline Klever / @karolikl

Taking a look

at the world of Web APIs...

Your car has one

Chuck Norris has one

Your dog has one

The number of Web APIs

is increasing fast

Web API growth 2005-2013

1995

"Why do we need a website?"

2000

"Of course we have a website!"

2005

"Why do we need an API?"

2010

"Of course we have an API!"

URI Design

Badly named and inconsistent URIs that violate the Principle of Least Astonishment will make your web API just as disappointing as the movie "Sharknado".

Principle of Least Astonishment

"[...] a programmer should try to think of the behavior that will least surprise someone who uses the program, rather than that behavior that is natural from knowing the inner workings of the program."

Problem #1

Inconsistent URI structure

We cannot guess the URI of an endpoint based on our experience with the other endpoints.

Problem #2

URIs are not hackable

/all_links_for_city_of/chicago/il.json

/all_links_for_city_of/chicago/il.json

/all_links_for_city_of/chicago/il.json

Problem #3

Link types

/all_links_for_city_of/chicago/il.json

/all_links_for_county_of/cook%20county/il.json

/primary_links_for_city_of/chicago/il.json

/primary_links_for_county_of/cook%20county/il.json

Possible solution

(One of many)

/links

/links/il

/links/il/cook%20county

/links/il/cook%20county/chicago

/links/il/cook%20county/chicago?type=primary

HTTP Verbs

Why do we need anything other than GET?

The most commonly used

GET

PUT

POST

DELETE

Safe methods

"... the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe"."

Are they safe?

GET: Yes

PUT: No

POST: No

DELETE: No

Idempotent methods

Methods we can issue the same request against as many times as we want without changing the result.

Are they idempotent?

GET: Yes

PUT: Yes

POST: No

DELETE: Yes

Get climate

GET /vehicles/{id}/command/climate_state

{
    "inside_temp": 17.0,       
    "outside_temp": 9.5,         
    "driver_temp_setting": 22.6, 
    "passenger_temp_setting": 22.6, 
    "is_auto_conditioning_on": false, 
    "is_front_defroster_on": null,
    "is_rear_defroster_on": false,
    "fan_status": 0             
}
                        

Open sunroof

GET /vehicles/{id}/command/sun_roof_control?state=open

Possible solution

GET /vehicles/{id}/command/sun_roof_control

{
    "state": "open"       
}
                        
PUT /vehicles/{id}/command/sun_roof_control?state=open

{
    "result": true       
}
                        

The other Verbs?

GET Returns the state of the sun roof (open/closed)
PUT Open/close the sunroof
POST Not supported, cannot create new sun roof
DELETE Not supported, cannot delete sun roof

A must read

Section 9 «Method definitions» in RFC 2616

https://tools.ietf.org/html/rfc2616#section-9

HTTP Status Codes

Everyone just loves an "error in disguise".

Problem #1

Disguising your errors

Invalid requests return with a 200 OK status code, giving the impression that the request was successful.

Problem #2

Displaying your internals

Including a detailed error report or stack trace makes your Web API vulnerable to attack

The basics

2xx Awesome!
4xx The user of the API made a mistake
5xx The creator of the API made a mistake

Possible solution

GET http://api.worldbank.org/countries/a?format=json 
404 Not Found
GET http://api.worldbank.org/topic?format:json 
400 Bad Request

A must read

Section 10 «Status Code Definitions» in RFC 2616

https://tools.ietf.org/html/rfc2616#section-10

Result Formatting

Dictating the format will drive developers away.

XML is on decline

Hurray!

Bye XML

Possible solutions

  • URL extensions
  • Query string parameters
  • Content negotiation

Versioning

However perfect you make your web API, you're bound to find a way that's even more perfect before long, and then you'll need to launch a new version.

Capture5 -> Complete / Cancel2

URL versioning

GET https://api.twitter.com/1.1/trends/place.json?id=1 

Query string parameters

GET http://api-public.netflix.com/catalog/titles/series/7002352?v=1.5 
GET https://api.foursquare.com/v2/venues/40a55d80f964a52020f31ee3?oauth_token=XXX&v=YYYYMMDD 

Vendor Specific Accept Header

HEADER Accept: {type}/vnd.{company}.{version}+{type}
HEADER Accept: {type}/vnd.{company}+{type}; version={version}
HEADER Accept: application/vnd.github.v3+json
HEADER Accept: application/vnd.github+json; version=3

Custom Request Header

HEADER x-ms-version: 2014-02-14
HEADER api-version: 2

Summary

URI design

HTTP Verbs

HTTP Status Codes

Result Formatting

Versioning

Questions?

Thank you!

By Karoline Klever / @karolikl / karolikl@gmail.com