Slide 1

Slide 1 text

RESTful APIs - Versioning and Caching Hendrik Saly, codecentric AG

Slide 2

Slide 2 text

Representational State Transfer Constraints Uniform interface Stateless Cacheable Layered system

Slide 3

Slide 3 text

REST Maturity Model Level Meaning HTTP methods used 1 XML-RPC/SOAP with only one endpoint URI POST 2 Different endpoints and resources POST 3 Different endpoints and resources GET, POST, PUT, DELETE, … 4 Different endpoints and resources, HATEOAS GET, POST, PUT, DELETE, … (Typically level 3 is implemented)

Slide 4

Slide 4 text

HATEOAS Hypermedia as the Engine of Application State Response contains hyperlinks to other resources Kind of finite state machine Not widely used { "name": "Foo", "links": [ { "rel": "self", "href": "http://localhost:8080/customer/1" } ], "details": "/details/1" }

Slide 5

Slide 5 text

Meaning of HTTP methods Method Meaning Safe Idempotent Cacheable Has Body GET Read Y Y Y Response only HEAD Same as GET without body Y Y Y N POST Create N N Y Request/Response PUT Upsert N Y N Request/Response DELETE Delete N Y N Response only OPTIONS returns the HTTP methods that the server supports Y Y N Response only PATCH, TRACE, CONNECT, etc. are out of scope here

Slide 6

Slide 6 text

Meaning of HTTP methods (2) URI type GET PUT POST DELETE Collection List of elements or URIs Replace entire collection create new collection delete complete collection Element Return element Replace or create element - delete element

Slide 7

Slide 7 text

API versioning Why this might be necessary? API evolves over time Adding new resources or response parts is not critical but Renaming and/or deletion is Two possibilities to solve this Encode version of the API in the URI Encode version of the API in a header Depends especially on the type of client (Browser or other)

Slide 8

Slide 8 text

URI versioning Pros Simple and clearly visible by looking on the URI Cons Its difficult to use separate parts of the API in different versions simultaneously Same resources have different URIs (REST constraint violation) Problem if client stores/bookmarks URIs cause also the version is stored along with the URI Can be used together with a Link header to relocate to newest API version /api/v1/customers/3

Slide 9

Slide 9 text

Header versioning (Content negotiation) Pros Its easy to use separate parts of the API in different versions simultaneously Same resources have same URIs No problems with stored/bookmarked URIs Accept Header supports more than one version Accept: application/vnd.myapp-v1+json

Slide 10

Slide 10 text

Header versioning (Content negotiation) (2) Cons Header is hidden You need own (self defined) mime types (thats no a real problem so far) To make HTTP caching work a Vary: Accept header is needed to make the Accept header part of the cache key Not widely spread (most devs are unfamiliar with that approach)

Slide 11

Slide 11 text

API versioning - best practice Keep it simple for the developers and implement URI versioning Provide a non versioned URI alias which point to the most recent version For more complicated situations use Link header

Slide 12

Slide 12 text

API caching Make sure all servers, proxies, web caches and clients support HTTP 1.1 Purpose is to decrease utilization of network bandwith/latency and discharge load on backend systems/HTTP server and therefore gain more performance (handle more load, increase responsiveness) Only GET and HEAD is cacheable If you not have such problems (and you don’t expect them in the future) do not use caching because there are several downsides

Slide 13

Slide 13 text

API caching (1) Downsides Stale responses Invalidation Can get very complex Depending on a cache makes the cache mandatory

Slide 14

Slide 14 text

API caching (2) There are three possibilities for caching: Let the browser do it Let the client do it (for example AngularJS caching) Cache costly backend operation on the server side (Not really API caching)

Slide 15

Slide 15 text

API caching (3) Client side caching can reduce utilization of network bandwith and load on backend systems Clients are responsible, needs probably programming If client is a browser it depends on the implementation of the browser (IE and Safari might show bugs) It also depends on the infrastructure between the client and the originating server (proxies, webcaches, … ) For browser caches or HTPP 1.1 compliant client it work May i cache? If cached is it fresh? If stale is it valid on the server?

Slide 16

Slide 16 text

States of Resource Representation Up-to-date (same as origin server) Fresh (as long as its not expired on client or proxy) Stale (expired)

Slide 17

Slide 17 text

HTTP Cache-Control header An easy and simple method is to use the HTTP 1.1 Cache-Control header to indicate when a resource response is outdated. Until this point in time the browser will not connect to the rest endpoint but will server the response from its cache. What May be Stored by Caches (request/response) no-store no caching at all What is Cacheable (response only) public by any cache, no revalidation if fresh private by any non shared cache, no revalidation if fresh no-cache by any cache, enforce revalidation even if fresh (request/response)

Slide 18

Slide 18 text

HTTP Cache-Control header (1) Expiration mechanism (request/response) max-age client is willing to accept a response whose age is no greater than the specified time Cache Revalidation and Reload Controls (response only) must-revalidate do an end-to-end revalidation every time proxy-revalidate sames as must-revalidate but not for private caches

Slide 19

Slide 19 text

HTTP Cache-Control header (2) But thats really only suitable for static resources like CSS, Javascript, Images, etc. and not recommended for representations of business domain objects. Therefore do not use it for API caching.

Slide 20

Slide 20 text

Validators If stale validate on the server. Last-Modified header (Time-based) ETag (Entity-Tag) header (Content-based)

Slide 21

Slide 21 text

HTTP ETag header (Content-based) Another method is to use the ETag header to maintain a kind of hashcode for the content. Every time the content changes on the server side the value of the ETag does change. sent by origin server or the user agent Sometimes ETag is hard to maintain, especially in a distributed backend environment HTTP/1.1 200 OK ETag: "hgt5398j" GET /customer/1 HTTP/1.1 IF-None-Match: "hgt5398j" HTTP/1.1 304 Not Modified ETag: "hgt5398j"

Slide 22

Slide 22 text

Disable HTTP caching completely Cache-Control: no-cache, no-store, must-revalidate Pragma: no-cache Expires: 0

Slide 23

Slide 23 text

Server side application level caching Server side caching can reduce load on backend systems by caching data in memory Guava cache (which ships with Dropwizard) for costly database queries Simple Maps/Lists Needs enough memory to be available Invalidation is perfectly under control

Slide 24

Slide 24 text

Client side application level caching Client side caching with Independent from the remote server or proxy Storage is Javascript heap memory AngularJS Alternatively angular-cache

Slide 25

Slide 25 text

Combining header versioning and caching If the response depends on an Accept header too then we need to set the HTTP Vary Header (which is broken in IE and Safari) Normally content in the browser cache is matched agains its URI and HTTP Method. With the Vary Header additional constraints, like the Accept or Authorization header, can be included in the cache key. Vary: Accept

Slide 26

Slide 26 text

Pitfalls Browser caches may not work for self-signed SSL certificates If a resource needs authentication this have to be included in the Vary header and Cache-control: private must be set to prevent shared caching of a security token Vary header is broken for some browsers and some types

Slide 27

Slide 27 text

Recommended caching strategy for REST Best is do no caching at all If you must cache because of backend utilization Consider server side application level caching Consider HTTP content based caching with ETag validation Cache-Control: no-cache, max-age=0 for client Cache-Control: public, max-age=0, must-revalidate + ETag for server If you must cache because of network utilization Consider client side application level caching That is because of Browsers and intermediate infrastructure (like proxies are) are subject to change, sometimes buggy and sometimes

Slide 28

Slide 28 text

Further reading https://redbot.org http://maxenglander.com/2013/04/23/basic-restful-api-versioning-in-jersey.html http://barelyenough.org/blog/2008/05/versioning-rest-web-services/ http://barelyenough.org/blog/2012/05/bookmarks-and-uri-based-versioning/ https://jakearchibald.com/2014/browser-cache-vary-broken/ http://www.apiacademy.co/how-to-http-caching-for-restful-hypermedia-apis/ https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1 http://odino.org/rest-better-http-cache/ http://www.tutorialspoint.com/restful/restful_caching.htm http://de.slideshare.net/Sperasoft/rest-services-caching http://de.slideshare.net/lfcipriani/api-caching-why-your-server

Slide 29

Slide 29 text

Thank you! Follow me on Twitter: This work is licensed under a [email protected] @hendrikdev22 Creative Commons Attribution 4.0 International License