Summaries of artifacts, templates, practices, and techniques for agile architecting (DPR-mm) and service design (SDPR-nn).
Note to reviewers: This tutorial is not complete yet, but hopefully it is helpful already (or can at least give an idea of what is coming). Bear with us if you spot inconsistencies or information is still missing.
We continue the story from Quick Start Tutorial 0 and assume you have been assigned the role of API product owner for a fictitious online shop and its APIs. You decided to use elements from DPR to support your architecture design work.
Let’s now walk through the main API design activity in DPR, Stepwise Service Design. Please open the activity page and keep it open while going through the seven steps in this online shop example.
Two obvious use cases in our sample scenario are specified in a brief format that unveils the required data and their relations just a bit:
UseCase UC1_Register {
actor = "Online Shopper"
interactions = create a "CustomerAccount"
benefit "shop online and do not have to leave home"
}
UseCase UC2_BrowseAndBuy {
actor = "Online Shopper"
interactions =
read a "Product" in a "ProductCatalog",
create an "Order" with its "OrderNumber",
create an "OrderItem" in an "Order"
benefit "get best price"
}
A specific and measurable Non-Functional Requirement (NFR) is:
Scoping decisions might include (we could capture them as Y-Statements; see Step 6 for an example of such statement):
Note that these assumptions and decisions merely scope the tutorial; you’ll be able to learn about the DPR way of API and architecture design without being knowledgeable in any of the technologies and concepts mentioned.
When analyzing the two use cases from Step 1, the following tactic DDD pattern instances may capture the analysis results (note that several entity attributes have been added; the Step 1 stories did not mention them explicitly, but justify their introduction implicitly):
The above diagram qualifies as the visual part of the domain model; on a real project, all figure/diagram elements would be explained (here or in a separate glossary).
Let us assume that the following architectural decisions have been made already (if not, we should make them now):
JavaScript Web frontend
A very basic Context Map for this scenario (resulting from Strategic DDD) is:
Follow the instructions and hints in the activity and artifact pages to produce a Candidate Endpoint List.
Such list can be derived from the Step 2 domain model and Step 3 architecture design and may look like this:
Endpoint | Operation | Responsibility/Exposed Data |
---|---|---|
Customer | create | Create an account |
Product | read | Provide information about product category, price, etc.; possibly also suppliers, shipment time, taxes |
Order | create | Model purchase items the order consists of; point to customer; calculate tax and discounts |
Order Item | add to order | Specify amount bought, reference product |
These candidate endpoints outline a Service Layer of the backend under construction. The table does not say much about Remote Facades and Data Transfer Objects (DTOs) yet; this is something to be improved in the next step.
The API that is required to satisfy the requirements can be summarized as:
API name: Online Shop API
Identified in: Steps 1 to 3 from above; Step 4 CEL
Direction: Frontend Integration
Visibility: Solution-Internal API
Endpoints in this API (and their architectural role):
1. Endpoint 1: Customer, responsible for account management (use case UC1_Register)
2. Endpoint 2: Product, responsible for master data management (use case UC2_BrowseAndBuy)
3. Endpoint 3: Order, implements "checkout" activity in shopping process (supports use case UC2_BrowseAndBuy)
The endpoint-level Refined Endpoint List that refactors and refines the output from the previous Step 4 may then contain the following entries:
Endpoint | Operation | Responsibility Pattern (MAP) | Published Language (Request and Response Message Payload) | Media Type/Profile |
---|---|---|---|---|
Customer | Master Data Holder | |||
create (POST) | State Creation Operation | in: account name, out: returns account name (and/or details) | Custom JSON | |
Product Catalog | Master Data Holder | |||
search (GET) | Retrieval Operation | in: search parameters, out: returns set of product descriptions, possibly paginated | Custom JSON | |
Order | Operational Data Holder | |||
create (POST) | State Creation Operation | in: products to be bought, out: returns order confirmation and/or DTO (containing items) | Custom JSON | |
add (PUT) | State Transition Operation | in: items to be added, out: returns order item id as confirmation | Custom JSON |
We have decided for endpoint and operation responsibilities on a conceptual level now; see the following Step 6 for an example of an ADR that continues the design decision making (on a technology level).
One of the architectural decisions might be (formatted as a Y-Statement):
In the context of the OnlineShopBackend subsystem,
facing the need to serve a number of technically diverse clients,
we decided for RESTful HTTP on maturity level 2
and neglected other protocols such as gRPC or SOAP/HTTP
to achieve interoperability, evolvability and auditability
accepting that static contracts and workflows do not comply with the REST level 3 vision of HATEOAS
because the implementation effort on client and server side required for hypermedia-driven state transitions
is not justified in this scenario (not requiring dynamic workflows)
and there is good contract language and tool support (OpenAPI, Swagger tools).
The API description that refines the output from Step 5 may look like this (notation: Microservice Domain-Specific Language (MDSL)):
API description OnlineShopBackend
data type CustomerAccount { "name":D<string>, "address":D<string>, "customeraccountId":CustomerAccountId }
data type CustomerAccountId { "customeraccountId":D<long> }
data type Order { "orderNumber":D<string>, "orderId":OrderId, "orderitemList":OrderItem* }
data type OrderId { "orderId":D<long> }
data type OrderItem { "productName":D<string>, "price":D<string>, "orderitemId":OrderItemId }
data type OrderItemId { "orderitemId":D<long> }
data type Product { "productName":D<string>, "image":D<string>, "productCategory":D<string>, "productId":ProductId }
data type ProductId { "productId":D<long> }
endpoint type Customer
exposes
operation createAccount
expecting
payload CustomerAccount
delivering
payload CustomerAccountId
endpoint type ProductCatalog
exposes
operation readProductInformation
expecting
payload ProductId*
delivering
payload Product*
endpoint type OrderBasket
exposes
operation createOrder with responsibility "POST"
expecting
payload Order
delivering
payload OrderId
operation addOrderItem with responsibility "PUT"
expecting
payload OrderItem
delivering
payload OrderItemId
API provider OnlineShopFeaturesBackendProvider
offers BusinessToConsumerAggregateBackend
at endpoint location "http://..."
via protocol HTTP
The MDSL command line tools can transform this technology-independent service contract into OpenAPI, gRPC Protocol Buffers, and Jolie.
We also do not show how to implement the contract yet, for instance in Spring Boot and Java. Have a look at Step 7 of this demo for tool-supported API design and service identification for such information.
In this phase, we may want to optimize message sizes and exchange frequency (updating API description and architectural decision log accordingly):
Keep on deciding and addressing design issues as they emerge:
See Microservice API Patterns (MAP) Tutorial 1 and Tutorial 2 for more examples of API design work related to quality and evolution concerns.
title: "Design Practice Repository (DPR): Tutorial 1 (Online Shop API Design)"
author: Olaf Zimmermann (ZIO)
date: "12, 04, 2020 (Source: Project DD-DSE)"
copyright: Olaf Zimmermann, 2020 (unless noted otherwise). All rights reserved.
license: Creative Commons Attribution 4.0 International License