JDD2014: REST API versioning practice: from header to model - Łukasz Wierzbicki

Post on 01-Jul-2015

189 views 1 download

description

Why REST API should be backward compatible and why it is hard to achieve. The talk will be about that and other problems we have encountered in Kontakt.io when building platform for worldwide services.

transcript

About me

Łukasz Wierzbicki •  +10 years of

professional experience

•  software engineer, architect, manager

Motivation

•  lots of ideas how to mark versions

•  lots of theory

•  ...little practise

•  any actual solution?

Why do we need versioning?

•  new fields in particular

resource

•  we don't need some

fields any longer

•  we're startup

•  people are already

using our API

Why, why, why?

Assumptions

•  business logic returns model

•  controllers return views

•  object-json/xml/? mapping done

transparently

Possibilities

•  several versions of model,

•  model as a “view”

•  one object mapper

cons: a lot of code, DAOs and services pros: don't see any

no 1

Possibilities, flow

cons: a lot of code, DAOs and services pros: don't see any

no 1

Dao 1

Dao 2

Service 2

Service 1 Backend 1

Backend 2

Model 2

Model 1 Controller 1

Controller 2 Response

Response

Version Router Request

Possibilities •  one model

•  converters

•  several versions of view objects

•  one object mapper

no 2

Possibilities, flow

no 2

cons: still a lot of boilerplate code pros: less code than previously

Dao Service

Backend 1

Backend 2

Converter 1

Converter 2

Response

Response

Version Router Request

Model

View 1

View 2

Controller 1

Controller 2

Model

Possibilities •  one model

•  one view/proxy factory

•  several versions of dynamic proxies

•  one object mapper

no 3

public class Address {

private final String street;

private final String city;

public Address(String street, String city) { super();

this.street = street; this.city = city;

}

public String getStreet() { return street;

}

public String getCity() { return city;

} }

@View public interface AddressV1 {

String getStreet(); @Property("city")

String getTown();

@Provider(Public.class ) Boolean getPublic();

class Public implements Provider<Address> { @Override

public Object get(Address source) { return true;

} }

}

Some code...

Model

Possibilities, flow

no 3

cons: some magic to write/handle pros: even less code to handle

Dao Service

Backend 1

Response

Response

Version Router Request

View 2

Controller 1

Controller 2

Proxy Factory

Backend 2

View.class

View 1

Possibilities

•  one model

•  view factory having list of properties

•  map as a view

•  one object mapper

no 4

Possibilities, flow

no 4

Dao Service

Backend 2

View Factory 1

Response

Response

Version Router Request

Map

Map

Controller 1

Controller 2

cons: some magic to write/handle pros: small amount of code, partial resources

View Factory 2

Backend 1

Possibilities •  lots of combinations

•  i.e. one view, one object mapper public class AddressView {

@Version("1", "2", "3") private String street;

@Version1 @Version3("town") private String city;

}

no ...

Our choice - no 4

•  because it is easy to use

•  because of less boilerplate code,

and we don't have time to make /

maintain it

•  because we wanted to have

“partial resources”

How?

•  converters get properties values and put them to maps

•  include list: “length”, user.role”, “user.id”, “user.name”

•  exclude list - great for small changes

•  “generated fields” - when hotfix needed

•  “mappings” - “name from model” -> “name in json”

Our api… foreword

•  REST but not RESTful/

HATEOAS

•  Just Http GETs and POSTs

•  Verbs in paths, i.e.: create,

update, assign

Thank You!