Todo lo que necesitas saber a la hora de diseñar RESTful APIsby @jespejo89
MADRID · NOV 18-19 · 2016
Technical Telecom Engineer Field: Telematics.
Doing web stuff since 2007Probably a bit earlier…
Lead Back-End Engineer at LOOPSince 2013. Between Salzburg and Berlin.
jespejo89jespejo89
Passionate about Web Services / APIsAnd skydiving.
Jesús Espejo
ABOUT ME
STRATEGYSET THE FRAME
DESIGN AND UXADD SOUL
TECHNOLOGYMAKE IT WORK
SOCIALMAKE ‘EM TALK
MOBILEFIRST CHOICE
INNOVATIONALL SET FOR 2020
MOTIONAND PHOTOGRAPHY
CONTENTAND INFLUENCERS
ACTIVATIONTARGET THEM
ANALYTICSUNTIL IT‘S DONE
ABOUT LOOP
WHAT IS AN API?
An API is a user interfacefor developers.
WHAT IS REST?
REpresentational State Transfer.
“REST is an architectural style to design networked applications.”
WHAT IS A RESTFUL API?
“An API can be considered RESTful when it conforms the REST constraints.”
Client <-> Server Layered System
Cacheable Stateless
Code on Demand (op) Uniform Interface
RESTFUL APIS
A fully RESTful API is hard to build.
RESTFUL APIS
We don’t really need a fully RESTful API.
PRAGMATIC REST
RESTafarians vs
Pragmatic REST
Definition by Mike Schinkel: http://mikeschinkel.com/blog/whatisarestafarian/
WHAT MAKES AN API GOOD?
* It’s intuitive.
* It’s flexible.
* It’s secure.
I N T U I T I V ERESOURCES | ACTIONS | ENDPOINTS | DATA FORMAT | ERRORS
A GOOD API IS…
It’s all about resources and actions.
RESOURCES / ACTIONS
RESOURCES / ACTIONS
Use nouns (resources), not verbs.
/getArtists/getAlbums/getPlaylists/getGenres/getUsers...
√X/artists/albums/playlists/genres/users...
To define endpoints. Plurals better than singulars.
RESOURCES / ACTIONS
2 base URIs needed per resource.
/getArtists/getArtistById?id={ID}/getPlaylists/getPlaylistsById?id={ID}/getAlbums...
√X/artists/artists/{ID}/playlists/playlists/{ID}/albums...
For a collection and for a single resource in the collection.
RESOURCES / ACTIONS
HTTP verb for action
GET /getArtistsPOST /createArtistPOST /updateArtist?id={ID}POST /deleteArtist?id={ID}POST /searchSongs...
√
X
GET /artistsPOST /artistsPUT /artists/{ID}PATCH /artists/{ID}DELETE /artists/{ID}...
GET à Retrieve resourcePOST à Create resourcePUT à Update (full) resourcePATCH à Update (partially) resourceDELETE à Delete resourceHEAD à Extract info on resourceOPTIONS à Inspect operations on resource
GET /artists/{ID}/albums
* Relations? *
RESOURCES / ACTIONS
GET /artists?genre=rock&sort=name* Filtering? *
POST /playlists/{ID}/songs
DELETE /playlist/{ID}/song/{ID}
RESOURCES / ACTIONS
* What about other actions? *
POST /sign-‐in
PATCH /playlists/{ID}/public
GET /artists/{ID}/related
POST /playlist/{ID}/subscribe
GET /songs/search?q=<terms>
GET /search?artists=false&q=<terms>
DATA EXCHANGE
JSON as data exchange format.For requests and responses.
DATA EXCHANGE
{“data”: {
. . .},
“meta”: {“code”: 200,. . .
},
“paging”: {“next”: “...”, “previous”: “...”, “count”: 123
}}
}}
}
Requested data
(single or collection)
Additional data
(not explicitly requested)
Pagination data
(for collections)
DATA EXCHANGE
POST / PUT / PATCH
Accept: application/jsonContent-‐Type: application/json
{“field” : “value”,“another_field” : [
{ “key_1” : “val_1”
},{
“key_2” : “val_2”}
],}
}Request body
DATA EXCHANGE
* What about file uploads? *
OR
Upload them via POST encoded as
multipart/form-‐dataalong with other
data needed.
Upload them via POST encoded with
the content type of the file that is
being uploaded.
Content-‐Type: multipart/form-‐data; boundary=MultipartBoundary
Content-‐Type: image/jpegContent-‐Type: video/mp4
...
ERRORS
HTTP Status Code: 200
{“code” : 500“error” : “Ooops! Something happened”
}
2xx à All fine, keep coding J200 à OK201 à Created204 à No content
...3xx à Redirections/Caching J
304 à Not Modified...
4xx à Client issues L400 à Bad Request403 à Forbidden404 à Not found405 à Method Not Allowed
...5xx à Server issues L
500 à Internal Server Error503 à Service Unavailable501 à Not implemented
...
* HTTP Status Codes *
HTTP Status Code: 400
{“code” : 400“message” : “Validation failed”,“errors” : [{
“field” : “first_name”,“message” : “first_name is mandatory”,
},... ]
}
√
X
S E C U R EAUTHENTICATION | SSL | THROTTLING
A GOOD API IS…
SECURITY
In general, same security principles as
in web should be applied.
AUTHENTICATION
Sessions?
AUTHENTICATION
Authorization: Bearer <JWT>
Via header:
/endpoint?access_token=<JWT>
Via URL:
√
!
OAuth 2.x
JWTokensand/or
* Sessions: A RESTful API should be stateless.
* HTTP Basic Auth via credentials.* Re-invent the wheel:
“We have something similar to OAuth…”
“We have our own authentication system based on tokens…”
X
SSL E V E R Y W H E R E
RATE LIMITING
X-‐Rate-‐Limit-‐Limit
Add request-rate limits.In order to prevent abuse.
Inform API consumers via custom headers:
Number of allowed requests per given time-window.
X-‐Rate-‐Limit-‐RemainingNumber of remaining requests for the
given time-window.
X-‐Rate-‐Limit-‐Reset-‐InNumber of seconds until the given
window is reset.
REST Security Cheat Sheet:https://www.owasp.org/index.php/REST_Security_Cheat_Sheet
F L E X I B L EVERSIONS | PAGINATION | PARTIAL OBJECTS | CACHE | COMPRESSION
A GOOD API IS…
VERSIONING
* As URL query string */artists?v=1.0
* As header *Custom header: X-‐API-‐Version
Accept: application/song+json;v=2Content-‐Type: application/song+json;v=2
* As URL segment */2016-‐09-‐30/artists
/v1/artists
* As a combination*/v1/artists + Headers
/artists?v=1.0 + Headers
Should I version my API?It depends. But probably yes.
PAGINATION
/v1/artists/{ID}/songs?range=20-‐30.
/v1/artists/{ID}/songs?offset=20&limit=10.
/v1/artists/{ID}/songs?next=NDMyNzQyODI3OTQw.
/v1/artists/{ID}/songs?since=1364849754&limit=10
Support pagination on collections.
PAGINATION
GET /artists/{ID}/songs?offset=30&limit=10
HTTP Status Code: 200 OK
{ ...“data” : {
“songs” : [ . . . ]},“paging” : {
“next” : “https://api.domain.com/v1/artists/{ID}/songs?offset=40&limit=10”, “previous” : “https://api.domain.com/v1/artists/{ID}/songs?offset=20&limit=10”,“count” : 187
}}
Link: <https://api.domain.com/v1/artists/{ID}/songs?offset=40&limit=10>; rel="next”,<https://api.domain.com/v1/artists/{ID}/songs?offset=20&limit=10>; rel="last"
}}
Body
Header
PARTIAL / EMBED OBJECTS
GET /v1/artists?fields=id,name,genres
&embed=albums.id,albums.name,albums.songs.id,albums.songs.name
Allow retrieving partial and embed objects.{ ...
“data” : {“artists” : {
“id” : “2fs4a6b8c0”,“name” : “Flight Facilities”,“genres” : [ “electro”, “funk”, “indie” ],“albums” : [{
“id” : “6cb8a6f287”,“name” : “Foreign Language (Remixes)”“songs” : [{
“id” : “5c700cabf1”,“name” : “Foreign Language”
}]
},...
...
CACHING
ETag: “0e0ab07cc5ea8cc07ae68f3aa277b1b6”.
If-‐None-‐Match: “0e0ab07cc5ea8cc07ae68f3aa277b1b6”
Cache data at HTTP level.Even dynamic data.
* ETag header *Last-‐Modified: “Sun, 06 Nov 1994 08:49:37 GMT”
.If-‐Modified-‐Since: “Sun, 06 Nov 1994 08:49:37 GMT”
* Last-Modified header *
COMPRESSION
Accept-‐Encoding: gzip, deflate
* Headers *
Compress responses.Whenever the client supports it.
Content-‐Encoding: gzip
H A T E O A SHYPERMEDIA AS THE ENGINE OF APPLICATION STATE
HYPERMEDIA AS THE ENGINE OF APPLICATION STATE
“A REST client needs no prior knowledge about
how to interact with any particular application
beyond a generic understanding of hypermedia.”
HATEOAS
HATEOAS
HATEOAS
GET /v1/artists/c45f8acb90
{“data”: {
“id” : “8c7d57fa90”,“name” : “Foals”,“links” : [
{“rel” : “self”,“uri” : “https://api.domain.com/v1/artists/c45f8acb90”
},{
“rel” : “artist.albums”,“uri” : “https://api.domain.com/v1/artists/c45f8acb90/albums”
},{
“rel” : “artist.related”,“uri” : “https://api.domain.com/v1/artists/c45f8acb90/related”
}]
}}
Auto-discoverable resources
Always keep in mind the
problem you are trying
to solve.
Be pragmatic.
Credit : Troy Hunt (@troyhunt)
Q U E S T I O N S
THANK YOUFOR YOUR ATTENTION
VISIT OUR WEBSITE
www.agentur-loop.com