@sfdxy/mule-lint 1.7.1 → 1.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -7
- package/dist/bin/mule-lint-mcp.d.ts +3 -0
- package/dist/bin/mule-lint-mcp.d.ts.map +1 -0
- package/dist/bin/mule-lint-mcp.js +13 -0
- package/dist/bin/mule-lint-mcp.js.map +1 -0
- package/dist/package.json +6 -3
- package/dist/src/core/ComplexityCalculator.d.ts.map +1 -1
- package/dist/src/core/ComplexityCalculator.js +8 -8
- package/dist/src/core/ComplexityCalculator.js.map +1 -1
- package/dist/src/core/FileScanner.d.ts.map +1 -1
- package/dist/src/core/FileScanner.js +11 -12
- package/dist/src/core/FileScanner.js.map +1 -1
- package/dist/src/core/XPathHelper.d.ts.map +1 -1
- package/dist/src/core/XPathHelper.js +23 -23
- package/dist/src/core/XPathHelper.js.map +1 -1
- package/dist/src/core/XmlParser.js +1 -1
- package/dist/src/core/XmlParser.js.map +1 -1
- package/dist/src/core/YamlParser.d.ts.map +1 -1
- package/dist/src/core/YamlParser.js +1 -1
- package/dist/src/core/YamlParser.js.map +1 -1
- package/dist/src/engine/LintEngine.d.ts.map +1 -1
- package/dist/src/engine/LintEngine.js +6 -4
- package/dist/src/engine/LintEngine.js.map +1 -1
- package/dist/src/formatters/CsvFormatter.d.ts.map +1 -1
- package/dist/src/formatters/CsvFormatter.js +6 -4
- package/dist/src/formatters/CsvFormatter.js.map +1 -1
- package/dist/src/formatters/HtmlFormatter.d.ts.map +1 -1
- package/dist/src/formatters/HtmlFormatter.js +12 -7
- package/dist/src/formatters/HtmlFormatter.js.map +1 -1
- package/dist/src/formatters/SarifFormatter.d.ts.map +1 -1
- package/dist/src/formatters/SarifFormatter.js +20 -10
- package/dist/src/formatters/SarifFormatter.js.map +1 -1
- package/dist/src/formatters/TableFormatter.d.ts.map +1 -1
- package/dist/src/formatters/TableFormatter.js +1 -1
- package/dist/src/formatters/TableFormatter.js.map +1 -1
- package/dist/src/mcp/index.d.ts +13 -0
- package/dist/src/mcp/index.d.ts.map +1 -0
- package/dist/src/mcp/index.js +375 -0
- package/dist/src/mcp/index.js.map +1 -0
- package/dist/src/rules/api-led/ApiLedRules.d.ts.map +1 -1
- package/dist/src/rules/api-led/ApiLedRules.js +3 -1
- package/dist/src/rules/api-led/ApiLedRules.js.map +1 -1
- package/dist/src/rules/base/BaseRule.d.ts.map +1 -1
- package/dist/src/rules/base/BaseRule.js +1 -1
- package/dist/src/rules/base/BaseRule.js.map +1 -1
- package/dist/src/rules/complexity/FlowComplexityRule.d.ts.map +1 -1
- package/dist/src/rules/complexity/FlowComplexityRule.js +3 -5
- package/dist/src/rules/complexity/FlowComplexityRule.js.map +1 -1
- package/dist/src/rules/dataweave/DataWeaveRules.d.ts.map +1 -1
- package/dist/src/rules/dataweave/DataWeaveRules.js +5 -5
- package/dist/src/rules/dataweave/DataWeaveRules.js.map +1 -1
- package/dist/src/rules/dataweave/Java17DWErrorHandlingRule.d.ts +21 -0
- package/dist/src/rules/dataweave/Java17DWErrorHandlingRule.d.ts.map +1 -0
- package/dist/src/rules/dataweave/Java17DWErrorHandlingRule.js +162 -0
- package/dist/src/rules/dataweave/Java17DWErrorHandlingRule.js.map +1 -0
- package/dist/src/rules/documentation/FlowDescriptionRule.d.ts.map +1 -1
- package/dist/src/rules/documentation/FlowDescriptionRule.js +1 -1
- package/dist/src/rules/documentation/FlowDescriptionRule.js.map +1 -1
- package/dist/src/rules/documentation/MissingDocNameRule.d.ts.map +1 -1
- package/dist/src/rules/documentation/MissingDocNameRule.js +1 -1
- package/dist/src/rules/documentation/MissingDocNameRule.js.map +1 -1
- package/dist/src/rules/error-handling/CorrelationIdRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/CorrelationIdRule.js +1 -1
- package/dist/src/rules/error-handling/CorrelationIdRule.js.map +1 -1
- package/dist/src/rules/error-handling/GenericErrorRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/GenericErrorRule.js +2 -5
- package/dist/src/rules/error-handling/GenericErrorRule.js.map +1 -1
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts +1 -1
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js +2 -2
- package/dist/src/rules/error-handling/GlobalErrorHandlerRule.js.map +1 -1
- package/dist/src/rules/error-handling/HttpStatusRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/HttpStatusRule.js +1 -1
- package/dist/src/rules/error-handling/HttpStatusRule.js.map +1 -1
- package/dist/src/rules/error-handling/MissingErrorHandlerRule.d.ts.map +1 -1
- package/dist/src/rules/error-handling/MissingErrorHandlerRule.js +9 -1
- package/dist/src/rules/error-handling/MissingErrorHandlerRule.js.map +1 -1
- package/dist/src/rules/experimental/ExperimentalRules.d.ts.map +1 -1
- package/dist/src/rules/experimental/ExperimentalRules.js +1 -1
- package/dist/src/rules/experimental/ExperimentalRules.js.map +1 -1
- package/dist/src/rules/http/HttpContentTypeRule.d.ts.map +1 -1
- package/dist/src/rules/http/HttpContentTypeRule.js +1 -1
- package/dist/src/rules/http/HttpContentTypeRule.js.map +1 -1
- package/dist/src/rules/http/HttpTimeoutRule.d.ts.map +1 -1
- package/dist/src/rules/http/HttpTimeoutRule.js +1 -1
- package/dist/src/rules/http/HttpTimeoutRule.js.map +1 -1
- package/dist/src/rules/http/HttpUserAgentRule.d.ts.map +1 -1
- package/dist/src/rules/http/HttpUserAgentRule.js +1 -1
- package/dist/src/rules/http/HttpUserAgentRule.js.map +1 -1
- package/dist/src/rules/index.d.ts +1 -1
- package/dist/src/rules/index.d.ts.map +1 -1
- package/dist/src/rules/index.js +7 -5
- package/dist/src/rules/index.js.map +1 -1
- package/dist/src/rules/logging/LoggerCategoryRule.js +2 -2
- package/dist/src/rules/logging/LoggerCategoryRule.js.map +1 -1
- package/dist/src/rules/logging/LoggerInUntilSuccessfulRule.js +1 -1
- package/dist/src/rules/logging/LoggerInUntilSuccessfulRule.js.map +1 -1
- package/dist/src/rules/logging/LoggerPayloadRule.d.ts.map +1 -1
- package/dist/src/rules/logging/LoggerPayloadRule.js +3 -3
- package/dist/src/rules/logging/LoggerPayloadRule.js.map +1 -1
- package/dist/src/rules/naming/FlowCasingRule.d.ts +1 -0
- package/dist/src/rules/naming/FlowCasingRule.d.ts.map +1 -1
- package/dist/src/rules/naming/FlowCasingRule.js +7 -1
- package/dist/src/rules/naming/FlowCasingRule.js.map +1 -1
- package/dist/src/rules/naming/FlowNamingRule.d.ts.map +1 -1
- package/dist/src/rules/naming/FlowNamingRule.js +12 -1
- package/dist/src/rules/naming/FlowNamingRule.js.map +1 -1
- package/dist/src/rules/naming/VariableNamingRule.d.ts.map +1 -1
- package/dist/src/rules/naming/VariableNamingRule.js +3 -3
- package/dist/src/rules/naming/VariableNamingRule.js.map +1 -1
- package/dist/src/rules/performance/AsyncErrorHandlerRule.d.ts.map +1 -1
- package/dist/src/rules/performance/AsyncErrorHandlerRule.js +1 -1
- package/dist/src/rules/performance/AsyncErrorHandlerRule.js.map +1 -1
- package/dist/src/rules/performance/LargeChoiceBlockRule.d.ts.map +1 -1
- package/dist/src/rules/performance/LargeChoiceBlockRule.js +1 -1
- package/dist/src/rules/performance/LargeChoiceBlockRule.js.map +1 -1
- package/dist/src/rules/performance/ScatterGatherRoutesRule.d.ts.map +1 -1
- package/dist/src/rules/performance/ScatterGatherRoutesRule.js +1 -1
- package/dist/src/rules/performance/ScatterGatherRoutesRule.js.map +1 -1
- package/dist/src/rules/security/HardcodedCredentialsRule.d.ts.map +1 -1
- package/dist/src/rules/security/HardcodedCredentialsRule.js +6 -6
- package/dist/src/rules/security/HardcodedCredentialsRule.js.map +1 -1
- package/dist/src/rules/security/HardcodedHttpRule.d.ts.map +1 -1
- package/dist/src/rules/security/HardcodedHttpRule.js +2 -6
- package/dist/src/rules/security/HardcodedHttpRule.js.map +1 -1
- package/dist/src/rules/security/InsecureTlsRule.d.ts.map +1 -1
- package/dist/src/rules/security/InsecureTlsRule.js +2 -2
- package/dist/src/rules/security/InsecureTlsRule.js.map +1 -1
- package/dist/src/rules/standards/ChoiceAntiPatternRule.d.ts.map +1 -1
- package/dist/src/rules/standards/ChoiceAntiPatternRule.js +8 -2
- package/dist/src/rules/standards/ChoiceAntiPatternRule.js.map +1 -1
- package/dist/src/rules/standards/DeprecatedComponentRule.d.ts.map +1 -1
- package/dist/src/rules/standards/DeprecatedComponentRule.js +1 -1
- package/dist/src/rules/standards/DeprecatedComponentRule.js.map +1 -1
- package/dist/src/rules/standards/DwlStandardsRule.d.ts.map +1 -1
- package/dist/src/rules/standards/DwlStandardsRule.js +1 -1
- package/dist/src/rules/standards/DwlStandardsRule.js.map +1 -1
- package/dist/src/rules/structure/StructureRules.d.ts.map +1 -1
- package/dist/src/rules/structure/StructureRules.js +6 -9
- package/dist/src/rules/structure/StructureRules.js.map +1 -1
- package/dist/src/rules/yaml/YamlRules.d.ts.map +1 -1
- package/dist/src/rules/yaml/YamlRules.js +19 -12
- package/dist/src/rules/yaml/YamlRules.js.map +1 -1
- package/dist/src/types/Config.d.ts.map +1 -1
- package/dist/src/types/Config.js +1 -5
- package/dist/src/types/Config.js.map +1 -1
- package/docs/README.md +95 -0
- package/docs/best-practices/documentation-standards.md +82 -0
- package/docs/best-practices/folder-structure.md +61 -0
- package/docs/best-practices/mulesoft-best-practices.md +902 -0
- package/docs/best-practices/rules-catalog.md +736 -0
- package/docs/linter/architecture.md +294 -0
- package/docs/linter/extending.md +426 -0
- package/docs/linter/folder-structure.md +251 -0
- package/docs/linter/images/html-report-dashboard.png +0 -0
- package/docs/linter/naming-conventions.md +300 -0
- package/docs/linter/rule-engine.md +532 -0
- package/docs/mcp-design.md +80 -0
- package/package.json +6 -3
|
@@ -0,0 +1,902 @@
|
|
|
1
|
+
# MuleSoft Development Best Practices
|
|
2
|
+
|
|
3
|
+
> **Purpose:** Comprehensive guide for building maintainable, secure, and performant Mule applications. This guide covers both practices enforced by mule-lint and general development guidelines for MuleSoft developers.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
### Linter-Enforced Practices
|
|
10
|
+
- [API-Led Connectivity](#api-led-connectivity)
|
|
11
|
+
- [Error Handling](#error-handling)
|
|
12
|
+
- [Logging Standards](#logging-standards)
|
|
13
|
+
- [Security Guidelines](#security-guidelines)
|
|
14
|
+
- [Performance Patterns](#performance-patterns)
|
|
15
|
+
- [Project Structure](#project-structure)
|
|
16
|
+
- [Naming Conventions](#naming-conventions)
|
|
17
|
+
- [Configuration Management](#configuration-management)
|
|
18
|
+
- [DataWeave Best Practices](#dataweave-best-practices)
|
|
19
|
+
- [Documentation Standards](#documentation-standards)
|
|
20
|
+
|
|
21
|
+
### General Developer Guidelines
|
|
22
|
+
- [Testing with MUnit](#testing-with-munit)
|
|
23
|
+
- [CI/CD Integration](#cicd-integration)
|
|
24
|
+
- [API Versioning](#api-versioning)
|
|
25
|
+
- [Deployment Practices](#deployment-practices)
|
|
26
|
+
- [Monitoring and Observability](#monitoring-and-observability)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## API-Led Connectivity
|
|
31
|
+
|
|
32
|
+
MuleSoft's API-Led Connectivity approach organizes APIs into three layers, each with distinct responsibilities.
|
|
33
|
+
|
|
34
|
+
### The Three Layers
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
┌─────────────────────────────────────────────────────────┐
|
|
38
|
+
│ Experience Layer │
|
|
39
|
+
│ (Channel-specific: Web, Mobile, Partner APIs) │
|
|
40
|
+
│ Naming: *-exp-*, *-experience-* │
|
|
41
|
+
└─────────────────────┬───────────────────────────────────┘
|
|
42
|
+
│
|
|
43
|
+
┌─────────────────────▼───────────────────────────────────┐
|
|
44
|
+
│ Process Layer │
|
|
45
|
+
│ (Orchestration, Business Logic, Aggregation) │
|
|
46
|
+
│ Naming: *-proc-*, *-process-* │
|
|
47
|
+
└─────────────────────┬───────────────────────────────────┘
|
|
48
|
+
│
|
|
49
|
+
┌─────────────────────▼───────────────────────────────────┐
|
|
50
|
+
│ System Layer │
|
|
51
|
+
│ (Backend Connectivity: SAP, Salesforce, Databases) │
|
|
52
|
+
│ Naming: *-sys-*, *-system-* │
|
|
53
|
+
└─────────────────────────────────────────────────────────┘
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Layer Guidelines
|
|
57
|
+
|
|
58
|
+
| Layer | Should Have | Should NOT Have |
|
|
59
|
+
|-------|-------------|-----------------|
|
|
60
|
+
| **Experience** | HTTP listeners, channel-specific transformations | Direct database access, complex business logic |
|
|
61
|
+
| **Process** | Flow-refs to other APIs, orchestration logic | Direct system connections, database queries |
|
|
62
|
+
| **System** | Database operations, HTTP requests to backends | Business logic, data aggregation |
|
|
63
|
+
|
|
64
|
+
### Example Flow Structure
|
|
65
|
+
|
|
66
|
+
```xml
|
|
67
|
+
<!-- Experience Layer: User-facing API -->
|
|
68
|
+
<flow name="orders-exp-get-order-flow">
|
|
69
|
+
<http:listener config-ref="HTTPS_Listener" path="/orders/{orderId}"/>
|
|
70
|
+
<flow-ref name="orders-proc-get-order-subflow"/>
|
|
71
|
+
<ee:transform><!-- Channel-specific response format --></ee:transform>
|
|
72
|
+
</flow>
|
|
73
|
+
|
|
74
|
+
<!-- Process Layer: Orchestration -->
|
|
75
|
+
<sub-flow name="orders-proc-get-order-subflow">
|
|
76
|
+
<flow-ref name="orders-sys-get-order-subflow"/>
|
|
77
|
+
<flow-ref name="customers-sys-get-customer-subflow"/>
|
|
78
|
+
<!-- Aggregate data from multiple sources -->
|
|
79
|
+
</sub-flow>
|
|
80
|
+
|
|
81
|
+
<!-- System Layer: Database access -->
|
|
82
|
+
<sub-flow name="orders-sys-get-order-subflow">
|
|
83
|
+
<db:select config-ref="Database_Config">
|
|
84
|
+
<db:sql>SELECT * FROM orders WHERE id = :orderId</db:sql>
|
|
85
|
+
</db:select>
|
|
86
|
+
</sub-flow>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Related Rules:** `API-001`, `API-002`, `API-003`
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Error Handling
|
|
94
|
+
|
|
95
|
+
Proper error handling ensures consistent API responses and easier debugging.
|
|
96
|
+
|
|
97
|
+
### Key Principles
|
|
98
|
+
|
|
99
|
+
1. **Every flow needs error handling** - Either explicit or via global handler
|
|
100
|
+
2. **Set HTTP status codes** - Always set `httpStatus` variable for API responses
|
|
101
|
+
3. **Include correlation ID** - Enable distributed tracing
|
|
102
|
+
4. **Be specific about error types** - Avoid catching `type="ANY"`
|
|
103
|
+
|
|
104
|
+
### Global Error Handler Pattern
|
|
105
|
+
|
|
106
|
+
Create a reusable global error handler:
|
|
107
|
+
|
|
108
|
+
```xml
|
|
109
|
+
<!-- src/main/mule/global-error-handler.xml -->
|
|
110
|
+
<error-handler name="global-error-handler">
|
|
111
|
+
<on-error-propagate type="APIKIT:BAD_REQUEST">
|
|
112
|
+
<set-variable variableName="httpStatus" value="400"/>
|
|
113
|
+
<ee:transform>
|
|
114
|
+
<ee:set-payload><![CDATA[%dw 2.0
|
|
115
|
+
output application/json
|
|
116
|
+
---
|
|
117
|
+
{
|
|
118
|
+
correlationId: correlationId,
|
|
119
|
+
error: "Bad Request",
|
|
120
|
+
message: error.description
|
|
121
|
+
}]]></ee:set-payload>
|
|
122
|
+
</ee:transform>
|
|
123
|
+
</on-error-propagate>
|
|
124
|
+
|
|
125
|
+
<on-error-propagate type="APIKIT:NOT_FOUND">
|
|
126
|
+
<set-variable variableName="httpStatus" value="404"/>
|
|
127
|
+
<!-- ... -->
|
|
128
|
+
</on-error-propagate>
|
|
129
|
+
|
|
130
|
+
<!-- Catch-all for unexpected errors -->
|
|
131
|
+
<on-error-propagate>
|
|
132
|
+
<set-variable variableName="httpStatus" value="500"/>
|
|
133
|
+
<logger category="com.myorg.errors" level="ERROR"
|
|
134
|
+
message="#['Error: ' ++ error.description ++ ' | CorrelationId: ' ++ correlationId]"/>
|
|
135
|
+
<!-- ... -->
|
|
136
|
+
</on-error-propagate>
|
|
137
|
+
</error-handler>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Flow Error Handler Reference
|
|
141
|
+
|
|
142
|
+
```xml
|
|
143
|
+
<flow name="my-api-flow">
|
|
144
|
+
<http:listener config-ref="HTTPS_Listener" path="/resource"/>
|
|
145
|
+
<!-- Flow logic -->
|
|
146
|
+
<error-handler ref="global-error-handler"/>
|
|
147
|
+
</flow>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Related Rules:** `MULE-001`, `MULE-003`, `MULE-005`, `MULE-007`, `MULE-009`
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Logging Standards
|
|
155
|
+
|
|
156
|
+
Effective logging enables debugging and monitoring without compromising security or performance.
|
|
157
|
+
|
|
158
|
+
### Key Principles
|
|
159
|
+
|
|
160
|
+
1. **Always use categories** - Enable log filtering in production
|
|
161
|
+
2. **Never log full payloads** - May contain PII and cause performance issues
|
|
162
|
+
3. **Include correlation IDs** - Enable request tracing
|
|
163
|
+
4. **Use structured logging** - JSON format for log aggregation tools
|
|
164
|
+
|
|
165
|
+
### Logger Category Convention
|
|
166
|
+
|
|
167
|
+
Use hierarchical category names:
|
|
168
|
+
|
|
169
|
+
```xml
|
|
170
|
+
<!-- ✅ Good - Hierarchical categories -->
|
|
171
|
+
<logger category="com.myorg.orders.api" level="INFO"
|
|
172
|
+
message="#['Processing order: ' ++ vars.orderId]"/>
|
|
173
|
+
|
|
174
|
+
<logger category="com.myorg.orders.db" level="DEBUG"
|
|
175
|
+
message="#['Query executed in ' ++ vars.queryTime ++ 'ms']"/>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Avoid Payload Logging
|
|
179
|
+
|
|
180
|
+
```xml
|
|
181
|
+
<!-- ❌ Bad - Logs entire payload -->
|
|
182
|
+
<logger message="#[payload]"/>
|
|
183
|
+
|
|
184
|
+
<!-- ✅ Good - Logs specific fields -->
|
|
185
|
+
<logger category="com.myorg.orders" level="INFO"
|
|
186
|
+
message="#['Order ' ++ payload.orderId ++ ' received for customer ' ++ payload.customerId]"/>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Structured Logging Format
|
|
190
|
+
|
|
191
|
+
```xml
|
|
192
|
+
<logger category="com.myorg.audit" level="INFO">
|
|
193
|
+
<message><![CDATA[#[%dw 2.0
|
|
194
|
+
output application/json
|
|
195
|
+
---
|
|
196
|
+
{
|
|
197
|
+
correlationId: correlationId,
|
|
198
|
+
event: "ORDER_CREATED",
|
|
199
|
+
orderId: payload.orderId,
|
|
200
|
+
timestamp: now()
|
|
201
|
+
}]]]></message>
|
|
202
|
+
</logger>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Avoid Logging in Retry Loops
|
|
206
|
+
|
|
207
|
+
```xml
|
|
208
|
+
<!-- ❌ Bad - Logger inside until-successful floods logs -->
|
|
209
|
+
<until-successful maxRetries="5">
|
|
210
|
+
<logger message="Attempting..."/> <!-- Will log 5 times on failure -->
|
|
211
|
+
<http:request config-ref="HTTP_Config" path="/api"/>
|
|
212
|
+
</until-successful>
|
|
213
|
+
|
|
214
|
+
<!-- ✅ Good - Log before and after -->
|
|
215
|
+
<logger category="com.myorg" message="Starting retry operation"/>
|
|
216
|
+
<until-successful maxRetries="5">
|
|
217
|
+
<http:request config-ref="HTTP_Config" path="/api"/>
|
|
218
|
+
</until-successful>
|
|
219
|
+
<logger category="com.myorg" message="Operation completed"/>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Related Rules:** `MULE-006`, `MULE-301`, `MULE-303`
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Security Guidelines
|
|
227
|
+
|
|
228
|
+
Protect sensitive data and follow secure development practices.
|
|
229
|
+
|
|
230
|
+
### Never Hardcode Secrets
|
|
231
|
+
|
|
232
|
+
```xml
|
|
233
|
+
<!-- ❌ Bad - Hardcoded credentials -->
|
|
234
|
+
<http:request-config host="api.example.com"
|
|
235
|
+
username="admin"
|
|
236
|
+
password="secret123"/>
|
|
237
|
+
|
|
238
|
+
<!-- ✅ Good - Property placeholders -->
|
|
239
|
+
<http:request-config host="${api.host}"
|
|
240
|
+
username="${api.username}"
|
|
241
|
+
password="${secure::api.password}"/>
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Never Hardcode URLs
|
|
245
|
+
|
|
246
|
+
```xml
|
|
247
|
+
<!-- ❌ Bad -->
|
|
248
|
+
<http:request url="https://api.production.example.com/orders"/>
|
|
249
|
+
|
|
250
|
+
<!-- ✅ Good -->
|
|
251
|
+
<http:request url="${api.orders.baseUrl}/orders"/>
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Encrypt Sensitive Properties
|
|
255
|
+
|
|
256
|
+
Use MuleSoft Secure Properties:
|
|
257
|
+
|
|
258
|
+
```yaml
|
|
259
|
+
# secure.yaml (encrypted)
|
|
260
|
+
api:
|
|
261
|
+
password: "![encryptedValue]"
|
|
262
|
+
clientSecret: "![encryptedValue]"
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### TLS Configuration
|
|
266
|
+
|
|
267
|
+
```xml
|
|
268
|
+
<!-- ❌ Bad - Insecure TLS -->
|
|
269
|
+
<tls:context name="Insecure_TLS">
|
|
270
|
+
<tls:trust-store insecure="true"/>
|
|
271
|
+
</tls:context>
|
|
272
|
+
|
|
273
|
+
<!-- ✅ Good - Proper certificate validation -->
|
|
274
|
+
<tls:context name="Secure_TLS">
|
|
275
|
+
<tls:trust-store path="${tls.truststore.path}"
|
|
276
|
+
password="${secure::tls.truststore.password}"/>
|
|
277
|
+
</tls:context>
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Related Rules:** `MULE-004`, `MULE-201`, `MULE-202`, `YAML-004`
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Performance Patterns
|
|
285
|
+
|
|
286
|
+
Avoid common performance anti-patterns.
|
|
287
|
+
|
|
288
|
+
### Async Scope Error Handling
|
|
289
|
+
|
|
290
|
+
Async scopes don't propagate errors to parent flows:
|
|
291
|
+
|
|
292
|
+
```xml
|
|
293
|
+
<!-- ❌ Bad - Errors silently swallowed -->
|
|
294
|
+
<async>
|
|
295
|
+
<http:request config-ref="HTTP_Config" path="/webhook"/>
|
|
296
|
+
</async>
|
|
297
|
+
|
|
298
|
+
<!-- ✅ Good - Explicit error handling -->
|
|
299
|
+
<async>
|
|
300
|
+
<try>
|
|
301
|
+
<http:request config-ref="HTTP_Config" path="/webhook"/>
|
|
302
|
+
<error-handler>
|
|
303
|
+
<on-error-continue>
|
|
304
|
+
<logger category="com.myorg.async" level="ERROR"
|
|
305
|
+
message="#['Async failed: ' ++ error.description]"/>
|
|
306
|
+
</on-error-continue>
|
|
307
|
+
</error-handler>
|
|
308
|
+
</try>
|
|
309
|
+
</async>
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Limit Choice Complexity
|
|
313
|
+
|
|
314
|
+
```xml
|
|
315
|
+
<!-- ❌ Bad - Too many when clauses -->
|
|
316
|
+
<choice>
|
|
317
|
+
<when expression="#[vars.status == 'NEW']">...</when>
|
|
318
|
+
<when expression="#[vars.status == 'PENDING']">...</when>
|
|
319
|
+
<when expression="#[vars.status == 'APPROVED']">...</when>
|
|
320
|
+
<!-- 10+ more conditions -->
|
|
321
|
+
<otherwise>...</otherwise>
|
|
322
|
+
</choice>
|
|
323
|
+
|
|
324
|
+
<!-- ✅ Good - Use DataWeave lookup -->
|
|
325
|
+
<ee:transform>
|
|
326
|
+
<ee:set-variable variableName="handler"><![CDATA[%dw 2.0
|
|
327
|
+
var handlers = {
|
|
328
|
+
"NEW": "new-handler-subflow",
|
|
329
|
+
"PENDING": "pending-handler-subflow",
|
|
330
|
+
"APPROVED": "approved-handler-subflow"
|
|
331
|
+
}
|
|
332
|
+
---
|
|
333
|
+
handlers[vars.status] default "default-handler-subflow"
|
|
334
|
+
]]></ee:set-variable>
|
|
335
|
+
</ee:transform>
|
|
336
|
+
<flow-ref name="#[vars.handler]"/>
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### HTTP Timeout Configuration
|
|
340
|
+
|
|
341
|
+
```xml
|
|
342
|
+
<!-- ✅ Always set explicit timeouts -->
|
|
343
|
+
<http:request-config name="HTTP_Request_Config"
|
|
344
|
+
responseTimeout="30000">
|
|
345
|
+
<http:request-connection host="${api.host}"
|
|
346
|
+
port="${api.port}"/>
|
|
347
|
+
</http:request-config>
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Scatter-Gather Limits
|
|
351
|
+
|
|
352
|
+
Limit parallel routes to avoid memory pressure:
|
|
353
|
+
|
|
354
|
+
```xml
|
|
355
|
+
<!-- Keep scatter-gather routes manageable (< 5-7) -->
|
|
356
|
+
<scatter-gather>
|
|
357
|
+
<route><flow-ref name="service1-subflow"/></route>
|
|
358
|
+
<route><flow-ref name="service2-subflow"/></route>
|
|
359
|
+
<route><flow-ref name="service3-subflow"/></route>
|
|
360
|
+
</scatter-gather>
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**Related Rules:** `MULE-403`, `MULE-501`, `MULE-502`, `MULE-503`, `MULE-801`
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Project Structure
|
|
368
|
+
|
|
369
|
+
Follow standard MuleSoft project organization.
|
|
370
|
+
|
|
371
|
+
### Required Structure
|
|
372
|
+
|
|
373
|
+
```
|
|
374
|
+
my-mule-project/
|
|
375
|
+
├── src/
|
|
376
|
+
│ ├── main/
|
|
377
|
+
│ │ ├── mule/ # Mule configuration files
|
|
378
|
+
│ │ │ ├── global.xml # Shared configs (listeners, error handlers)
|
|
379
|
+
│ │ │ ├── global-error-handler.xml
|
|
380
|
+
│ │ │ ├── orders-api.xml # API implementation
|
|
381
|
+
│ │ │ └── orders-flows.xml # Business flows
|
|
382
|
+
│ │ └── resources/
|
|
383
|
+
│ │ ├── api/ # RAML/OAS specifications
|
|
384
|
+
│ │ ├── dwl/ # External DataWeave files
|
|
385
|
+
│ │ │ ├── common.dwl # Reusable functions
|
|
386
|
+
│ │ │ └── transform-order.dwl
|
|
387
|
+
│ │ ├── dev.yaml # Environment configs
|
|
388
|
+
│ │ ├── qa.yaml
|
|
389
|
+
│ │ └── prod.yaml
|
|
390
|
+
│ └── test/
|
|
391
|
+
│ └── munit/ # MUnit test files
|
|
392
|
+
├── pom.xml
|
|
393
|
+
└── mule-artifact.json
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### File Organization Guidelines
|
|
397
|
+
|
|
398
|
+
| Guideline | Recommendation |
|
|
399
|
+
|-----------|----------------|
|
|
400
|
+
| Flows per file | Max 10 flows/sub-flows per XML file |
|
|
401
|
+
| File responsibility | One domain/feature per file |
|
|
402
|
+
| Global configs | Centralize in `global.xml` |
|
|
403
|
+
| Error handling | Separate `global-error-handler.xml` |
|
|
404
|
+
|
|
405
|
+
**Related Rules:** `MULE-802`, `MULE-803`, `MULE-804`
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
## Naming Conventions
|
|
410
|
+
|
|
411
|
+
Consistent naming improves readability and maintainability.
|
|
412
|
+
|
|
413
|
+
### Flows and Sub-flows
|
|
414
|
+
|
|
415
|
+
```xml
|
|
416
|
+
<!-- Use kebab-case with suffixes -->
|
|
417
|
+
<flow name="orders-api-get-order-flow">
|
|
418
|
+
<sub-flow name="validate-order-input-subflow">
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Variables
|
|
422
|
+
|
|
423
|
+
```xml
|
|
424
|
+
<!-- Use camelCase -->
|
|
425
|
+
<set-variable variableName="orderId"/>
|
|
426
|
+
<set-variable variableName="customerData"/>
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### Connector Configurations
|
|
430
|
+
|
|
431
|
+
```xml
|
|
432
|
+
<!-- Use descriptive names -->
|
|
433
|
+
<http:request-config name="Orders_API_Config"/>
|
|
434
|
+
<db:config name="Orders_Database_Config"/>
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
**Related Rules:** `MULE-002`, `MULE-101`, `MULE-102`, `EXP-002`
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## Configuration Management
|
|
442
|
+
|
|
443
|
+
Externalize environment-specific values.
|
|
444
|
+
|
|
445
|
+
### Environment Files
|
|
446
|
+
|
|
447
|
+
Create separate files for each environment:
|
|
448
|
+
|
|
449
|
+
```yaml
|
|
450
|
+
# dev.yaml
|
|
451
|
+
http:
|
|
452
|
+
host: "0.0.0.0"
|
|
453
|
+
port: "8081"
|
|
454
|
+
|
|
455
|
+
api:
|
|
456
|
+
orders:
|
|
457
|
+
baseUrl: "http://localhost:8082/api"
|
|
458
|
+
timeout: "30000"
|
|
459
|
+
|
|
460
|
+
db:
|
|
461
|
+
host: "localhost"
|
|
462
|
+
port: "5432"
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### Property Naming
|
|
466
|
+
|
|
467
|
+
Use hierarchical, lowercase naming:
|
|
468
|
+
|
|
469
|
+
```yaml
|
|
470
|
+
# ✅ Good
|
|
471
|
+
db.host: localhost
|
|
472
|
+
api.orders.baseUrl: http://example.com
|
|
473
|
+
http.request.timeout: 30000
|
|
474
|
+
|
|
475
|
+
# ❌ Bad
|
|
476
|
+
DBHOST: localhost
|
|
477
|
+
ApiOrdersUrl: http://example.com
|
|
478
|
+
HTTP_TIMEOUT: 30000
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
**Related Rules:** `YAML-001`, `YAML-003`
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
## DataWeave Best Practices
|
|
486
|
+
|
|
487
|
+
Write maintainable and reusable DataWeave code.
|
|
488
|
+
|
|
489
|
+
### Externalize Complex Transforms
|
|
490
|
+
|
|
491
|
+
```xml
|
|
492
|
+
<!-- ❌ Bad - Large inline transform -->
|
|
493
|
+
<ee:transform>
|
|
494
|
+
<ee:set-payload><![CDATA[%dw 2.0
|
|
495
|
+
<!-- 50+ lines of DataWeave -->
|
|
496
|
+
]]></ee:set-payload>
|
|
497
|
+
</ee:transform>
|
|
498
|
+
|
|
499
|
+
<!-- ✅ Good - External file -->
|
|
500
|
+
<ee:transform>
|
|
501
|
+
<ee:set-payload resource="dwl/transform-order-response.dwl"/>
|
|
502
|
+
</ee:transform>
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Create Reusable Modules
|
|
506
|
+
|
|
507
|
+
```dataweave
|
|
508
|
+
// src/main/resources/dwl/common.dwl
|
|
509
|
+
%dw 2.0
|
|
510
|
+
|
|
511
|
+
fun formatDate(date: DateTime) =
|
|
512
|
+
date as String {format: "yyyy-MM-dd"}
|
|
513
|
+
|
|
514
|
+
fun maskPII(value: String) =
|
|
515
|
+
value[0 to 2] ++ "****" ++ value[-2 to -1]
|
|
516
|
+
|
|
517
|
+
fun toErrorResponse(error, correlationId: String) = {
|
|
518
|
+
correlationId: correlationId,
|
|
519
|
+
timestamp: now(),
|
|
520
|
+
error: error.errorType.identifier,
|
|
521
|
+
message: error.description
|
|
522
|
+
}
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
### File Naming
|
|
526
|
+
|
|
527
|
+
Use kebab-case for DWL files:
|
|
528
|
+
- `transform-order.dwl`
|
|
529
|
+
- `validate-input.dwl`
|
|
530
|
+
- `common-utils.dwl`
|
|
531
|
+
|
|
532
|
+
**Related Rules:** `DW-001`, `DW-002`, `DW-003`
|
|
533
|
+
|
|
534
|
+
---
|
|
535
|
+
|
|
536
|
+
## Documentation Standards
|
|
537
|
+
|
|
538
|
+
Document for maintainability.
|
|
539
|
+
|
|
540
|
+
### Flow Documentation
|
|
541
|
+
|
|
542
|
+
```xml
|
|
543
|
+
<flow name="orders-api-create-order-flow"
|
|
544
|
+
doc:name="Create Order"
|
|
545
|
+
doc:description="Creates a new order in the system. Validates input, checks inventory, and persists to database.">
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### Component Documentation
|
|
549
|
+
|
|
550
|
+
```xml
|
|
551
|
+
<logger doc:name="Log Order Received"
|
|
552
|
+
category="com.myorg.orders"
|
|
553
|
+
message="#['Order received: ' ++ payload.orderId]"/>
|
|
554
|
+
|
|
555
|
+
<ee:transform doc:name="Transform to Database Format">
|
|
556
|
+
<!-- ... -->
|
|
557
|
+
</ee:transform>
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
**Related Rules:** `MULE-601`, `MULE-604`
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
## Quick Reference Card
|
|
565
|
+
|
|
566
|
+
| Practice | Do | Don't |
|
|
567
|
+
|----------|-----|-------|
|
|
568
|
+
| **Error Handling** | Use global handler, set httpStatus | Catch `type="ANY"`, ignore errors |
|
|
569
|
+
| **Logging** | Use categories, log specific fields | Log `#[payload]`, log in retry loops |
|
|
570
|
+
| **Security** | Use `${property}`, encrypt secrets | Hardcode URLs, passwords, keys |
|
|
571
|
+
| **Performance** | Set timeouts, handle async errors | Unlimited retries, huge choice blocks |
|
|
572
|
+
| **Naming** | kebab-case flows, camelCase vars | Inconsistent casing, no suffixes |
|
|
573
|
+
| **Structure** | Separate files by domain | Monolithic XML files |
|
|
574
|
+
| **Config** | Environment-specific YAML files | Hardcoded values |
|
|
575
|
+
| **DataWeave** | External .dwl files, reusable modules | Large inline transforms |
|
|
576
|
+
|
|
577
|
+
---
|
|
578
|
+
|
|
579
|
+
# General Developer Guidelines
|
|
580
|
+
|
|
581
|
+
> The following sections cover general MuleSoft development best practices that are not enforced by the linter but are important for building production-ready applications.
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
## Testing with MUnit
|
|
586
|
+
|
|
587
|
+
MUnit is MuleSoft's native testing framework. Comprehensive testing is essential for reliable integrations.
|
|
588
|
+
|
|
589
|
+
### Test Coverage Goals
|
|
590
|
+
|
|
591
|
+
| Test Type | Coverage Target | Purpose |
|
|
592
|
+
|-----------|-----------------|---------|
|
|
593
|
+
| Unit Tests | 80%+ flow coverage | Validate individual flow logic |
|
|
594
|
+
| Integration Tests | All critical paths | Validate end-to-end scenarios |
|
|
595
|
+
| Error Scenario Tests | All error handlers | Validate error responses |
|
|
596
|
+
|
|
597
|
+
### MUnit Best Practices
|
|
598
|
+
|
|
599
|
+
```xml
|
|
600
|
+
<!-- test/munit/orders-api-test-suite.xml -->
|
|
601
|
+
<munit:test name="create-order-success-test"
|
|
602
|
+
description="Validates successful order creation">
|
|
603
|
+
|
|
604
|
+
<!-- Mock external dependencies -->
|
|
605
|
+
<munit:behavior>
|
|
606
|
+
<munit-tools:mock-when processor="http:request">
|
|
607
|
+
<munit-tools:with-attributes>
|
|
608
|
+
<munit-tools:with-attribute attributeName="config-ref"
|
|
609
|
+
whereValue="Orders_HTTP_Config"/>
|
|
610
|
+
</munit-tools:with-attributes>
|
|
611
|
+
<munit-tools:then-return>
|
|
612
|
+
<munit-tools:payload value='{"orderId": "12345"}'/>
|
|
613
|
+
</munit-tools:then-return>
|
|
614
|
+
</munit-tools:mock-when>
|
|
615
|
+
</munit:behavior>
|
|
616
|
+
|
|
617
|
+
<!-- Execute -->
|
|
618
|
+
<munit:execution>
|
|
619
|
+
<flow-ref name="create-order-flow"/>
|
|
620
|
+
</munit:execution>
|
|
621
|
+
|
|
622
|
+
<!-- Assert -->
|
|
623
|
+
<munit:validation>
|
|
624
|
+
<munit-tools:assert-that expression="#[payload.orderId]"
|
|
625
|
+
is="#[MunitTools::notNullValue()]"/>
|
|
626
|
+
</munit:validation>
|
|
627
|
+
</munit:test>
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
### Test Organization
|
|
631
|
+
|
|
632
|
+
```
|
|
633
|
+
src/test/munit/
|
|
634
|
+
├── orders-api-test-suite.xml # API endpoint tests
|
|
635
|
+
├── orders-flows-test-suite.xml # Business logic tests
|
|
636
|
+
├── error-handling-test-suite.xml # Error scenario tests
|
|
637
|
+
└── common-test-resources.xml # Shared mocks and utilities
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
### Key Principles
|
|
641
|
+
|
|
642
|
+
1. **Mock external dependencies** - Don't call real systems in unit tests
|
|
643
|
+
2. **Test error scenarios** - Verify all error handlers work correctly
|
|
644
|
+
3. **Use descriptive test names** - Names should describe the scenario
|
|
645
|
+
4. **Isolate tests** - Each test should be independent
|
|
646
|
+
|
|
647
|
+
---
|
|
648
|
+
|
|
649
|
+
## CI/CD Integration
|
|
650
|
+
|
|
651
|
+
Automate build, test, and deployment for consistent, reliable releases.
|
|
652
|
+
|
|
653
|
+
### Recommended Pipeline Stages
|
|
654
|
+
|
|
655
|
+
```
|
|
656
|
+
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
657
|
+
│ Build │ → │ Lint │ → │ Test │ → │ Package │ → │ Deploy │
|
|
658
|
+
│ │ │ │ │ │ │ │ │ │
|
|
659
|
+
│ mvn │ │ mule- │ │ mvn test │ │ mvn │ │ anypoint │
|
|
660
|
+
│ compile │ │ lint │ │ │ │ package │ │ deploy │
|
|
661
|
+
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
### GitHub Actions Example
|
|
665
|
+
|
|
666
|
+
```yaml
|
|
667
|
+
# .github/workflows/mule-ci.yml
|
|
668
|
+
name: Mule CI/CD
|
|
669
|
+
|
|
670
|
+
on:
|
|
671
|
+
push:
|
|
672
|
+
branches: [main, develop]
|
|
673
|
+
pull_request:
|
|
674
|
+
branches: [main]
|
|
675
|
+
|
|
676
|
+
jobs:
|
|
677
|
+
build-and-test:
|
|
678
|
+
runs-on: ubuntu-latest
|
|
679
|
+
steps:
|
|
680
|
+
- uses: actions/checkout@v4
|
|
681
|
+
|
|
682
|
+
- name: Set up JDK 11
|
|
683
|
+
uses: actions/setup-java@v3
|
|
684
|
+
with:
|
|
685
|
+
java-version: '11'
|
|
686
|
+
distribution: 'adopt'
|
|
687
|
+
|
|
688
|
+
- name: Cache Maven packages
|
|
689
|
+
uses: actions/cache@v3
|
|
690
|
+
with:
|
|
691
|
+
path: ~/.m2
|
|
692
|
+
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
|
693
|
+
|
|
694
|
+
- name: Build with Maven
|
|
695
|
+
run: mvn -B clean compile
|
|
696
|
+
|
|
697
|
+
- name: Run mule-lint
|
|
698
|
+
run: npx @sfdxy/mule-lint ./src/main/mule -f sarif -o lint-results.sarif
|
|
699
|
+
|
|
700
|
+
- name: Run MUnit tests
|
|
701
|
+
run: mvn -B test
|
|
702
|
+
|
|
703
|
+
- name: Upload SARIF results
|
|
704
|
+
uses: github/codeql-action/upload-sarif@v2
|
|
705
|
+
with:
|
|
706
|
+
sarif_file: lint-results.sarif
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
### Git Branch Strategy
|
|
710
|
+
|
|
711
|
+
| Branch | Purpose | Deployment Target |
|
|
712
|
+
|--------|---------|-------------------|
|
|
713
|
+
| `main` | Production-ready code | Production |
|
|
714
|
+
| `develop` | Integration branch | QA/Staging |
|
|
715
|
+
| `feature/*` | New features | Development |
|
|
716
|
+
| `hotfix/*` | Production fixes | Production |
|
|
717
|
+
|
|
718
|
+
---
|
|
719
|
+
|
|
720
|
+
## API Versioning
|
|
721
|
+
|
|
722
|
+
Plan for API evolution from the start.
|
|
723
|
+
|
|
724
|
+
### URL-Based Versioning (Recommended)
|
|
725
|
+
|
|
726
|
+
```
|
|
727
|
+
/api/v1/orders
|
|
728
|
+
/api/v2/orders
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
### Implementation Pattern
|
|
732
|
+
|
|
733
|
+
```xml
|
|
734
|
+
<!-- src/main/mule/orders-api-v1.xml -->
|
|
735
|
+
<flow name="orders-api-v1-main-flow">
|
|
736
|
+
<http:listener config-ref="HTTPS_Listener" path="/api/v1/orders/*"/>
|
|
737
|
+
<apikit:router config-ref="orders-v1-config"/>
|
|
738
|
+
</flow>
|
|
739
|
+
|
|
740
|
+
<!-- src/main/mule/orders-api-v2.xml -->
|
|
741
|
+
<flow name="orders-api-v2-main-flow">
|
|
742
|
+
<http:listener config-ref="HTTPS_Listener" path="/api/v2/orders/*"/>
|
|
743
|
+
<apikit:router config-ref="orders-v2-config"/>
|
|
744
|
+
</flow>
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
### Version Deprecation Strategy
|
|
748
|
+
|
|
749
|
+
1. **Announce deprecation** - Communicate timeline to consumers
|
|
750
|
+
2. **Add deprecation headers** - Return `Deprecation` header in responses
|
|
751
|
+
3. **Monitor usage** - Track v1 vs v2 adoption
|
|
752
|
+
4. **Sunset gracefully** - Remove only after consumer migration
|
|
753
|
+
|
|
754
|
+
```xml
|
|
755
|
+
<!-- Add deprecation warning -->
|
|
756
|
+
<set-variable variableName="outboundHeaders" value="#[{
|
|
757
|
+
'Deprecation': 'true',
|
|
758
|
+
'Sunset': 'Sat, 01 Jan 2025 00:00:00 GMT',
|
|
759
|
+
'Link': '</api/v2/orders>; rel="successor-version"'
|
|
760
|
+
}]"/>
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
---
|
|
764
|
+
|
|
765
|
+
## Deployment Practices
|
|
766
|
+
|
|
767
|
+
Deploy safely and consistently across environments.
|
|
768
|
+
|
|
769
|
+
### Environment Promotion
|
|
770
|
+
|
|
771
|
+
```
|
|
772
|
+
Development → QA → Staging → Production
|
|
773
|
+
↓ ↓ ↓ ↓
|
|
774
|
+
dev.yaml qa.yaml stg.yaml prod.yaml
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
### Deployment Checklist
|
|
778
|
+
|
|
779
|
+
| Item | Description |
|
|
780
|
+
|------|-------------|
|
|
781
|
+
| ✅ All tests pass | MUnit and integration tests |
|
|
782
|
+
| ✅ Lint checks pass | No errors from mule-lint |
|
|
783
|
+
| ✅ Properties configured | Environment YAML verified |
|
|
784
|
+
| ✅ Secrets encrypted | No plaintext credentials |
|
|
785
|
+
| ✅ API Manager policies | Authentication, rate limiting |
|
|
786
|
+
| ✅ Monitoring configured | Dashboards and alerts ready |
|
|
787
|
+
|
|
788
|
+
### Blue-Green Deployment
|
|
789
|
+
|
|
790
|
+
For zero-downtime deployments:
|
|
791
|
+
|
|
792
|
+
1. Deploy new version to "green" workers
|
|
793
|
+
2. Run smoke tests against green
|
|
794
|
+
3. Switch load balancer to green
|
|
795
|
+
4. Monitor for issues
|
|
796
|
+
5. Decommission "blue" workers (or keep for rollback)
|
|
797
|
+
|
|
798
|
+
### Rollback Strategy
|
|
799
|
+
|
|
800
|
+
```bash
|
|
801
|
+
# Anypoint CLI rollback example
|
|
802
|
+
anypoint-cli runtime-mgr cloudhub-application modify \
|
|
803
|
+
--environment Production \
|
|
804
|
+
--applicationName orders-api \
|
|
805
|
+
--runtime 4.4.0 \
|
|
806
|
+
--artifact-id orders-api-1.2.0.jar
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
---
|
|
810
|
+
|
|
811
|
+
## Monitoring and Observability
|
|
812
|
+
|
|
813
|
+
Production applications need comprehensive monitoring.
|
|
814
|
+
|
|
815
|
+
### The Three Pillars
|
|
816
|
+
|
|
817
|
+
| Pillar | Tool | Purpose |
|
|
818
|
+
|--------|------|---------|
|
|
819
|
+
| **Logs** | Anypoint Monitoring, Splunk, ELK | Debug issues, audit trail |
|
|
820
|
+
| **Metrics** | Anypoint Monitoring, Grafana | Performance, health status |
|
|
821
|
+
| **Traces** | Anypoint Monitoring, Jaeger | Request flow, latency analysis |
|
|
822
|
+
|
|
823
|
+
### Key Metrics to Monitor
|
|
824
|
+
|
|
825
|
+
```
|
|
826
|
+
Application Health:
|
|
827
|
+
├── Response time (p50, p95, p99)
|
|
828
|
+
├── Error rate (%)
|
|
829
|
+
├── Throughput (requests/sec)
|
|
830
|
+
├── Active connections
|
|
831
|
+
└── Worker CPU/Memory usage
|
|
832
|
+
|
|
833
|
+
Business Metrics:
|
|
834
|
+
├── Orders processed per hour
|
|
835
|
+
├── Failed transactions
|
|
836
|
+
├── API calls by consumer
|
|
837
|
+
└── Integration latency by backend
|
|
838
|
+
```
|
|
839
|
+
|
|
840
|
+
### Alerting Best Practices
|
|
841
|
+
|
|
842
|
+
| Alert Level | Condition | Response |
|
|
843
|
+
|-------------|-----------|----------|
|
|
844
|
+
| **Critical** | Error rate > 10%, App down | Immediate on-call response |
|
|
845
|
+
| **Warning** | Error rate > 5%, Latency > 5s | Investigate within 1 hour |
|
|
846
|
+
| **Info** | Unusual patterns, Resource > 70% | Review in daily standup |
|
|
847
|
+
|
|
848
|
+
### Correlation ID Pattern
|
|
849
|
+
|
|
850
|
+
Ensure correlation IDs flow through all systems:
|
|
851
|
+
|
|
852
|
+
```xml
|
|
853
|
+
<!-- Set correlation ID at entry point -->
|
|
854
|
+
<set-variable variableName="correlationId"
|
|
855
|
+
value="#[correlationId default uuid()]"/>
|
|
856
|
+
|
|
857
|
+
<!-- Include in all outbound requests -->
|
|
858
|
+
<http:request config-ref="HTTP_Config" path="/downstream">
|
|
859
|
+
<http:headers><![CDATA[#[{
|
|
860
|
+
'X-Correlation-ID': vars.correlationId
|
|
861
|
+
}]]]></http:headers>
|
|
862
|
+
</http:request>
|
|
863
|
+
|
|
864
|
+
<!-- Include in all log messages -->
|
|
865
|
+
<logger category="com.myorg"
|
|
866
|
+
message="#['[' ++ vars.correlationId ++ '] Processing request...']"/>
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
### Health Check Endpoint
|
|
870
|
+
|
|
871
|
+
Expose a health endpoint for load balancers and monitoring:
|
|
872
|
+
|
|
873
|
+
```xml
|
|
874
|
+
<flow name="health-check-flow">
|
|
875
|
+
<http:listener config-ref="HTTPS_Listener" path="/health"/>
|
|
876
|
+
<set-payload value='#[%dw 2.0
|
|
877
|
+
output application/json
|
|
878
|
+
---
|
|
879
|
+
{
|
|
880
|
+
status: "UP",
|
|
881
|
+
timestamp: now(),
|
|
882
|
+
version: p("app.version"),
|
|
883
|
+
environment: p("mule.env")
|
|
884
|
+
}]'/>
|
|
885
|
+
</flow>
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
---
|
|
889
|
+
|
|
890
|
+
## Summary
|
|
891
|
+
|
|
892
|
+
This guide covers both linter-enforced practices and general developer guidelines:
|
|
893
|
+
|
|
894
|
+
| Category | Linter Enforced | General Guidelines |
|
|
895
|
+
|----------|-----------------|-------------------|
|
|
896
|
+
| Code Quality | ✅ Naming, Structure, Complexity | Testing, Code Review |
|
|
897
|
+
| Security | ✅ Hardcoded secrets, TLS | Secrets Management, IAM |
|
|
898
|
+
| Operations | ✅ Error handling, Logging | CI/CD, Monitoring, Deployment |
|
|
899
|
+
| Architecture | ✅ API-Led patterns | Versioning, Documentation |
|
|
900
|
+
|
|
901
|
+
For linter rule details, see the [Rules Catalog](rules-catalog.md).
|
|
902
|
+
|