In this appendix, we return to the fictitious case we introduced in Chapter 2, “Lake-side Mutual Case Study.” Many examples from the case are provided in Part 2. Here, we feature selected specification and implementation details.
Many of the patterns from this book were applied in the Lakeside Mutual case. Some examples follow:
The class InsuranceQuoteRequestProcessingResource.java
in the Policy Management microservice is an activity-oriented PROCESSING RESOURCE, which is indicated by its name suffix. The data-oriented CustomerInformationHolder.java
in the Customer Core service is an INFORMATION HOLDER RESOURCE.
The representation element customerProfile
in CustomerDto.java
applies DATA ELEMENT and EMBEDDED ENTITY.
A RATE LIMIT realization can be found in RateLimitInterceptor.java
in the Customer Self-Service microservice.
A more complete overview is available in the GitHub repository of Lakeside Mutual.1 In the following, we provide two different views on the getCustomers
RETRIEVAL OPERATION of the Customer Core INFORMATION HOLDER RESOURCE.
1. https://github.com/Microservice-API-Patterns/LakesideMutual/blob/master/MAP.md.
Figure 2.4 in Chapter 2 shows a domain model of the realized insurance business concepts; the Java Service Layer featured here implements parts of this domain model. Due to space constraints, we show only parts of each artifact here; a more complete implementation can be found in the GitHub repository.
This is the CustomerInformationHolder
class that serves as a Spring @RestController
:
@RestController
@RequestMapping("/customers")
public class CustomerInformationHolder {
/**
* Returns a 'page' of customers.
*
* The query parameters {@code limit} and {@code offset} can be
* used to specify the maximum size of the page and the offset of
* the page's first customer.
*
* The response contains the customers, limit and offset of the
* current page, as well as the total number of customers * (data set size).
* Additionally, it contains HATEOAS-style links that link to the
* endpoint addresses of the current, previous, and next page.
*/
@Operation(summary =
"Get all customers in pages of 10 entries per page.")
@GetMapping // operation responsibility: Retrieval Operation
public ResponseEntity<PaginatedCustomerResponseDto>
getCustomers(
@RequestParam(
value = "filter", required = false, defaultValue = "")
String filter,
@RequestParam(
value = "limit", required = false, defaultValue = "10")
Integer limit,
@RequestParam(
value = "offset", required = false, defaultValue = "0")
Integer offset,
@RequestParam(
value = "fields", required = false, defaultValue = "")
String fields) {
String decodedFilter = UriUtils.decode(filter, "UTF-8");
Page<CustomerAggregateRoot> customerPage = customerService
.getCustomers(decodedFilter, limit, offset);
List<CustomerResponseDto> customerDtos = customerPage
.getElements()
.stream()
.map(c -> createCustomerResponseDto(c, fields))
.collect(Collectors.toList());
PaginatedCustomerResponseDto response =
createPaginatedCustomerResponseDto(
filter,
customerPage.getLimit(),
customerPage.getOffset(),
customerPage.getSize(),
fields,
customerDtos);
return ResponseEntity.ok(response);
}
Stepping back from the implementation details, the following OpenAPI specification (shortened for clarity) of the getCustomers
operation from the Java Service Layer provides another view of the API design:
openapi: 3.0.1
info:
title: Customer Core API
description: This API allows clients to create new customers
and retrieve details about existing customers.
license:
name: Apache 2.0
version: v1.0.0
servers:
- url: http://localhost:8110
description: Generated server url
paths:
/customers:
get:
tags:
- customer-information-holder
summary: Get all customers in pages of 10 entries per page.
operationId: getCustomers
parameters:
- name: filter
in: query
description: search terms to filter the customers by
name
required: false
schema:
type: string
default: ''
- name: limit
in: query
description: the maximum number of customers per page
required: false
schema:
type: integer
format: int32
default: 10
- name: offset
in: query
description: the offset of the page's first customer
required: false
schema:
type: integer
format: int32
default: 0
- name: fields
in: query
description: a comma-separated list of the fields
that should be included in the response
required: false
schema:
type: string
default: ''
responses:
'200':
description: OK
content:
'*/*':
schema:
$ref: "#/components/schemas
/PaginatedCustomerResponseDto"
components:
schemas:
Address:
type: object
properties:
streetAddress:
type: string
postalCode:
type: string
city:
type: string
CustomerResponseDto:
type: object
properties:
customerId:
type: string
firstname:
type: string
lastname:
type: string
birthday:
type: string
format: date-time
streetAddress:
type: string
postalCode:
type: string
city:
type: string
email:
type: string
phoneNumber:
type: string
moveHistory:
type: array
items:
$ref: '#/components/schemas/Address'
links:
type: array
items:
$ref: '#/components/schemas/Link'
Link:
type: object
properties:
rel:
type: string
href:
type: string
AddressDto:
required:
- city
- postalCode
- streetAddress
type: object
properties:
streetAddress:
type: string
postalCode:
type: string
city:
type: string
description: the customer's new address
PaginatedCustomerResponseDto:
type: object
properties:
filter:
type: string
limit:
type: integer
format: int32
offset:
type: integer
format: int32
size:
type: integer
format: int32
customers:
type: array
items:
$ref: '#/components/schemas/CustomerResponseDto'
links:
type: array
items:
$ref: '#/components/schemas/Link'
When querying the endpoint using curl
, the following HTTP response is returned:
curl -X GET --header
'Authorization: Bearer b318ad736c6c844b'
http://localhost:8110/customers?limit=2
{
"limit": 2,
"offset": 0,
"size": 50,
"customers": [ {
"customerId": "bunlo9vk5f",
"firstname": "Ado",
"lastname": "Kinnett",
"birthday": "1975-06-13T23:00:00.000+00:00",
"streetAddress": "2 Autumn Leaf Lane",
"postalCode": "6500",
"city": "Bellinzona",
"email": "[email protected]",
"phoneNumber": "055 222 4111",
"moveHistory": [ ]
}, {
"customerId": "bd91pwfepl",
"firstname": "Bel",
"lastname": "Pifford",
"birthday": "1964-02-01T23:00:00.000+00:00",
"streetAddress": "4 Sherman Parkway",
"postalCode": "1201",
"city": "Genf",
"email": "[email protected]",
"phoneNumber": "055 222 4111",
"moveHistory": [ ]
} ],
"_links": {
"self": {
"href": "/customers?filter=&limit=2&offset=0&fields="
},
"next": {
"href": "/customers?filter=&limit=2&offset=2&fields="
}
}
}
3.148.113.111