On this page
HDI Global SE
The HDI brand operates in Germany and internationally, offering life and property/casualty insurance services. They cater to both private individuals and corporate clients, and have been providing industrial insurance since 2016.
tl;dr just go and have a look atfull production-used AsyncAPI document
Challenges
The HDI has various platform teams, among them the Integration Platform Team, which offers three products: Azure API Management, Azure Event Hub, and the Azure Service Bus.
For synchronous communication, we already use OpenAPI, as such we want to ensure the same level of transparency and discoverability for asynchronous scenarios as well.
Our central platform team offers the Azure Service Bus with self-service capabilities.
Customers are able to manage their own topics and subscriptions by simply modifying the according values in their repositories.
This means that most of the data required to document asynchronous communication is already available, although distributed between different repositories.
This necessitated the creation of a comprehensive catalog of existing topics, allowing potential subscribers easy access to messages from any topics of their choosing.
Solution
The solution was to create an an AsyncAPI document where each topic owned by the customer is represented as a channel. This document is automatically generated by a pipeline whenever there's a change in the topic configuration. The necessary information is read from the customer repositories and then passed to a bash script as input. After successful creation, this file, along with a generated markdown for it, is saved within a documentation repository. This documentation repository serves as the basis for our Azure DevOps wiki, ensuring that all project documentation is centralized and easily accessible. This ensures that the information is readily accessible to every developer, allowing easy access to messages from any topics of their choosing. This approach makes our asynchronous communication is as transparent and discoverable as our synchronous communication.
Use Case
- The AsyncAPI documents are used for documentation purposes by the platform team. It provides a comprehensive overview of the asynchronous communication in our system, including the available topics and the structure of the messages.
- (Future Plans) The AsyncAPI document will be used to generate Java DTOs using the AsyncAPI Java generator, ensuring type safety and clear data structure understanding.
More Details
Testing strategy
n/a
Approach to code generation
Our team currently does not use or ofer a code generation tool. However, our customers are free to use any tool they prefer to generate DTOs from the AsyncAPI document.
Architecture
The following enterprise integration patterns are applied :
- Message Channel
Each channel in the AsyncAPI document corresponds to an existing Service Bus topic that can be subscribed to.
1channels: 2 claimStatus-emea: 3 servers: 4 - $ref: '#/servers/box-emea' 5 address: https://namespace.servicebus.windows.net/topic/example/claimStatus
- Message
The 'messages' section under each channel in the AsyncAPI document adheres to this pattern.
Each message is identified by a name and contains a payload, which represents the data transferred between applications.
1 messages: 2 claimStatus: 3 name: claimStatus-Message 4 contentType: application/json
- Document Message
The 'payload' under each message in the AsyncAPI document adheres to this pattern.
The payload is a self-contained document that describes the message and is comprehensible to the message receiver.
In our repository structure, the message-schema file is stored separately and just referenced in the Topic configs. To make sure that all information is accessible in one place, the schema is directly copied to the AsyncAPI document.
1payload: 2 $ref: '#/components/schemas/claimStatus-example.json'
1components: 2 schemas: 3 claimStatus-example.json: { 4 "$schema": "http://json-schema.org/draft-06/schema#", 5 "type": "object", 6 "properties": { 7 "message": { 8 "type": "object", 9 "properties": { 10 "version": { 11 "type": "string" 12 }, 13 "header": { 14 "type": "object", 15 "properties": { 16 "messageId": { 17 "type": "string" 18 }, 19 "entityType": { 20 "type": "string" 21 }, 22 "eventType": { 23 "type": "object", 24 "enum": [ 25 "create", 26 "update" 27 ] 28 } 29 }, 30 "required": [ 31 "messageId", 32 "entityType", 33 "eventType" 34 ] 35 }, 36 "data": { 37 "type": "object", 38 "properties": { 39 "par": { 40 "type": "object", 41 "properties": { 42 "tenantNumber": { 43 "type": "string" 44 }, 45 "policyNumber": { 46 "type": "number" 47 }, 48 "contractNumber": { 49 "type": "number" 50 }, 51 "sourceSystem": { 52 "type": "string" 53 }, 54 "claimStatus": { 55 "type": "string" 56 }, 57 "currencyCode": { 58 "type": "string" 59 }, 60 "registrYear": { 61 "type": "number" 62 }, 63 "broker": { 64 "type": "string" 65 }, 66 "insured": { 67 "type": "string" 68 }, 69 "lineOfBusiness": { 70 "type": "number" 71 }, 72 "claimCountry": { 73 "type": "string" 74 }, 75 "isNewClaim": { 76 "type": "boolean" 77 }, 78 "dateOfLoss": { 79 "type": "string", 80 "format": "date" 81 }, 82 "creationDate": { 83 "type": "string", 84 "format": "date" 85 }, 86 "notificationDate": { 87 "type": "string", 88 "format": "date" 89 }, 90 "businessDate": { 91 "type": "string", 92 "format": "date" 93 } 94 }, 95 "required": [ 96 "tenantNumber" 97 ] 98 } 99 }, 100 "required": [ 101 "par" 102 ] 103 } 104 }, 105 "required": [ 106 "version", 107 "header", 108 "data" 109 ] 110 } 111 }, 112 "required": [ 113 "message" 114 ] 115 } 116
More Details about AsyncAPI
How AsyncAPI documents are stored
A seperate Git repository functions as a "customer Wiki", serving as a central location for all relevant documents about the existing infrastructure. This includes the AsyncAPI document, which provides a comprehensive overview of the asynchronous communication in our system.
Where maintainers edit AsyncAPI documents
If changes for any topic are applied by a customer, the documentation pipeline is triggered. This pipeline uses a bash script to read the updated configuration from the customer's repository. It then generates a new AsyncAPI document reflecting these changes.
The AsyncAPI document is validated using the AsyncAPI CLI to confirm that the document is correctly formatted and adheres to the AsyncAPI specification right after creation and befor being commited to the documentation repository.
What extensions are used
none
How documentation is generated
Documentation is generated via AsyncAPI CLI and published to the Azure DevOps wiki right after the AsyncAPI file is generated.
What bindings are used
none
What tools are used
Schemas
Storage strategy
A Git repository functions as a self-service portal where customers can manage their own configurations for the Azure Service Bus. This includes defining their own message schemas for any topics they own.
Schema Registry
none
Versioning of schemas
The customer has the freedom to choose the versioning for their own message-schema files.
Validation of message schemas
Validation using Ajv is used solely for the purpose of ensuring that the JSON data adheres to the expected schema. This validation is performed for each customer by the Pull Request pipeline we provide. It does not perform any other form of validation or processing on the data.
Additional Resources
Production-use AsyncAPI document
1asyncapi: 3.0.0
2info:
3 title: customer-example
4 version: 1.0.0
5 description: |
6 This is an AsyncAPI document for customer-example.
7 It contains every Topic owned by the customer in form of channel.
8 Dowload the coresponding schema files from the following link:
9servers:
10 box-apac:
11 host: namespace.servicebus.windows.net
12 protocol: amqp
13 description: Azure Service Bus namespace endpoint for box.
14 box-emea:
15 host: namespace.servicebus.windows.net
16 protocol: amqp
17 description: Azure Service Bus namespace endpoint for box.
18channels:
19 claimStatus-emea:
20 servers:
21 - $ref: '#/servers/box-emea'
22 address: https://namespace.servicebus.windows.net/topic/example/claimStatus
23 messages:
24 claimStatus:
25 name: claimStatus-Message
26 contentType: application/json
27 payload:
28 $ref: '#/components/schemas/claimStatus-example.json'
29 claimDetails-emea:
30 servers:
31 - $ref: '#/servers/box-emea'
32 address: https://namespace.servicebus.windows.net/topic/example/claimDetails
33 messages:
34 claimDetails:
35 name: claimDetails-Message
36 contentType: application/json
37 payload:
38 $ref: '#/components/schemas/claimDetails-example.json'
39operations:
40 claimStatus-emea:
41 action: send
42 channel:
43 $ref: '#/channels/claimStatus-emea'
44 messages:
45 - $ref: '#/channels/claimStatus-emea/messages/claimStatus'
46 claimDetails-emea:
47 action: send
48 channel:
49 $ref: '#/channels/claimDetails-emea'
50 messages:
51 - $ref: '#/channels/claimDetails-emea/messages/claimDetails'
52components:
53 schemas:
54 claimDetails-example.json: {
55 "$schema": "http://json-schema.org/draft-06/schema#",
56 "type": "object",
57 "properties": {
58 "policyNumber": {
59 "type": "string"
60 },
61 "claimNumber": {
62 "type": "string"
63 },
64 "notificationDate": {
65 "type": "string"
66 },
67 "occurrenceDate": {
68 "type": "string"
69 },
70 "claimAmount": {
71 "type": "integer"
72 },
73 "description": {
74 "type": "string"
75 },
76 "editor": {
77 "type": "string"
78 },
79 "location": {
80 "type": "string"
81 },
82 "country": {
83 "type": "string"
84 },
85 "currency": {
86 "type": "string"
87 },
88 "movements": {
89 "type": "array",
90 "items": [
91 {
92 "type": "object",
93 "properties": {
94 "amount": {
95 "type": "integer"
96 },
97 "movementType": {
98 "type": "string"
99 },
100 "benefitType": {
101 "type": "string"
102 }
103 },
104 "required": [
105 "amount",
106 "movementType",
107 "benefitType"
108 ]
109 },
110 {
111 "type": "object",
112 "properties": {
113 "amount": {
114 "type": "integer"
115 },
116 "movementType": {
117 "type": "string"
118 },
119 "benefitType": {
120 "type": "string"
121 }
122 },
123 "required": [
124 "amount",
125 "movementType",
126 "benefitType"
127 ]
128 },
129 {
130 "type": "object",
131 "properties": {
132 "amount": {
133 "type": "integer"
134 },
135 "movementType": {
136 "type": "string"
137 },
138 "benefitType": {
139 "type": "string"
140 }
141 },
142 "required": [
143 "amount",
144 "movementType",
145 "benefitType"
146 ]
147 }
148 ]
149 }
150 },
151 "required": [
152 "policyNumber",
153 "claimNumber"
154 ]
155}
156 claimStatus-example.json: {
157 "$schema": "http://json-schema.org/draft-06/schema#",
158 "type": "object",
159 "properties": {
160 "message": {
161 "type": "object",
162 "properties": {
163 "version": {
164 "type": "string"
165 },
166 "header": {
167 "type": "object",
168 "properties": {
169 "messageId": {
170 "type": "string"
171 },
172 "entityType": {
173 "type": "string"
174 },
175 "eventType": {
176 "type": "object",
177 "enum": [
178 "create",
179 "update"
180 ]
181 }
182 },
183 "required": [
184 "messageId",
185 "entityType",
186 "eventType"
187 ]
188 },
189 "data": {
190 "type": "object",
191 "properties": {
192 "par": {
193 "type": "object",
194 "properties": {
195 "tenantNumber": {
196 "type": "string"
197 },
198 "policyNumber": {
199 "type": "number"
200 },
201 "contractNumber": {
202 "type": "number"
203 },
204 "sourceSystem": {
205 "type": "string"
206 },
207 "claimStatus": {
208 "type": "string"
209 },
210 "currencyCode": {
211 "type": "string"
212 },
213 "registrYear": {
214 "type": "number"
215 },
216 "broker": {
217 "type": "string"
218 },
219 "insured": {
220 "type": "string"
221 },
222 "lineOfBusiness": {
223 "type": "number"
224 },
225 "claimCountry": {
226 "type": "string"
227 },
228 "isNewClaim": {
229 "type": "boolean"
230 },
231 "dateOfLoss": {
232 "type": "string",
233 "format": "date"
234 },
235 "creationDate": {
236 "type": "string",
237 "format": "date"
238 },
239 "notificationDate": {
240 "type": "string",
241 "format": "date"
242 },
243 "businessDate": {
244 "type": "string",
245 "format": "date"
246 }
247 },
248 "required": [
249 "tenantNumber"
250 ]
251 }
252 },
253 "required": [
254 "par"
255 ]
256 }
257 },
258 "required": [
259 "version",
260 "header",
261 "data"
262 ]
263 }
264 },
265 "required": [
266 "message"
267 ]
268}