Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DDD & REST — Domain-Driven APIs for the web

DDD & REST — Domain-Driven APIs for the web

Slides of the talk I gave at JavaLand 2017.

@springcentral

Oliver Drotbohm

March 28, 2017
Tweet

More Decks by Oliver Drotbohm

Other Decks in Programming

Transcript

  1. 7

  2. Stringly typed code ! 9 class Customer { private Long

    id; private String firstname, lastname, email; … }
  3. Stringly typed code ! 10 class SomeService { void createUser(…,

    String email) { // Valid email address? … } }
  4. 11 class Customer { private Long id; private Firstname firstname;

    private Lastname lastname; private EmailAddress emailAddress; … }
  5. Stringly typed code ! 12 class SomeService { void createUser(…,

    String email) { // Valid email address? } }
  6. Strongly typed code " 13 class SomeService { void createUser(…,

    EmailAddress email) { // Valid email address! } }
  7. 30 void addToOrder(Order order, Product product, Quantity quantity) { order.items.stream()


    .filter(it -> it.product.equals(product) .ifPresentOrElse( it -> it.increase(quantity), order.items.add(new LineItem(product, quantity)) ); }
  8. 30 void addToOrder(Order order, Product product, Quantity quantity) { order.items.stream()


    .filter(it -> it.product.equals(product) .ifPresentOrElse( it -> it.increase(quantity), order.items.add(new LineItem(product, quantity)) ); }
  9. 30 void addToOrder(Order order, Product product, Quantity quantity) { order.items.stream()


    .filter(it -> it.product.equals(product) .ifPresentOrElse( it -> it.increase(quantity), order.items.add(new LineItem(product, quantity)) ); } Aggregate code in clients !
  10. 32 class Order { Order add(Product product, Quantity quantity) {

    this.items.stream()
 .filter(it -> it.product.equals(product) .ifPresentOrElse( it -> it.increase(quantity), order.items.add(new LineItem(product, quantity)) ); } }
  11. 32 class Order { Order add(Product product, Quantity quantity) {

    this.items.stream()
 .filter(it -> it.product.equals(product) .ifPresentOrElse( it -> it.increase(quantity), order.items.add(new LineItem(product, quantity)) ); } } Aggregate code in aggregate "
  12. 34 class OrderManagement { private final OrderRepository orders; private final

    Inventory inventory; @Transactional void completeOrder(Order order) { orders.save(order.complete()); order.doWithLineItems(item -> inventory.reduce(item.product, item.quantity)); } }
  13. 36 class OrderManagement { private final OrderRepository orders; private final

    Inventory inventory; private final LoyaltyProgram loyalty; @Transactional void complete(Order order) { orders.save(order.complete()); order.doWithLineItems(item -> inventory.reduce(item.product, item.quantity)); loyalty.update(order); } }
  14. 38 class OrderManagement { private final OrderRepository orders; private final

    RestOperations operations; @Transactional void completeOrder(Order order) { orders.save(order.complete()); // Update external systems operations.postForEntity(…); operations.postForEntity(…); } }
  15. 42 class OrderManagement { private final OrderRepository orders; private final

    ApplicationEventPublisher publisher; @Transactional void completeOrder(Order order) { OrderCompletedEvent event = order.complete(); orders.save(order); publisher.publish(event); } }
  16. 43 class Inventory { private final InventoryItemRepository items; @EventListener void

    on(OrderCompletedEvent order) { // Update inventory } }
  17. 45 class OrderManagement { private final OrderRepository orders; private final

    ApplicationEventPublisher publisher; @Transactional void completeOrder(Order order) { OrderCompletedEvent event = order.complete(); orders.save(order); publisher.publish(event); } }
  18. 47 // Super class contains methods with // @DomainEvents und

    @AfterDomainEventPublication class Order extends AbstractAggregateRoot { Order complete() { register(new OrderCompletedEvent(this)); return this; } }
  19. 48 class OrderManagement { private final OrderRepository orders; void completeOrder(Order

    order) { repository.save(order.complete()); } } The aggregate is in charge "
  20. 49 Level 0: CRUD Level 1: Explicit operations Level 2:

    Some operations as events Level 3: CQRS / ES
  21. Method URI Action Step POST /orders Create new order 1

    POST/PATCH /orders/{id} Update the order (only if "payment expected") 2 DELETE /orders/{id} Cancel order (only if "payment expected") 3 PUT /orders/{id}/payment Pay order (only if "payment expected") 4 Barista preparing the order GET /orders/{id} Poll order state 5 GET /orders/{id}/receipt Access receipt DELETE /orders/{id}/receipt Conclude the order process 6
  22. Method URI Action Step POST /orders Create new order 1

    POST/PATCH /orders/{id} Update the order (only if "payment expected") 2 DELETE /orders/{id} Cancel order (only if "payment expected") 3 PUT /orders/{id}/payment Pay order (only if "payment expected") 4 Barista preparing the order GET /orders/{id} Poll order state 5 GET /orders/{id}/receipt Access receipt DELETE /orders/{id}/receipt Conclude the order process 6
  23. Method Resource type Action Step POST orders Create new order

    1 POST/PATCH update Update the order 2 DELETE cancel Cancel order 3 PUT payment Pay order 4 Barista preparing the order GET order Poll order state 5 GET receipt Access receipt DELETE receipt Conclude the order process 6
  24. 69 GET /order/42 { „_links“ : { „cancel“ : {

    „href“ : … }, … „createdDate“ : …, „status“ : „Payment expected“ … }
  25. 72 Amount of domain knowledge in the client Amount of

    protocol knowledge in the client Coupling to the server Non-hypermedia
 based systems Hypermedia
 based systems
  26. API evolvability is key
 in a system of systems 73

    See „Evolving Distributed Systems“
  27. Web Service Repository - Orders Spring Data Spring Data
 REST

    Payment Spring Data Manual
 implementation Manual
 implementation