All you need to know when designing RESTful APIs

Post on 08-Jan-2017

655 views 1 download

Transcript of All you need to know when designing RESTful APIs

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