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 OpenAPI is used as a standard. For asynchronous scenarios we want to use AsyncAPI to achieve the same level of transparency and discoverability.
We as platform team offer the Azure Service Bus with self-service capabilities. Our customers are able to manage their own topics and subscriptions by maintaining a custom
configuration model in a GitOps fashion.
We want to establish AsyncAPI as documentation standard in HDI's organization. Information about the available message formats and topics is already available in distributed
sources (e.g. repositories) and needs to be aggregated.
To achieve discoverability the creation of a comprehensive catalog of existing topics is necessary, allowing potential subscribers access to information about
messages from the available topics, so they can choose which ones to subscribe to.
Solution
The solution is to create AsyncAPI documents where each topic owned by the customer is represented as a channel. As we are using the GitOps setup it is straightforward to run pipeline whenever there is a change (commit) 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. As the documentation wiki is public the information is accessible to every developer, allowing easy access to messages from any topics of their choice. This approach makes our asynchronous communication 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.
- (Outlook) The AsyncAPI document will be used to generate Java DTOs, ensuring type safety and clear data structure understanding.
- (Outlook) Having the AsyncAPI documents at hand we are currently planning to use them to configure an internal developer portal (IDP) that will aggregate async and sync APIs among other things.
- (Outlook) Evaluate if replacing the custom configuration model and use AsyncAPI documents in the center to configure asynchronous communication instead.
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 before 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}