OAS: Maintain required flag for request body (#752)

* sample data

* Maintain required flag

* accept some changes

* Make required field stable

* Fix an unneeded warning
This commit is contained in:
Andrey Pokhilko 2022-02-03 12:41:07 +03:00 committed by GitHub
parent 5934be4da6
commit 9cddb0c7e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 335 additions and 69 deletions

View File

@ -350,13 +350,17 @@ func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool) e
} }
handleNameVals(hdrGW, &opObj.Parameters) handleNameVals(hdrGW, &opObj.Parameters)
if req.PostData.Text != "" && isSuccess { if isSuccess {
reqBody, err := getRequestBody(req, opObj, isSuccess) reqBody, err := getRequestBody(req, opObj)
if err != nil { if err != nil {
return err return err
} }
if reqBody != nil { if reqBody != nil {
if req.PostData.Text == "" {
reqBody.Required = false
} else {
reqCtype, _ := getReqCtype(req) reqCtype, _ := getReqCtype(req)
reqMedia, err := fillContent(reqResp{Req: req}, reqBody.Content, reqCtype) reqMedia, err := fillContent(reqResp{Req: req}, reqBody.Content, reqCtype)
if err != nil { if err != nil {
@ -366,6 +370,7 @@ func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool) e
_ = reqMedia _ = reqMedia
} }
} }
}
return nil return nil
} }
@ -537,9 +542,11 @@ func handleFormData(content *openapi.MediaType, parts []PartWithBody) {
for name := range seenNames { for name := range seenNames {
content.Schema.Required = append(content.Schema.Required, name) content.Schema.Required = append(content.Schema.Required, name)
} }
sort.Strings(content.Schema.Required)
} // else it's a known schema with no required fields } // else it's a known schema with no required fields
} else { } else {
content.Schema.Required = intersectSliceWithMap(content.Schema.Required, seenNames) content.Schema.Required = intersectSliceWithMap(content.Schema.Required, seenNames)
sort.Strings(content.Schema.Required)
} }
} }
@ -603,6 +610,10 @@ func getReqCtype(req *har.Request) (ctype string, params map[string]string) {
} }
} }
if ctype == "" {
return "", map[string]string{}
}
mediaType, params, err := mime.ParseMediaType(ctype) mediaType, params, err := mime.ParseMediaType(ctype)
if err != nil { if err != nil {
logger.Log.Errorf("Cannot parse Content-Type header %q: %v", ctype, err) logger.Log.Errorf("Cannot parse Content-Type header %q: %v", ctype, err)
@ -638,9 +649,14 @@ func getResponseObj(resp *har.Response, opObj *openapi.Operation, isSuccess bool
return resResponse, nil return resResponse, nil
} }
func getRequestBody(req *har.Request, opObj *openapi.Operation, isSuccess bool) (*openapi.RequestBodyObj, error) { func getRequestBody(req *har.Request, opObj *openapi.Operation) (*openapi.RequestBodyObj, error) {
if opObj.RequestBody == nil { if opObj.RequestBody == nil {
// create if there is body in request
if req.PostData.Text != "" {
opObj.RequestBody = &openapi.RequestBodyObj{Description: "Generic request body", Required: true, Content: map[string]*openapi.MediaType{}} opObj.RequestBody = &openapi.RequestBodyObj{Description: "Generic request body", Required: true, Content: map[string]*openapi.MediaType{}}
} else {
return nil, nil
}
} }
reqBody, err := opObj.RequestBody.ResolveRequestBody(reqBodyResolver) reqBody, err := opObj.RequestBody.ResolveRequestBody(reqBodyResolver)
@ -648,9 +664,6 @@ func getRequestBody(req *har.Request, opObj *openapi.Operation, isSuccess bool)
return nil, err return nil, err
} }
// TODO: maintain required flag for it, but only consider successful responses
//reqBody.Content[]
return reqBody, nil return reqBody, nil
} }

View File

@ -370,6 +370,174 @@
"wait": -1, "wait": -1,
"receive": 1 "receive": 1
} }
},
{
"startedDateTime": "2019-09-06T06:16:21.757122+00:00",
"time": 1,
"request": {
"method": "POST",
"url": "https://httpbin.org/body-optional",
"httpVersion": "",
"cookies": [],
"headers": [
],
"queryString": [],
"headersSize": -1,
"bodySize": -1,
"postData": {
"mimeType": "",
"text": ""
}
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "",
"cookies": [],
"headers": [
],
"content": {
"size": 0,
"mimeType": "",
"text": ""
},
"redirectURL": "",
"headersSize": -1,
"bodySize": 0
},
"cache": {},
"timings": {
"send": -1,
"wait": -1,
"receive": 1
}
},
{
"startedDateTime": "2019-09-06T06:16:21.747122+00:00",
"time": 1,
"request": {
"method": "POST",
"url": "https://httpbin.org/body-optional",
"httpVersion": "",
"cookies": [],
"headers": [
{
"name": "Content-Type",
"value": "application/json"
}
],
"queryString": [],
"headersSize": -1,
"bodySize": -1,
"postData": {
"mimeType": "",
"text": "{\"key\", \"val\"}"
}
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "",
"cookies": [],
"headers": [
],
"content": {
"size": 0,
"mimeType": "",
"text": ""
},
"redirectURL": "",
"headersSize": -1,
"bodySize": 0
},
"cache": {},
"timings": {
"send": -1,
"wait": -1,
"receive": 1
}
},
{
"startedDateTime": "2019-09-06T06:16:21.757122+00:00",
"time": 1,
"request": {
"method": "POST",
"url": "https://httpbin.org/body-optional",
"httpVersion": "",
"cookies": [],
"headers": [
],
"queryString": [],
"headersSize": -1,
"bodySize": -1,
"postData": {
"mimeType": "",
"text": ""
}
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "",
"cookies": [],
"headers": [
],
"content": {
"size": 0,
"mimeType": "",
"text": ""
},
"redirectURL": "",
"headersSize": -1,
"bodySize": 0
},
"cache": {},
"timings": {
"send": -1,
"wait": -1,
"receive": 1
}
},
{
"startedDateTime": "2019-09-06T06:16:21.757122+00:00",
"time": 1,
"request": {
"method": "POST",
"url": "https://httpbin.org/body-required",
"httpVersion": "",
"cookies": [],
"headers": [
],
"queryString": [],
"headersSize": -1,
"bodySize": -1,
"postData": {
"mimeType": "",
"text": "body exists"
}
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "",
"cookies": [],
"headers": [
],
"content": {
"size": 0,
"mimeType": "",
"text": ""
},
"redirectURL": "",
"headersSize": -1,
"bodySize": 0
},
"cache": {},
"timings": {
"send": -1,
"wait": -1,
"receive": 1
}
} }
] ]
} }

View File

@ -2,7 +2,7 @@
"openapi": "3.1.0", "openapi": "3.1.0",
"info": { "info": {
"title": "https://httpbin.org", "title": "https://httpbin.org",
"description": "Mizu observed 9 entries (0 failed), at 0.222 hits/s, average response time is 0.363 seconds", "description": "Mizu observed 13 entries (0 failed), at 0.154 hits/s, average response time is 0.251 seconds",
"version": "1.0" "version": "1.0"
}, },
"servers": [ "servers": [
@ -15,7 +15,7 @@
"get": { "get": {
"summary": "/appears-once", "summary": "/appears-once",
"description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.630 seconds", "description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.630 seconds",
"operationId": "ebf78fe8-6ebe-40bb-ad88-eab0dce05e91", "operationId": "8dfc5a75-5f9b-4b57-ad88-77154a016201",
"responses": { "responses": {
"200": { "200": {
"description": "Successful call with status 200", "description": "Successful call with status 200",
@ -26,6 +26,16 @@
} }
} }
}, },
"x-counters-per-source": {
"": {
"entries": 1,
"failures": 0,
"firstSeen": 1567750580.0471218,
"lastSeen": 1567750580.0471218,
"sumRT": 0.63,
"sumDuration": 0
}
},
"x-last-seen-ts": 1567750580.0471218, "x-last-seen-ts": 1567750580.0471218,
"x-counters-total": { "x-counters-total": {
"entries": 1, "entries": 1,
@ -34,16 +44,6 @@
"lastSeen": 1567750580.0471218, "lastSeen": 1567750580.0471218,
"sumRT": 0.63, "sumRT": 0.63,
"sumDuration": 0 "sumDuration": 0
},
"x-counters-per-source": {
"": {
"entries": 1,
"failures": 0,
"firstSeen": 1567750580.0471218,
"lastSeen": 1567750580.0471218,
"sumRT": 0.63,
"sumDuration": 0
}
} }
} }
}, },
@ -51,7 +51,7 @@
"get": { "get": {
"summary": "/appears-twice", "summary": "/appears-twice",
"description": "Mizu observed 2 entries (0 failed), at 0.500 hits/s, average response time is 0.630 seconds", "description": "Mizu observed 2 entries (0 failed), at 0.500 hits/s, average response time is 0.630 seconds",
"operationId": "67e6640a-8cb2-4e31-ae4d-b066b397ee93", "operationId": "844ae464-fcee-4bd7-97cf-aaa096196c02",
"responses": { "responses": {
"200": { "200": {
"description": "Successful call with status 200", "description": "Successful call with status 200",
@ -62,15 +62,6 @@
} }
} }
}, },
"x-last-seen-ts": 1567750581.7471218,
"x-counters-total": {
"entries": 2,
"failures": 0,
"firstSeen": 1567750580.7471218,
"lastSeen": 1567750581.7471218,
"sumRT": 1.26,
"sumDuration": 1
},
"x-counters-per-source": { "x-counters-per-source": {
"": { "": {
"entries": 2, "entries": 2,
@ -80,6 +71,100 @@
"sumRT": 1.26, "sumRT": 1.26,
"sumDuration": 1 "sumDuration": 1
} }
},
"x-last-seen-ts": 1567750581.7471218,
"x-counters-total": {
"entries": 2,
"failures": 0,
"firstSeen": 1567750580.7471218,
"lastSeen": 1567750581.7471218,
"sumRT": 1.26,
"sumDuration": 1
}
}
},
"/body-optional": {
"post": {
"summary": "/body-optional",
"description": "Mizu observed 3 entries (0 failed), at 0.000 hits/s, average response time is 0.001 seconds",
"operationId": "6e78e253-1f15-4ecd-9147-ba407c6fbeac",
"responses": {
"200": {
"description": "Successful call with status 200",
"content": {
"": {}
}
}
},
"x-last-seen-ts": 1567750581.757122,
"x-counters-total": {
"entries": 3,
"failures": 0,
"firstSeen": 1567750581.7471218,
"lastSeen": 1567750581.757122,
"sumRT": 0.003,
"sumDuration": 0
},
"x-counters-per-source": {
"": {
"entries": 3,
"failures": 0,
"firstSeen": 1567750581.7471218,
"lastSeen": 1567750581.757122,
"sumRT": 0.003,
"sumDuration": 0
}
},
"requestBody": {
"description": "Generic request body",
"content": {
"application/json": {
"example": "{\"key\", \"val\"}"
}
}
}
}
},
"/body-required": {
"post": {
"summary": "/body-required",
"description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.001 seconds",
"operationId": "1eefebc8-28c0-43d8-877f-4c5f67ff479d",
"responses": {
"200": {
"description": "Successful call with status 200",
"content": {
"": {}
}
}
},
"x-last-seen-ts": 1567750581.757122,
"x-counters-total": {
"entries": 1,
"failures": 0,
"firstSeen": 1567750581.757122,
"lastSeen": 1567750581.757122,
"sumRT": 0.001,
"sumDuration": 0
},
"x-counters-per-source": {
"": {
"entries": 1,
"failures": 0,
"firstSeen": 1567750581.757122,
"lastSeen": 1567750581.757122,
"sumRT": 0.001,
"sumDuration": 0
}
},
"requestBody": {
"description": "Generic request body",
"content": {
"": {
"example": "body exists"
}
},
"required": true
} }
} }
}, },
@ -87,7 +172,7 @@
"post": { "post": {
"summary": "/form-multipart", "summary": "/form-multipart",
"description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.001 seconds", "description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.001 seconds",
"operationId": "a8e0380e-3ade-4150-af6b-9edb7f24d9dc", "operationId": "fc1eb6a3-3d55-4b4a-bfd0-c2ae85d590d5",
"responses": { "responses": {
"200": { "200": {
"description": "Successful call with status 200", "description": "Successful call with status 200",
@ -98,14 +183,6 @@
} }
} }
}, },
"x-counters-total": {
"entries": 1,
"failures": 0,
"firstSeen": 1567750582.7471218,
"lastSeen": 1567750582.7471218,
"sumRT": 0.001,
"sumDuration": 0
},
"x-counters-per-source": { "x-counters-per-source": {
"": { "": {
"entries": 1, "entries": 1,
@ -117,6 +194,14 @@
} }
}, },
"x-last-seen-ts": 1567750582.7471218, "x-last-seen-ts": 1567750582.7471218,
"x-counters-total": {
"entries": 1,
"failures": 0,
"firstSeen": 1567750582.7471218,
"lastSeen": 1567750582.7471218,
"sumRT": 0.001,
"sumDuration": 0
},
"requestBody": { "requestBody": {
"description": "Generic request body", "description": "Generic request body",
"content": { "content": {
@ -154,7 +239,7 @@
"post": { "post": {
"summary": "/form-urlencoded", "summary": "/form-urlencoded",
"description": "Mizu observed 2 entries (0 failed), at 0.500 hits/s, average response time is 0.001 seconds", "description": "Mizu observed 2 entries (0 failed), at 0.500 hits/s, average response time is 0.001 seconds",
"operationId": "dd251f61-2636-4c38-ad9d-d4b654464eba", "operationId": "b416c98b-4ba8-4739-bd2a-6c3e31478bc9",
"responses": { "responses": {
"200": { "200": {
"description": "Successful call with status 200", "description": "Successful call with status 200",
@ -163,7 +248,6 @@
} }
} }
}, },
"x-last-seen-ts": 1567750581.7471218,
"x-counters-total": { "x-counters-total": {
"entries": 2, "entries": 2,
"failures": 0, "failures": 0,
@ -182,6 +266,7 @@
"sumDuration": 1 "sumDuration": 1
} }
}, },
"x-last-seen-ts": 1567750581.7471218,
"requestBody": { "requestBody": {
"description": "Generic request body", "description": "Generic request body",
"content": { "content": {
@ -232,7 +317,7 @@
"get": { "get": {
"summary": "/{Id}", "summary": "/{Id}",
"description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.630 seconds", "description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.630 seconds",
"operationId": "095b3932-c824-4054-a6da-bc872f279743", "operationId": "d8b4de17-4c0e-401c-891b-36a7cee390bf",
"responses": { "responses": {
"200": { "200": {
"description": "Successful call with status 200", "description": "Successful call with status 200",
@ -287,7 +372,7 @@
"get": { "get": {
"summary": "/{Id}/sub1", "summary": "/{Id}/sub1",
"description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.111 seconds", "description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.111 seconds",
"operationId": "6f168b6d-9b67-490e-9895-903b078de4c5", "operationId": "edacc275-1761-4011-af9b-3a3ed7c3d2b8",
"responses": { "responses": {
"200": { "200": {
"description": "Successful call with status 200", "description": "Successful call with status 200",
@ -296,7 +381,6 @@
} }
} }
}, },
"x-last-seen-ts": 1567750483.864529,
"x-counters-total": { "x-counters-total": {
"entries": 1, "entries": 1,
"failures": 0, "failures": 0,
@ -314,7 +398,8 @@
"sumRT": 0.111, "sumRT": 0.111,
"sumDuration": 0 "sumDuration": 0
} }
} },
"x-last-seen-ts": 1567750483.864529
}, },
"parameters": [ "parameters": [
{ {
@ -340,7 +425,7 @@
"get": { "get": {
"summary": "/{Id}/sub2", "summary": "/{Id}/sub2",
"description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.630 seconds", "description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.630 seconds",
"operationId": "d1e7900f-01dc-4d79-912e-5ca79ecd73e3", "operationId": "61702da5-e4e7-4d95-8071-a6208f3d19d4",
"responses": { "responses": {
"200": { "200": {
"description": "Successful call with status 200", "description": "Successful call with status 200",
@ -351,6 +436,15 @@
} }
} }
}, },
"x-last-seen-ts": 1567750578.7471218,
"x-counters-total": {
"entries": 1,
"failures": 0,
"firstSeen": 1567750578.7471218,
"lastSeen": 1567750578.7471218,
"sumRT": 0.63,
"sumDuration": 0
},
"x-counters-per-source": { "x-counters-per-source": {
"": { "": {
"entries": 1, "entries": 1,
@ -360,15 +454,6 @@
"sumRT": 0.63, "sumRT": 0.63,
"sumDuration": 0 "sumDuration": 0
} }
},
"x-last-seen-ts": 1567750578.7471218,
"x-counters-total": {
"entries": 1,
"failures": 0,
"firstSeen": 1567750578.7471218,
"lastSeen": 1567750578.7471218,
"sumRT": 0.63,
"sumDuration": 0
} }
}, },
"parameters": [ "parameters": [
@ -392,22 +477,22 @@
] ]
} }
}, },
"x-counters-total": {
"entries": 9,
"failures": 0,
"firstSeen": 1567750483.864529,
"lastSeen": 1567750582.7471218,
"sumRT": 3.2639999999999993,
"sumDuration": 2
},
"x-counters-per-source": { "x-counters-per-source": {
"": { "": {
"entries": 9, "entries": 13,
"failures": 0, "failures": 0,
"firstSeen": 1567750483.864529, "firstSeen": 1567750483.864529,
"lastSeen": 1567750582.7471218, "lastSeen": 1567750582.7471218,
"sumRT": 3.2639999999999993, "sumRT": 3.268,
"sumDuration": 2
}
},
"x-counters-total": {
"entries": 13,
"failures": 0,
"firstSeen": 1567750483.864529,
"lastSeen": 1567750582.7471218,
"sumRT": 3.268,
"sumDuration": 2 "sumDuration": 2
} }
} }
}