Skip to content

Commit 688c43a

Browse files
committed
I've addressed the comments and tweaked the logic to fit the rule for all LRO operations.
1 parent ed01a3b commit 688c43a

File tree

5 files changed

+72
-49
lines changed

5 files changed

+72
-49
lines changed

docs/lro-azure-async-operation-header.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,32 @@ ARM OpenAPI(swagger) specs
1414

1515
## Output Message
1616

17-
A 202 response should include an Azure-AsyncOperation response header.
17+
All long-running operations must include an Azure-AsyncOperation response header.
1818

1919
## Description
2020

21-
Azure-AsyncOperation header must be supported for all async operations that return 202.
21+
Azure-AsyncOperation header must be supported for all async long-running operations.
2222

2323
## CreatedAt
2424

2525
Oct 11, 2024
2626

2727
## How to fix the violation
2828

29-
Adding the Azure-AsyncOperation header schema to the 202 response header schema.
29+
Adding the Azure-AsyncOperation header to the response..
3030

3131
## Good Example
3232

3333
```json
3434
"/api/configServers": {
35-
put: {
36-
operationId: "ConfigServers_Update",
37-
responses: {
38-
202: {
39-
description: 'Accepted',
40-
headers: {
41-
'Azure-AsyncOperation': {
42-
type: 'string',
35+
"put": {
36+
"operationId": "ConfigServers_Update",
37+
"responses": {
38+
"202": {
39+
"description": "Accepted",
40+
"headers": {
41+
"Azure-AsyncOperation": {
42+
"type": "string",
4343
},
4444
},
4545
},
@@ -52,12 +52,12 @@ Adding the Azure-AsyncOperation header schema to the 202 response header schema.
5252

5353
```json
5454
"/api/configServers": {
55-
put: {
56-
operationId: "ConfigServers_Update",
57-
responses: {
55+
"put": {
56+
"operationId": "ConfigServers_Update",
57+
"responses": {
5858
"202": {
59-
description: "Success",
60-
headers: {
59+
"description": "Success",
60+
"headers": {
6161
//No Azure-AsyncOperation header
6262
},
6363
},

docs/rules.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ Please refer to [long-running-response-status-code-data-plane.md](./long-running
497497

498498
### LroAzureAsyncOperationHeader
499499

500-
Azure-AsyncOperation header must be supported for all async operations that return 202.
500+
Azure-AsyncOperation header must be supported for all async long-running operations.
501501

502502
Please refer to [lro-azure-async-operation-header.md](./lro-azure-async-operation-header.md) for details.
503503

packages/rulesets/generated/spectral/az-arm.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3313,16 +3313,13 @@ const ruleset = {
33133313
},
33143314
LroAzureAsyncOperationHeader: {
33153315
rpcGuidelineCode: "RPC-Async-V1-06",
3316-
description: "Azure-AsyncOperation header must be supported for all async operations that return 202.",
3316+
description: "Azure-AsyncOperation header must be supported for all async long-running operations.",
33173317
message: "{{description}}",
33183318
severity: "error",
33193319
formats: [oas2],
3320-
given: "$.paths[*][*].responses[?(@property == '202')]",
3320+
given: "$[paths,'x-ms-paths'].*.*[?(@property === 'x-ms-long-running-operation' && @ === true)]^.responses.*.headers[?(@property !== 'Azure-AsyncOperation')]",
33213321
then: {
3322-
function: hasHeader,
3323-
functionOptions: {
3324-
name: "Azure-AsyncOperation",
3325-
},
3322+
function: falsy,
33263323
},
33273324
},
33283325
LroLocationHeader: {

packages/rulesets/src/spectral/az-arm.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,16 +161,14 @@ const ruleset: any = {
161161
// RPC Code: RPC-Async-V1-06
162162
LroAzureAsyncOperationHeader: {
163163
rpcGuidelineCode: "RPC-Async-V1-06",
164-
description: "Azure-AsyncOperation header must be supported for all async operations that return 202.",
164+
description: "Azure-AsyncOperation header must be supported for all async long-running operations.",
165165
message: "{{description}}",
166166
severity: "error",
167167
formats: [oas2],
168-
given: "$.paths[*][*].responses[?(@property == '202')]",
168+
given:
169+
"$[paths,'x-ms-paths'].*.*[?(@property === 'x-ms-long-running-operation' && @ === true)]^.responses.*.headers[?(@property !== 'Azure-AsyncOperation')]",
169170
then: {
170-
function: hasheader,
171-
functionOptions: {
172-
name: "Azure-AsyncOperation",
173-
},
171+
function: falsy,
174172
},
175173
},
176174

packages/rulesets/src/spectral/test/lro-azure-async-operation-header.test.ts

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,7 @@ test("LroAzureAsyncOperationHeader should find no errors", () => {
2323
},
2424
202: {
2525
description: "Accepted",
26-
headers: {
27-
"Azure-AsyncOperation": {
28-
description: "The URL where the status of the asynchronous operation can be checked.",
29-
type: "string",
30-
},
31-
},
26+
// no header scenario
3227
},
3328
default: {
3429
description: "Error",
@@ -37,14 +32,15 @@ test("LroAzureAsyncOperationHeader should find no errors", () => {
3732
},
3833
post: {
3934
operationId: "foo_post",
35+
"x-ms-long-running-operation": true,
4036
responses: {
4137
200: {
4238
description: "Success",
4339
},
4440
202: {
4541
description: "Accepted",
4642
headers: {
47-
"Azure-asyncoperation": {
43+
"Azure-AsyncOperation": {
4844
description: "The URL where the status of the asynchronous operation can be checked.",
4945
type: "string",
5046
},
@@ -57,14 +53,12 @@ test("LroAzureAsyncOperationHeader should find no errors", () => {
5753
},
5854
put: {
5955
operationId: "foo_put",
56+
"x-ms-long-running-operation": true,
6057
responses: {
61-
200: {
62-
description: "Success",
63-
},
64-
202: {
58+
204: {
6559
description: "Accepted",
6660
headers: {
67-
"azure-asyncOperation": {
61+
"Azure-AsyncOperation": {
6862
description: "The URL where the status of the asynchronous operation can be checked.",
6963
type: "string",
7064
},
@@ -75,6 +69,17 @@ test("LroAzureAsyncOperationHeader should find no errors", () => {
7569
},
7670
},
7771
},
72+
delete: {
73+
operationId: "foo_put",
74+
responses: {
75+
204: {
76+
description: "No x-ms-long-running-operation ",
77+
},
78+
default: {
79+
description: "Error",
80+
},
81+
},
82+
},
7883
},
7984
},
8085
}
@@ -90,6 +95,7 @@ test("LroAzureAsyncOperationHeader should find errors with no Azure-AsyncOperati
9095
"/foo1/operations": {
9196
get: {
9297
operationId: "foo_get",
98+
"x-ms-long-running-operation": true,
9399
responses: {
94100
200: {
95101
description: "Success",
@@ -98,7 +104,7 @@ test("LroAzureAsyncOperationHeader should find errors with no Azure-AsyncOperati
98104
description: "Accepted",
99105
headers: {
100106
Location: {
101-
description: "The URL where the status of the asynchronous operation can be checked.",
107+
description: "No Azure-AsyncOperation header",
102108
type: "string",
103109
},
104110
},
@@ -110,13 +116,19 @@ test("LroAzureAsyncOperationHeader should find errors with no Azure-AsyncOperati
110116
},
111117
post: {
112118
operationId: "foo_post",
119+
"x-ms-long-running-operation": false,
113120
responses: {
114121
200: {
115122
description: "Success",
116123
},
117124
202: {
118-
description: "Accepted",
119-
headers: {},
125+
description: "Empty header case",
126+
headers: {
127+
Location: {
128+
description: "No Azure-AsyncOperation header",
129+
type: "string",
130+
},
131+
},
120132
},
121133
default: {
122134
description: "Error",
@@ -125,15 +137,16 @@ test("LroAzureAsyncOperationHeader should find errors with no Azure-AsyncOperati
125137
},
126138
put: {
127139
operationId: "foo_put",
140+
"x-ms-long-running-operation": true,
128141
responses: {
129142
200: {
130143
description: "Success",
131144
},
132145
202: {
133146
description: "Accepted",
134147
headers: {
135-
azureasyncOperation: {
136-
description: "The URL where the status of the asynchronous operation can be checked.",
148+
"azure-asyncOperation1": {
149+
description: "check the wrong wording",
137150
type: "string",
138151
},
139152
},
@@ -143,16 +156,31 @@ test("LroAzureAsyncOperationHeader should find errors with no Azure-AsyncOperati
143156
},
144157
},
145158
},
159+
delete: {
160+
operationId: "foo_put",
161+
"x-ms-long-running-operation": true,
162+
responses: {
163+
202: {
164+
description: "Accepted",
165+
headers: {
166+
"azure-asyncOperation": {
167+
description: "Check case sensitive scenario",
168+
type: "string",
169+
},
170+
},
171+
},
172+
},
173+
},
146174
},
147175
},
148176
}
149177
return linter.run(myOpenApiDocument).then((results) => {
150178
expect(results.length).toBe(3)
151-
expect(results[0].path.join(".")).toBe("paths./foo1/operations.get.responses.202.headers")
179+
expect(results[0].path.join(".")).toBe("paths./foo1/operations.get.responses.202.headers.Location")
152180
expect(results[0].message).toEqual(ERROR_MESSAGE)
153-
expect(results[1].path.join(".")).toBe("paths./foo1/operations.post.responses.202.headers")
181+
expect(results[1].path.join(".")).toBe("paths./foo1/operations.put.responses.202.headers.azure-asyncOperation1")
154182
expect(results[1].message).toEqual(ERROR_MESSAGE)
155-
expect(results[2].path.join(".")).toBe("paths./foo1/operations.put.responses.202.headers")
183+
expect(results[2].path.join(".")).toBe("paths./foo1/operations.delete.responses.202.headers.azure-asyncOperation")
156184
expect(results[2].message).toEqual(ERROR_MESSAGE)
157185
})
158186
})

0 commit comments

Comments
 (0)