How the Services Communicate

The third decision is how the services communicate: who calls whom, and in what style.

Who calls whom

The storefronts send every request to one address, as before. Shopend’s gateway works like the registrar’s: it sends each request to a service by its path. Requests for the catalog, carts, and orders go to the commerce service. Requests to sign up and sign in go to the account service.

The other services are called only by Shopend’s own services. The commerce service calls the payment service to take a payment or make a refund, the shipping service to ship an order or stop a shipment, and the notification service to send an email.

graph TB
    S[Storefronts] --> GW[Gateway]
    GW -->|catalog, carts, orders| C[Commerce service]
    GW -->|sign up, sign in| A[Account service]
    C --> P[Payment service]
    C --> SH[Shipping service]
    C --> N[Notification service]

The diagram leaves out the database, which all five services share.

Cancelling an order

A shopper cancels an order before it ships. The storefront sends the request to the commerce service. The commerce service marks the order as cancelled and puts the stock back. Then it calls the payment service to refund the payment, the shipping service to stop the shipment, and the notification service to send the email. The notification service reads the shopper’s email address from the database.

sequenceDiagram
    participant S as Storefront
    participant C as Commerce service
    participant P as Payment service
    participant SH as Shipping service
    participant N as Notification service
    S->>C: Cancel the order
    C->>C: Mark the order cancelled, put the stock back
    C->>P: Refund the payment
    C->>SH: Stop the shipment
    C->>N: Send the cancellation email
    C-->>S: Order cancelled

Each of these calls goes over the network, and any of them can fail. A call from CodeDrill’s application to the runner can fail in the same way. Deciding what to do when one fails is not part of this chapter.

REST, GraphQL, or RPC

REST fits an API that offers resources. It also fits a public API, because most developers already know what GET and 404 mean. GraphQL fits clients that need to choose which fields of related data they read. RPC fits calls between services where we write both sides and each call is an action with arguments and a result.

The merchants’ developers write the storefronts. Requests for the catalog, carts, and orders stay in GraphQL. We chose it for the shop API because a storefront’s website and phone app need different fields. Signing up and signing in are different. Each request sends the same few fields, and each response has the same shape, so choosing fields does not help. They are part of Shopend’s public API, so I use REST for them.

The calls between Shopend’s services fit RPC. We write both sides, and each call is an action: refund this payment, stop this shipment, send this email. CodeDrill’s application uses RPC for the runner in the same way.

Contracts

Recall that we called the shop API’s schema a contract between the API and its clients. Each service has a contract too: the operations it offers, the arguments each one takes, what each one returns, and the errors it can report. Each service is deployed on its own, so a new release of a service must keep its contract working for the services that call it. That is why we can change the notification service’s emails without releasing the commerce service.