Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
DLACZEGO 99% FIRM, KTÓRE TWORZĄ
API RESTOWE KŁAMIE?
/Bartek Andrzejczak @baandrzejczak
O MNIE
dev @
twitter
github
blog @
BMS
@baandrzejczak
@bandrzejczak
bandrzejczak.com
AGENDA
Geneza kłamstwa
Co to jest HATEOAS?
Jak ważny jest HATEOAS?
Czy HATEOAS jest mi potrzebny?
HATEOAS od strony serwer...
MOŻE POWTÓRZYMY ANGIELSKI?
GOOGLE
0:01
AMBROSE LITTLE
0:20
CZYM WŁAŚCIWIE JEST REST?
This chapter introduces and elaborates the
Representational State Transfer (REST)
architectural ...
OGRANICZENIA NARZUCANE PRZEZ REST
Podział klient-serwer
Bezstanowość serwera
Cache
Jednolity interfejs
Identyfikacja zasob...
HYPERMEDIA AS THE ENGINE OF
APPLICATION STATE
Role, artefakty, zdarzenia oraz reguły Scruma
są niezmienne i choć możliwe jest
wykorzystanie tylko wybranych jego
element...
JAK WAŻNY JEST HATEOAS?
In order to obtain a uniform interface,
multiple architectural constraints are needed
to guide the...
The name “Representational State Transfer” is intended to
evoke an image of how a well-designed Web application
behaves:
a...
CO DAJE NAM HATEOAS?
KIEDY HATEOAS JEST STRATĄ CZASU?
Brak wyraźnego flow aplikacji
CRUD
Małe API
ZALETY
Sterowanie przepływem danych w aplikacji
Sterowanie dostępnymi podzasobami
Luźniejsze związanie serwera i klienta
D...
WADY
Więcej pracy
Więcej transferu
Brak ekspertów w temacie
Tworzenie API dla nieistniejącego klienta
DLA JAKIEGO KLIENTA NADAJE SIĘ HATEOAS?
FORMAT LINKÓW
HTML
<a href="http://swapi.co/api/films/1/">A New Hope</a>
JSON API
{
    "name": "Luke Skywalker",
    "height": "1.72 m",
    "mass": "77 Kg",
    "hair_color": "Blond",
    "link...
PAYPAL API
{
    "name": "Luke Skywalker",
    "height": "1.72 m",
    "links": [
        {
            "href": "http://sw...
VERTICALRESPONSE API
{
    "name": "Luke Skywalker",
    "height": "1.72 m",
    "mass": "77 Kg",
    "hair_color": "Blond...
HYPERTEXT APPLICATION LANGUAGE (HAL)
{
    "name": "Luke Skywalker",
    "height": "1.72 m",
    "mass": "77 Kg",
    "hai...
HYPERTEXT APPLICATION LANGUAGE (HAL)
{
  "_links": {
    "self": {
      "href": "/"
    },
    "curies": [
      {
      ...
JSON-LD
{
    "name": "Luke Skywalker",
    "height": "1.72 m",
    "mass": "77 Kg",
    "hair_color": "Blond",
    "@self...
NAGŁÓWKI HTTP
Link: <http://swapi.co/api/species/1/>; rel="species"
HATEOAS NA SERWERZE
JERSEY DECLARATIVE LINKING
NAJPROSTSZY PRZYKŁAD
@Path("/people")
public class PeopleResource {
    @GET
    public List<Pe...
PARAMETRY ŚCIEŻEK
@Path("/people/{id}")
public class PersonResource {
    ...
}
public class Person {
    public String na...
STAŁE ŚCIEŻKI
public class Root {
    @InjectLink("/films", rel="films")
    public URI films;
}
{
    "films": "http://sw...
LINKI W NAGŁÓWKACH
@InjectLinks(
    value=@InjectLink("planets/${resource.homeworldId}"),
    rel="homeworld"
)
public cl...
PLUSY
Wybór pomiędzy linkami w nagłówkach i w
reprezentacjach
MINUSY
Brak możliwości przesyłania tylko niektórych
linków
S...
JAX-RS 2.0
Tylko imperatywna konstrukcja linków.
@Path("/people/{id}")
public class PersonResource {
    @GET
    public R...
Ścieżki można pobierać z metod...
@Path("/people/{id}")
public class PersonResource {
    @GET
    public Response get(@Pa...
...lub hardcodować
@GET
public Response get(@PathParam("id") String personId) {
    Person person = new PeopleRepository()...
PLUSY
Brak ingerencji w klasy reprezentacji
Implementacja przez wiele różnych frameworków
MINUSY
Płaska struktura linków
N...
SPRING-HATEOAS
Aby dodawać linki do klasy, musi ona rozszerzać klasę
ResourceSupport - linki staną się częścią reprezentac...
Linki dodajemy bezpośrednio do reprezentacji
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*;
@Contr...
Wynik:
{
    "name": "Luke Skywalker",
    "height": "1.72 m",
    "mass": "77 Kg",
    "hair_color": "Blond",
    "_links...
PLUSY
Minimalna ingerencja w klasy reprezentacji
Możliwość zagnieżdżania linków
Obsługa różnych formatów linków
Wsparcie J...
HATEOAS W KLIENCIE
JAVA (JAX-RS)
Linki w reprezentacjach
{
    "name": "Luke Skywalker",
    "links": {
        "homeworld": {
            "u...
Linki w nagłówkach
HTTP 200 OK
Content­Type: application/json
Link: <http://swapi.co/api/planets/1>; rel="homeworld"
Link:...
JAVASCRIPT (ANGULARJS)
Linki w reprezentacjach
{
    "name": "Luke Skywalker",
    "links": {
        "father": {
        ...
Linki w nagłówkach
HTTP 200 OK
Content­Type: application/json
Link: <http://swapi.co/api/people/2>; rel="father"
{
    "na...
Link: </people>;
    rel="people";
    actions="[
        {'name':'add','method':'POST'},
        {'name':'list','method':...
PODSUMOWANIE
HATEOAS
Maszyna stanów
Rosnące wsparcie bibliotek
SWAPI.CO
PYTANIA?
DZIĘKI!
4Developers 2015: Dlaczego 99% firm, które tworzą API RESTowe kłamie? - Bartek Andrzejczak, Business Management Software
4Developers 2015: Dlaczego 99% firm, które tworzą API RESTowe kłamie? - Bartek Andrzejczak, Business Management Software
4Developers 2015: Dlaczego 99% firm, które tworzą API RESTowe kłamie? - Bartek Andrzejczak, Business Management Software
4Developers 2015: Dlaczego 99% firm, które tworzą API RESTowe kłamie? - Bartek Andrzejczak, Business Management Software
4Developers 2015: Dlaczego 99% firm, które tworzą API RESTowe kłamie? - Bartek Andrzejczak, Business Management Software
4Developers 2015: Dlaczego 99% firm, które tworzą API RESTowe kłamie? - Bartek Andrzejczak, Business Management Software
4Developers 2015: Dlaczego 99% firm, które tworzą API RESTowe kłamie? - Bartek Andrzejczak, Business Management Software
4Developers 2015: Dlaczego 99% firm, które tworzą API RESTowe kłamie? - Bartek Andrzejczak, Business Management Software
4Developers 2015: Dlaczego 99% firm, które tworzą API RESTowe kłamie? - Bartek Andrzejczak, Business Management Software
4Developers 2015: Dlaczego 99% firm, które tworzą API RESTowe kłamie? - Bartek Andrzejczak, Business Management Software
Upcoming SlideShare
Loading in …5
×

4Developers 2015: Dlaczego 99% firm, które tworzą API RESTowe kłamie? - Bartek Andrzejczak, Business Management Software

210 views

Published on

Bartek Andrzejczak - Business Management Software

Language: Polish

Istnieje duże prawdopodobieństwo, że na co dzień piszesz aplikacje z użyciem wzorca REST. Ale czy Twoje aplikacje można określić jako w pełni RESTful? Czy na pewno niczego im nie brakuje?

HATEOAS (Hypermedia as the Engine of Application State) to najrzadziej implementowana część REST-a. Wprowadza ona do modelu linki łączące poszczególne zasoby w ramach API, bez których aplikacja nie może być w pełni RESTful. Jednak czy aplikacje tylko częściowo implementujące wzorzec REST będą gorsze? Oczywiście, że nie, ale nikt nie powiedział, że nie mogą być lepsze!

Podczas prezentacji chciałbym przedstawić tę, moim zdaniem, nieco niedocenianą część REST'a, pokazać czym jest HATEOAS, jak wygląda, gdzie pasuje a gdzie nie oraz jak można go zaimplementować po stronie serwera i klienta.

Published in: Software
  • Be the first to comment

  • Be the first to like this

4Developers 2015: Dlaczego 99% firm, które tworzą API RESTowe kłamie? - Bartek Andrzejczak, Business Management Software

  1. 1. DLACZEGO 99% FIRM, KTÓRE TWORZĄ API RESTOWE KŁAMIE? /Bartek Andrzejczak @baandrzejczak
  2. 2. O MNIE dev @ twitter github blog @ BMS @baandrzejczak @bandrzejczak bandrzejczak.com
  3. 3. AGENDA Geneza kłamstwa Co to jest HATEOAS? Jak ważny jest HATEOAS? Czy HATEOAS jest mi potrzebny? HATEOAS od strony serwera HATEOAS od strony klienta
  4. 4. MOŻE POWTÓRZYMY ANGIELSKI?
  5. 5. GOOGLE 0:01 AMBROSE LITTLE 0:20
  6. 6. CZYM WŁAŚCIWIE JEST REST? This chapter introduces and elaborates the Representational State Transfer (REST) architectural style for distributed hypermedia systems (...) (...) a style is a named set of constraints on architectural elements that induces the set of properties desired of the architecture. "Architectural Styles and the Design of Network-based Software Architectures" Roy T. Fielding
  7. 7. OGRANICZENIA NARZUCANE PRZEZ REST Podział klient-serwer Bezstanowość serwera Cache Jednolity interfejs Identyfikacja zasobów Manipulacja zasobami przez reprezentacje Samoopisujące się wiadomości HATEOAS Podział na warstwy Code-on-demand (Opcjonalne)
  8. 8. HYPERMEDIA AS THE ENGINE OF APPLICATION STATE
  9. 9. Role, artefakty, zdarzenia oraz reguły Scruma są niezmienne i choć możliwe jest wykorzystanie tylko wybranych jego elementów, wynikiem takiego postępowania nie będzie Scrum. Scrum istnieje tylko w swojej pełnej postaci i sprawdza się doskonale w roli ramy dla innych technik, metodyk czy praktyk. Scrum Guide
  10. 10. JAK WAŻNY JEST HATEOAS? In order to obtain a uniform interface, multiple architectural constraints are needed to guide the behavior of components. REST is defined by four interface constraints: identification of resources; manipulation of resources through representations; self- descriptive messages; and, hypermedia as the engine of application state. These constraints will be discussed in Section 5.2. "Architectural Styles and the Design of Network-based Software Architectures" Roy T. Fielding
  11. 11. The name “Representational State Transfer” is intended to evoke an image of how a well-designed Web application behaves: a network of web pages (a virtual state-machine) where the user progresses through the application by selecting links (state transitions) resulting in the next page (representing the next state of the application) being transferred to the user and rendered for their use
  12. 12. CO DAJE NAM HATEOAS?
  13. 13. KIEDY HATEOAS JEST STRATĄ CZASU? Brak wyraźnego flow aplikacji CRUD Małe API
  14. 14. ZALETY Sterowanie przepływem danych w aplikacji Sterowanie dostępnymi podzasobami Luźniejsze związanie serwera i klienta Dodatkowa dokumentacja API (jednak niewystarczająca)
  15. 15. WADY Więcej pracy Więcej transferu Brak ekspertów w temacie Tworzenie API dla nieistniejącego klienta
  16. 16. DLA JAKIEGO KLIENTA NADAJE SIĘ HATEOAS?
  17. 17. FORMAT LINKÓW HTML <a href="http://swapi.co/api/films/1/">A New Hope</a>
  18. 18. JSON API {     "name": "Luke Skywalker",     "height": "1.72 m",     "mass": "77 Kg",     "hair_color": "Blond",     "links": {         "species": {             "self": "http://swapi.co/api/species/1/",             "all": "http://swapi.co/api/species/"         }     } }
  19. 19. PAYPAL API {     "name": "Luke Skywalker",     "height": "1.72 m",     "links": [         {             "href": "http://swapi.co/api/people/1/",             "rel": "self",             "method": "GET"         },         {             "href": "http://swapi.co/api/species/1/",             "rel": "species",             "method": "GET"         }     ] }
  20. 20. VERTICALRESPONSE API {     "name": "Luke Skywalker",     "height": "1.72 m",     "mass": "77 Kg",     "hair_color": "Blond",     "links": {         "self": {             "url": "http://swapi.co/api/people/1/"         },         "homeworld": {             "url": "http://swapi.co/api/planets/1/"         }     } }
  21. 21. HYPERTEXT APPLICATION LANGUAGE (HAL) {     "name": "Luke Skywalker",     "height": "1.72 m",     "mass": "77 Kg",     "hair_color": "Blond",     "_links": {         "self": {             "href": "http://swapi.co/api/people/1/",             "title": "Luke Skywalker"         },         "http://swapi.co/api/rels/species": {             "href": "http://swapi.co/api/species/1/",             "title": "Human"         }     } }
  22. 22. HYPERTEXT APPLICATION LANGUAGE (HAL) {   "_links": {     "self": {       "href": "/"     },     "curies": [       {         "name": "ht",         "href": "http://haltalk.herokuapp.com/rels/{rel}",         "templated": true       }     ],     "ht:users": {       "href": "/users"     }   } }
  23. 23. JSON-LD {     "name": "Luke Skywalker",     "height": "1.72 m",     "mass": "77 Kg",     "hair_color": "Blond",     "@self": "http://swapi.co/api/people/1/",     "@species": "http://swapi.co/api/species/1/", }
  24. 24. NAGŁÓWKI HTTP Link: <http://swapi.co/api/species/1/>; rel="species"
  25. 25. HATEOAS NA SERWERZE
  26. 26. JERSEY DECLARATIVE LINKING NAJPROSTSZY PRZYKŁAD @Path("/people") public class PeopleResource {     @GET     public List<Person> list() { ... }     @GET     @Path("/{id}")     public Person get(@PathParam("id") String personId) {         return new PeopleRepository().find(personId);     } } public class Person {     public String name;     @InjectLink(resource=PeopleResource.class)     public URI self; } {     "name": "Luke Skywalker",     "self": "http://swapi.co/api/people" }
  27. 27. PARAMETRY ŚCIEŻEK @Path("/people/{id}") public class PersonResource {     ... } public class Person {     public String name;     @InjectLink(         resource=PlanetResource.class,         bindings={             @Binding("${resource.homeworldId}")         }     )     public URI homeworld;     @JsonIgnore     public String homeworldId; } {     "name": "Luke Skywalker",     "homeworld": "http://swapi.co/api/planets/1" }
  28. 28. STAŁE ŚCIEŻKI public class Root {     @InjectLink("/films", rel="films")     public URI films; } {     "films": "http://swapi.co/api/films" }
  29. 29. LINKI W NAGŁÓWKACH @InjectLinks(     value=@InjectLink("planets/${resource.homeworldId}"),     rel="homeworld" ) public class Person {     public String name;     @JsonIgnore     public String homeworldId; } HTTP 200 OK Allow: GET, HEAD, OPTIONS Content­Type: application/json Vary: Accept Link: <http://swapi.co/api/planets/1>; rel="homeworld" {     "name": "Luke Skywalker" }
  30. 30. PLUSY Wybór pomiędzy linkami w nagłówkach i w reprezentacjach MINUSY Brak możliwości przesyłania tylko niektórych linków Silne połączenie reprezentacji z zasobami Annotation hell
  31. 31. JAX-RS 2.0 Tylko imperatywna konstrukcja linków. @Path("/people/{id}") public class PersonResource {     @GET     public Response get(@PathParam("id") String personId) {         return Response                 .ok(new PeopleRepository().find(personId))                 .links(Link.fromResource(PersonResource.class)                             .rel("self").build(personId))                 .build();     } } HTTP 200 OK Content­Type: application/json Link: <http://swapi.co/api/people/1>; rel="self"
  32. 32. Ścieżki można pobierać z metod... @Path("/people/{id}") public class PersonResource {     @GET     public Response get(@PathParam("id") String personId) {         return Response                 .ok(new PeopleRepository().find(personId))                 .links(Link                         .fromMethod(PersonResource.class, "films")                         .rel("films").build(personId))                 .build();     }     @GET     @Path("/films")     public Response films(){ ... } } HTTP 200 OK Content­Type: application/json Link: <http://swapi.co/api/people/1/films>; rel="films"
  33. 33. ...lub hardcodować @GET public Response get(@PathParam("id") String personId) {     Person person = new PeopleRepository().find(personId);     String fatherId = person.findFather();     return Response             .ok()             .links(Link                     .fromPath("/people/{id}")                     .rel("father").build(fatherId))             .build(); } HTTP 200 OK Content­Type: application/json Link: <http://swapi.co/api/people/darthVader>; rel="father" {     "name": "Luke Skywalker" }
  34. 34. PLUSY Brak ingerencji w klasy reprezentacji Implementacja przez wiele różnych frameworków MINUSY Płaska struktura linków Nagłówek trudniej jest analizować niż reprezentację
  35. 35. SPRING-HATEOAS Aby dodawać linki do klasy, musi ona rozszerzać klasę ResourceSupport - linki staną się częścią reprezentacji. public class Person extends ResourceSupport {     public String name;     public String height;     public String mass;     public String hair_color; }
  36. 36. Linki dodajemy bezpośrednio do reprezentacji import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*; @Controller public class PersonController{     @RequestMapping("/people/{id}")     @ResponseBody     public HttpEntity<Person> get(@PathVariable("id") String personId) {         Person person = new PeopleRepository().find(personId);         person.add(             linkTo(methodOn(PersonController.class).get(personId))                 .withSelfRel()         );         return new ResponseEntity<Person>(person, HttpStatus.OK);     } }
  37. 37. Wynik: {     "name": "Luke Skywalker",     "height": "1.72 m",     "mass": "77 Kg",     "hair_color": "Blond",     "_links":{         "self":{             "href": "http://swapi.co/api/people/1"         }     } }
  38. 38. PLUSY Minimalna ingerencja w klasy reprezentacji Możliwość zagnieżdżania linków Obsługa różnych formatów linków Wsparcie JAX-RS MINUSY Narastająca logika w kontrolerach, w przypadku linkowania bardziej skomplikowanych struktur (np. kolekcji)
  39. 39. HATEOAS W KLIENCIE
  40. 40. JAVA (JAX-RS) Linki w reprezentacjach {     "name": "Luke Skywalker",     "links": {         "homeworld": {             "uri": "http://swapi.co/api/planets/1"         }     } } final Person table = target.request().get(Person.class); URI homeworldURI = table.getLinks().getHomeworld().getUri(); WebTarget homeworldTarget = client.target(homeworldURI);
  41. 41. Linki w nagłówkach HTTP 200 OK Content­Type: application/json Link: <http://swapi.co/api/planets/1>; rel="homeworld" Link: <http://swapi.co/api/species/1>; rel="species" {     "name": "Luke Skywalker" } final Response response = target.request().get(); URI homeworldURI = response.getLink("homeworld").getUri(); URI speciesURI = response.getLink("species").getUri();
  42. 42. JAVASCRIPT (ANGULARJS) Linki w reprezentacjach {     "name": "Luke Skywalker",     "links": {         "father": {             "uri": "http://swapi.co/api/people/2"         }     } } var personResource = $resource("/api/people/:personId"); var luke = personResource.query({personId: 1}, function () {     var lukesFather = $resource(luke.links.father)                                 .query(null, function () {         console.log(lukesFather);     }); });
  43. 43. Linki w nagłówkach HTTP 200 OK Content­Type: application/json Link: <http://swapi.co/api/people/2>; rel="father" {     "name": "Luke Skywalker" } var personResource = $resource("/api/people/:personId"); var luke = personResource.query({personId: 1}, function () {     var lukesFather = firstPerson.resource("father")                                 .query(null, function () {         console.log(lukesFather);     }); });
  44. 44. Link: </people>;     rel="people";     actions="[         {'name':'add','method':'POST'},         {'name':'list','method':'GET'}     ]" $http.get("/").success(     function (root) {         var peopleList = root.links.people.list();         root.links.people.add(             {                 "name": "Darth Vader",                 "height": "1.8"             }         );     } ); https://github.com/bandrzejczak/bpm-console-gui https://github.com/bandrzejczak/bpm-console-rest
  45. 45. PODSUMOWANIE HATEOAS Maszyna stanów Rosnące wsparcie bibliotek
  46. 46. SWAPI.CO
  47. 47. PYTANIA?
  48. 48. DZIĘKI!

×