api pain points (phpne)
DESCRIPTION
I've been building APIs for a long time now and it is becoming ever more common for server-side developer thanks to the rise of front-end JavaScript frameworks, iPhone applications and generally API-centric architectures. On one hand you're just grabbing stuff from a data source and shoving it out as JSON, but surviving changes in business logic, database schema updates, new or deprecated etc gets super difficult. This talk will outline the common pitfalls developers get trapped in when building APIs and outline methods to avoid them, including naming stuff badly then having to rename everything, when and how to use POST/PUT/PATCH, data structures, DDoSing yourself because pagination, picking your authentication system and all sorts of other stuff.TRANSCRIPT
A P I PA I N - P O I N T SGE TT I NG T H INGS W R O NG F O R F U N A ND PR O F I T
@P H ILST U R GE O N 2014
A RC H I T E C T U R EO LD SCH O O L
http://girlsgotsole.com/blog/thankful-thursday-rest-days/
DATA B A S E S E E D I N GLE AV E YO U R CU ST O ME R S A LO NE
E N D P O I N T T H E O RYNA MING T H I NGS I S H A R D
P LU RA L V S I N G U L A R ?CO NS IST E NCY I S K ING
/user/23
/users
P LU RA L V S I N G U L A R ?CO NS IST E NCY I S K ING
/opportunity/43
/opportunities
P LU RA L V S I N G U L A R ?CO NS IST E NCY I S K ING
/person/dave
/people
P LU RA L V S I N G U L A R ?CO NS IST E NCY I S K ING
/places/places/12/places/12/checkins/places/12/checkins/34/checkins/34
N O N E E D F O R S E OQ U E RY ST R I NGS A R E F I NE
/users/active/true
/users?active=true
A U T O - I N C R E M E N T = B A D
CT R L + S YO U R W E BS IT E
/checkins/1/checkins/2
/checkins/2369
…/checkins/3
A U T O - I N C R E M E N T = B A D
CT R L + S YO U R W E BS IT E
github.com/zackkitzmiller/tiny-php
$tiny = new \ZackKitzmiller\Tiny('lDpuU74QNH6B');
echo $tiny->to(5);// E
echo $tiny->from('E');// 5
A U T O - I N C R E M E N T = B A D
CT R L + S YO U R W E BS IT E
use Rhumsaa\Uuid\Uuid;use Rhumsaa\Uuid\Exceptio
$uuid4 = Uuid::uuid4();
echo $uuid4;// 25769c6c-d34d-4bfe-ba98-e0ee856f3e7a
github.com/ramsey/uuid
H TT P V E R BS M ATT E RH O NE ST LY
Dont be @jamiehannaford. That sounds like a bad day.
F O R M PAY LOA D SJ U ST SE ND J SO N
foo=something&bar[baz]=thing&bar[stuff]=junk&bar=true
H AC KY PAY LOA D SNO T L IKE T H AT
R E A L J S O N PAY LOA D ST H NX!
R E A D I N G R E A L DATA I S E A S Y
T H E H TT P WAY
json_decode($_POST['stupid-json']);
json_decode(file_get_contents(‘php://input'));
Input::get(‘foo’);
200 I S NOT THE ON LY S UC C ES S
KNO W YO U R CO DE S
if ($statusCode != 200) {throw new Exception('AAGHH!!');
}
2xx is all about success3xx is all about redirection
4xx is all about client errors5xx is all about service errors
200 - Generic everything is OK
201 - Created something OK
202 - Accepted but is being processed async
400 - Bad Request (Validation?)
401 - Unauthorized
403 - Current user is forbidden
404 - That URL is not a valid route
405 - Method Not Allowed
410 - Data has been deleted, deactivated, suspended, etc
500 - Something unexpected happened and it is the APIs fault
503 - API is not here right now, please try again later
418 - I am a Teapothttp://httpstatus.es/418
C L E A R , H U M A N E R R O R S
W H AT H A PPE NE D
{ "error": { "errors": [ { "domain": "youtube.parameter", "reason": "missingRequiredParameter", "message": "No filter selected.", "locationType": "parameter", "location": "" } ], "code": 400, "message": "No filter selected." }}
E R R OR S S H OUL D MA K E S E N S E
W H AT H A PPE NE D
&mine=true
"reason": "missingRequiredParameter", "message": "No filter selected.",
…
WTF
S U PPL E M E N T H TT P C O D E S
W H AT H A PPE NE D
{"error": {
"type": "OAuthException", "message": "Session has expired at unix time 1385243766. The current unix time is 1385848532"}
}
S U PPL E M E N T H TT P C O D E S
W H AT H A PPE NE D
{ "error": { "message": "(#210) Subject must be a page.", "type": "OAuthException", "code": 210 }}
S U PPL E M E N T H TT P C O D E S
W H AT H A PPE NE D
{ "error": { "message": "(#210) Subject must be a page.", "type": "OAuthException", "code": 210, "url": “http://developers.facebook.com/errors#210“ }}
OA U T H 2 . 0
thephpleague.com
github.com/thephpleague/oauth2-server
OA U T H 2 C AN D O A LO T
PA SSW O R DS , I MPL IC I T , SO C IA L LO G INS…
U S E S S L
LO LE XCE PT F O R …
FAC E BOOK … YOU B#% @*DS ! ! !
SE R IO U SLY
Refresh Tokens?
Lol
YO U T U B E … YO U S E M I -B #% @ * D S ! ! !
ST I LL SE R IO U SLY
Refresh Tokens?
Kinda
P R E S E N TAT I O N L AY E RDO NT LE T U SE R S BE H IND T H E CU RTA IN
return Places::all();
P R E S E N TAT I O N L AY E RDO NT LE T U SE R S BE H IND T H E CU RTA IN
T RA N SFORM E RS… A SSE M B L E !
public function transform(Book $book) { return [ 'id' => (int) $book->id, 'title' => $book->title, 'year' => $book->yr, ‘created' => (string) $book->created_at, ]; }
fractal.thephpleague.com
F L E X I B L E R E S P O N S E SST O P YO U R I P H O NE DE V CO MP L A IN I NG
GET /checkins/dsfXte ?include=place,user,activity
PAG I N AT EDATA GR O W S FA ST
{"data": [
...],"cursors": { "after": "MTI=", "next_url": "https://api.example.com/places
?cursor=MTI%3"}
}
D E F I N E A L I M I T RA N G EPAG INAT IO N DDO S
if ($limit < 1 || $limit > 100) {$limit = 100;
}
A U T O M AT E T E S T I N GIF YOU LOVE YOUR JOB
http://www.engineersgotblued.com/
P H P U N I T + B E H AT
http://www.bil-jac.com/bestfriendsclub.php
Scenario: Find a merchant
When I request "GET /moments/1"
Then I get a "200" response
And scope into the "data" property
And the properties exist:
"""
id
title
year
created
"""
Scenario: Try to find an ` checkinWhen I request "GET /checkins/nope"Then I get a "404" response
Scenario:Wrong Arguments for user followGiven I have the payload:
""" {"is_following": "foo"} """
When I request "PUT /users/1”Then I get a "400" response
Not a boolean
apiblueprint.org
V E R S I O N I N G/ V 1 /DO E SNT CO U NT
https://api.example.com/v1/places
V E R S I O N I N G/ V 1 /DO E SNT CO U NT
https://api-v1.example.com/places
V E R S I O N I N G/ V 1 /DO E SNT CO U NT
Accept: application/vnd.example+json; version=1
Accept: application/vnd.example+json; version=2
V E R S I O N I N G/ V 1 /DO E SNT CO U NT
Accept: application/vnd.example.user+json; version=1
Accept: application/vnd.example.user+json; version=2
V E R S I O N I N G/ V 1 /DO E SNT CO U NT
Copy Facebook
Maybe?
THIS ONE TIME!
Facebook ruined the one good thing they ever did
E V E RY T H I N G I S W R O N GDO NT BE T H AT GU Y
troyhunt.com/2014/02/your-api-versioning-is-wrong-which-is.html
leanpub.com/build-apis-you-wont-hate/c/TOONARMY