Reactive e-commerce API design

by Oleg Ilyenko / @easyangel

About me

  • 8 years of software development
    • 5 years working on e-commerce products
  • Creator of Scaldi - Scala DI library
  • Author of Hacking Scala blog
  • Scala Backend Engineer at commercetools GmbH

RESTful API design

  • Resources
    • Where to put the boundary?
  • HTTP verbs
    • Semantics of POST?
  • Transactions
    • Scalability

Separating the Model

Single Model

Separate Read/Write Model


Command Query Responsibility Segregation

  • Multiple read models
  • Precise and flexible write model

POST /my-shop/orders

  "customerId": "456",
  "lineItems": [
    {"productId": "PRODUCT-1",  "quantity": 3},
    {"productId": "PRODUCT-25", "quantity": 2}

POST /my-shop/carts/CART-123

  "actions": [
    {"action": "addLineItem",    "productId": "PRODUCT-1",  "quantity": 5},
    {"action": "removeLineItem", "productId": "PRODUCT-1",  "quantity": 2},
    {"action": "addLineItem",    "productId": "PRODUCT-25", "quantity": 2}

POST /my-shop/orders

  "cartId": "CART-123"


  • Change history
  • Much less data to transfer
    • Good for mobile clients
  • More control over the changes
  • Not very suitable for data synchronization

Event Sourcing

Event Sourcing

  • Events represent facts from the past
    • OrderCreated
    • ProductNameChanged
  • After event is saved, all business logic is already performed
  • Most normalized form of the data
  • Point-in-time restore/view
  • Scale reads and writes separately

Multiple Read Models

Disadvantages of Event Sourcing

  • Bigger database
  • Events need to be backwards compatible
  • Eventual consistency

Resource Boundaries

  • Where to put the boundary?
  • Should line item be part of order resource?
  • Or maybe it should be a separate resource?

Transactional Boundary

“We will argue below why we conclude that atomic transactions cannot span entities. The programmer must always stick to the data contained inside a single entity for each transaction. This restriction is true for entities within the same application and for entities within different applications.”
Life beyond Distributed Transactions
by Pat Helland

Optimistic Concurrency Control

Bigger workflows

The Reactive Manifesto

Event API

GET /my-shop/events

HTTP/1.1 200 OK
Content-Type: text/event-stream

id: EVENT-123
data: {
        "entity": "product",
        "entityId": "PROD-56",
        "type": "nameChanged",
        "sequenceNumber": 10,
        "payload": {...}


  • SSE (Server-sent events)
    • Last-Event-ID header
  • WebSockets
  • Long-polling

Important properties

  • Event ID
    • Can be: entityId + entityVersion
  • Type of entity
  • ID of entity
  • Sequence number within this entity

Thank you!