Skip to content

Commit 86f96dd

Browse files
dbantykgutwin
andauthored
Support multiple bodies (#900)
It's possible for an endpoint to allow multiple content-types. In this case, the caller should select one at runtime, rather than one being picked arbitrarily. This is a breaking change because instead of separate named params per type of body, there is only one body parameter (to better reflect that a choice is required). Closes #822 --------- Co-authored-by: Karl Gutwin <[email protected]> Co-authored-by: Dylan Anthony <[email protected]>
1 parent 3253448 commit 86f96dd

File tree

69 files changed

+1534
-905
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1534
-905
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
default: patch
3+
---
4+
5+
# Always use correct content type for requests
6+
7+
In previous versions, a request body that was similar to a known content type would use that content type in the request. For example `application/json` would be used for `application/vnd.api+json`. This was incorrect and could result in invalid requests being sent.
8+
9+
Now, the content type defined in the OpenAPI document will always be used.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
default: major
3+
---
4+
5+
# Renamed body types and parameters
6+
7+
PR #900 addresses #822.
8+
9+
Where previously there would be one body parameter per supported content type, now there is a single `body` parameter which takes a union of all the possible inputs. This correctly models the fact that only one body can be sent (and ever would be sent) in a request.
10+
11+
For example, when calling a generated endpoint, code which used to look like this:
12+
13+
```python
14+
post_body_multipart.sync_detailed(
15+
client=client,
16+
multipart_data=PostBodyMultipartMultipartData(),
17+
)
18+
```
19+
20+
Will now look like this:
21+
22+
```python
23+
post_body_multipart.sync_detailed(
24+
client=client,
25+
body=PostBodyMultipartBody(),
26+
)
27+
```
28+
29+
Note that both the input parameter name _and_ the class name have changed. This should result in simpler code when there is only a single body type and now produces correct code when there are multiple body types.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
default: minor
3+
---
4+
5+
# Support multiple possible `requestBody`
6+
7+
PR #900 addresses #822.
8+
9+
It is now possible in some circumstances to generate valid code for OpenAPI documents which have multiple possible `requestBody` values. Previously, invalid code could have been generated with no warning (only one body could actually be sent).
10+
11+
Only one content type per "category" is currently supported at a time. The categories are:
12+
13+
- JSON, like `application/json`
14+
- Binary data, like `application/octet-stream`
15+
- Encoded form data, like `application/x-www-form-urlencoded`
16+
- Files, like `multipart/form-data`

end_to_end_tests/baseline_openapi_3.0.json

+148-32
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,85 @@
66
"version": "0.1.0"
77
},
88
"paths": {
9+
"/bodies/multiple": {
10+
"post": {
11+
"description": "Test multiple bodies",
12+
"tags": [
13+
"bodies"
14+
],
15+
"requestBody": {
16+
"content": {
17+
"application/json": {
18+
"schema": {
19+
"type": "object",
20+
"properties": {
21+
"a": {
22+
"type": "string"
23+
}
24+
}
25+
}
26+
},
27+
"application/octet-stream": {
28+
"schema": {
29+
"type": "string",
30+
"format": "binary"
31+
}
32+
},
33+
"application/x-www-form-urlencoded": {
34+
"schema": {
35+
"type": "object",
36+
"properties": {
37+
"a": {
38+
"type": "string"
39+
}
40+
}
41+
}
42+
},
43+
"multipart/form-data": {
44+
"schema": {
45+
"type": "object",
46+
"properties": {
47+
"a": {
48+
"type": "string"
49+
}
50+
}
51+
}
52+
}
53+
}
54+
},
55+
"responses": {
56+
"200": {
57+
"description": "OK"
58+
}
59+
}
60+
}
61+
},
62+
"/bodies/json-like": {
63+
"post": {
64+
"tags": ["bodies"],
65+
"description": "A content type that works like json but isn't application/json",
66+
"operationId": "json-like",
67+
"requestBody": {
68+
"content": {
69+
"application/vnd+json": {
70+
"schema": {
71+
"type": "object",
72+
"properties": {
73+
"a": {
74+
"type": "string"
75+
}
76+
}
77+
}
78+
}
79+
}
80+
},
81+
"responses": {
82+
"200": {
83+
"description": "OK"
84+
}
85+
}
86+
}
87+
},
988
"/tests/": {
1089
"get": {
1190
"tags": [
@@ -806,7 +885,9 @@
806885
},
807886
"/responses/unions/simple_before_complex": {
808887
"post": {
809-
"tags": ["responses"],
888+
"tags": [
889+
"responses"
890+
],
810891
"description": "Regression test for #603",
811892
"responses": {
812893
"200": {
@@ -815,12 +896,18 @@
815896
"application/json": {
816897
"schema": {
817898
"type": "object",
818-
"required": ["a"],
899+
"required": [
900+
"a"
901+
],
819902
"properties": {
820903
"a": {
821904
"oneOf": [
822-
{"type": "string"},
823-
{"type": "object"}
905+
{
906+
"type": "string"
907+
},
908+
{
909+
"type": "object"
910+
}
824911
]
825912
}
826913
}
@@ -948,20 +1035,20 @@
9481035
},
9491036
"parameters": [
9501037
{
951-
"name": "param",
952-
"in": "query",
953-
"schema": {
954-
"type": "string"
955-
}
956-
},
957-
{
958-
"name": "param",
959-
"in": "path",
960-
"required": true,
961-
"schema": {
962-
"type": "string"
963-
}
1038+
"name": "param",
1039+
"in": "query",
1040+
"schema": {
1041+
"type": "string"
1042+
}
1043+
},
1044+
{
1045+
"name": "param",
1046+
"in": "path",
1047+
"required": true,
1048+
"schema": {
1049+
"type": "string"
9641050
}
1051+
}
9651052
]
9661053
},
9671054
"/same-name-multiple-locations/{param}": {
@@ -1010,7 +1097,9 @@
10101097
},
10111098
"/tag_with_number": {
10121099
"get": {
1013-
"tags": ["1"],
1100+
"tags": [
1101+
"1"
1102+
],
10141103
"responses": {
10151104
"200": {
10161105
"description": "Success"
@@ -1253,7 +1342,9 @@
12531342
"/naming/property-conflict-with-import": {
12541343
"description": "Ensure that property names don't conflict with imports",
12551344
"post": {
1256-
"tags": ["naming"],
1345+
"tags": [
1346+
"naming"
1347+
],
12571348
"requestBody": {
12581349
"content": {
12591350
"application/json": {
@@ -1310,9 +1401,15 @@
13101401
{
13111402
"$ref": "#/components/parameters/integer-param"
13121403
},
1313-
{"$ref": "#/components/parameters/header-param"},
1314-
{"$ref": "#/components/parameters/cookie-param"},
1315-
{"$ref": "#/components/parameters/path-param"}
1404+
{
1405+
"$ref": "#/components/parameters/header-param"
1406+
},
1407+
{
1408+
"$ref": "#/components/parameters/cookie-param"
1409+
},
1410+
{
1411+
"$ref": "#/components/parameters/path-param"
1412+
}
13161413
],
13171414
"responses": {
13181415
"200": {
@@ -1643,7 +1740,11 @@
16431740
},
16441741
"Body_upload_file_tests_upload_post": {
16451742
"title": "Body_upload_file_tests_upload_post",
1646-
"required": ["some_file", "some_object", "some_nullable_object"],
1743+
"required": [
1744+
"some_file",
1745+
"some_object",
1746+
"some_nullable_object"
1747+
],
16471748
"type": "object",
16481749
"properties": {
16491750
"some_file": {
@@ -1685,7 +1786,10 @@
16851786
"some_object": {
16861787
"title": "Some Object",
16871788
"type": "object",
1688-
"required": ["num", "text"],
1789+
"required": [
1790+
"num",
1791+
"text"
1792+
],
16891793
"properties": {
16901794
"num": {
16911795
"type": "number"
@@ -1698,7 +1802,9 @@
16981802
"some_optional_object": {
16991803
"title": "Some Optional Object",
17001804
"type": "object",
1701-
"required": ["foo"],
1805+
"required": [
1806+
"foo"
1807+
],
17021808
"properties": {
17031809
"foo": {
17041810
"type": "string"
@@ -1921,7 +2027,10 @@
19212027
},
19222028
"type_enum": {
19232029
"type": "integer",
1924-
"enum": [0, 1]
2030+
"enum": [
2031+
0,
2032+
1
2033+
]
19252034
}
19262035
}
19272036
},
@@ -1934,11 +2043,15 @@
19342043
},
19352044
"type": {
19362045
"type": "string",
1937-
"enum": ["submodel"]
2046+
"enum": [
2047+
"submodel"
2048+
]
19382049
},
19392050
"type_enum": {
19402051
"type": "integer",
1941-
"enum": [0]
2052+
"enum": [
2053+
0
2054+
]
19422055
}
19432056
}
19442057
},
@@ -1953,7 +2066,10 @@
19532066
},
19542067
"type_enum": {
19552068
"type": "integer",
1956-
"enum": [0, 1]
2069+
"enum": [
2070+
0,
2071+
1
2072+
]
19572073
}
19582074
}
19592075
},
@@ -2096,7 +2212,7 @@
20962212
}
20972213
}
20982214
},
2099-
"ModelWithDateTimeProperty" : {
2215+
"ModelWithDateTimeProperty": {
21002216
"type": "object",
21012217
"properties": {
21022218
"datetime": {
@@ -2274,10 +2390,10 @@
22742390
"type": "string",
22752391
"format": "byte"
22762392
},
2277-
"import": {
2393+
"import": {
22782394
"type": "object"
22792395
},
2280-
"None": {
2396+
"None": {
22812397
"type": "object"
22822398
},
22832399
"model.reference.with.Periods": {

0 commit comments

Comments
 (0)