developers are users too #yourapisucks
TRANSCRIPT
Developing Android Apps With Xamarin in C#
http://bit.ly/xamarin-edin
2 Days : 10th – 11th November, Edinburgh
Discount code to get an additional £100 off early bird tickets : EB100
Talk my language
Using your domain terms rather than
mine
Line1: 1A Queen Anne Drive,
Line2: Lochend Ind Estate
City: Edinburgh
Postcode: EH28 8PL
Postcode: EH28 8PL
Easting: 8212096
Northing: -6213914Postcode: EH28 8PL
Weakest link
Using basic, or no authentication. You
should not be my weakest link
http://www.example.com/api/pay
?cardnumber=12341234123412
34&ccv=1234&expirymonth=12&
expiryyear=12&amount=123456
Open kimono
Unsecured authentication
http://www.example.com/api
/pay?username=bob&passw
ord=supersecret
Side effects
Not understanding idempotence. I can
just about forgive post everything, but
not get with side effects
http://www.example.com/api/createTransaction?...
Busy waiting?
Don’t keep the caller waiting. If it’s
going to take a while, use callbacks or
another form of notification.
Exceptional validation
Returning exceptions as validation.
Validate everything, and return
multiple errors.
And don’t return errors on an
alternative channel (such as email).
NOT:
HTTP 500 - Credit Card number invalid
BETTER:
HTTP 400
{
validationErrors: [
{“CreditCardNumber” : “Must be 16
characters”}
{“ExpiryDate” : “Must be in the future”}
{“CCV” : “Is required”}
]
}
A forest of confusion
Multiple, inconsistent APIs, especially
inconsistent authentication
GET /cat
{ Name : “Garfield” }
GET /food/index.php/fooditem/1
🍌
Inconsistent behaviour
Inconsistent behavior
GET /cat
{ Name : “Garfield” }
GET /cat
{ Name : “Jatt” }
GET /cat
{ Name : “Lion-o” }
GET /cat
🍌
Breaking the contract
Adding versioning to an existing API,
poorly - breaking the contract. See
http://www.troyhunt.com/2014/02/yo
ur-api-versioning-is-wrong-which-
is.html
Today:
http://www.example.com/api/getAddress?postcode=
EH28%208PL
Tomorrow:
HTTP POST
http://www.example.com/api/getAddress
X-www-form-urlencoded
API-version: “v1.1”
Search-type: “postcode-lookup”
Input: “EH28 8PL”
Verbosity compounds reducible complexity
E.g. Win32 API is often cryptic and
long-winded
Use sensible defaults
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = WndProc;wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = hInstance;wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));wcex.hCursor = LoadCursor(NULL, IDC_ARROW);wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName = NULL;wcex.lpszClassName = szWindowClass;wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
if (!RegisterClassEx(&wcex)){
MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Win32 Guided Tour"), NULL);return 1;
}
hInst = hInstance; // Store instance handle in our global variableHWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,500, 100, NULL, NULL, hInstance, NULL );
if (!hWnd){
MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Win32 Guided Tour"), NULL);
return 1;}
ShowWindow(hWnd,nCmdShow);UpdateWindow(hWnd);
MSG msg;while (GetMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg);DispatchMessage(&msg);
}return (int) msg.wParam;
}
HWND hWnd = CreateWindow(
szWindowClass,szTitle,
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,500, 100,NULL,NULL,hInstance,NULL
);
https://msdn.microsoft.com/en-
us/library/bb384843.aspx
Errors as a side effect
Return code is a constant, errors are a
side effect (HTTP 200, or return -1 in
C)
Success : ERROR -
Credit Card Expiry Date is in the past
Hidden Prerequisites
Hidden prerequisites - throwing an
error when submitting an order
because you didn't call
ExpectCreditCard first
You said what?
Documentation out of sync with code.
Try swashbuckling
getPostcode(double opt)
This method takes returns
the current longitude and
latitude of the user based
on the information provided
by their device.
Sucking Eggs
Teaching Granny to suck eggs
getAddressFromPostcode
(string postcode)
This method takes a
postcode and returns the
associated address.
Use the platform
Legacy models VS JSON-native {
Name : “Your Woman”
Address : “<Line1>My House</Line1>
<Line2>My Street</Line2>
<Town>White Town</Town>
<Postcode>EE11EE</Postcode>”
}
Strawman Testing
Test data / API out of sync with live
Testing the wrong thing
Planet Earth (for testing only)
Tests doomed to succeed
Incomplete test data: imagine
postcode lookup where test addresses
are all SW...
No Flat x/y
No BFPO
No Irish or other EU addresses
Takeaways : avoiding the axe
User first : Design from the outside in
If there’s a standard, use it
Be consistent
Be clear
Be helpful, but only when asked
Over to youHave you seen an API that
sucked?
https://craignicol.wordpress.com
https://twitter.com/craignicol
https://plus.google.com/+CraigNicolGeek
Continue the discussion at theCodeCraftConf, 16th September at CitizenM : http://conf.codecraftuk.org/
10% Ticket Discount with code DevsUsersToo
I’ll be guiding a session on Writing Usable APIs