Skip to content

Commit f65122c

Browse files
Fix: use nullable to allow empty path param (#271)
* fix: check for nullable parameter and allow empty string * tests: add tests for nullable parameters * style: remove line breaks * fix: account for parameter overriding at operation level * fix: depend on minLength instead
1 parent b731888 commit f65122c

File tree

3 files changed

+151
-0
lines changed

3 files changed

+151
-0
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"_format_version": "3.0",
3+
"services": [
4+
{
5+
"host": "backend.com",
6+
"id": "aac33fce-7ade-5b69-9249-97bea965698e",
7+
"name": "odata-style-api-with-nullable-path-params",
8+
"path": "/path",
9+
"plugins": [],
10+
"port": 80,
11+
"protocol": "http",
12+
"routes": [
13+
{
14+
"id": "649b2718-47a3-57ec-aec0-b8a4f1bf010d",
15+
"methods": [
16+
"GET"
17+
],
18+
"name": "odata-style-api-with-nullable-path-params_customproductdata",
19+
"paths": [
20+
"~/CustomWarehouseData\\(Warehouse='(?\u003cwarehouse\u003e[^#?/]*)',Product='(?\u003cproduct\u003e[^#?/]+)',Location='(?\u003clocation\u003e[^#?/]*)'\\)$"
21+
],
22+
"plugins": [],
23+
"regex_priority": 100,
24+
"strip_path": false,
25+
"tags": [
26+
"OAS3_import",
27+
"OAS3file_21-nullable-path-param.yaml"
28+
]
29+
},
30+
{
31+
"id": "dd39d9e0-196d-509d-b141-13e77ce94f81",
32+
"methods": [
33+
"GET"
34+
],
35+
"name": "odata-style-api-with-nullable-path-params_customdata",
36+
"paths": [
37+
"~/custom/(?\u003ccustomid\u003e[^#?/]+)$"
38+
],
39+
"plugins": [],
40+
"regex_priority": 100,
41+
"strip_path": false,
42+
"tags": [
43+
"OAS3_import",
44+
"OAS3file_21-nullable-path-param.yaml"
45+
]
46+
}
47+
],
48+
"tags": [
49+
"OAS3_import",
50+
"OAS3file_21-nullable-path-param.yaml"
51+
]
52+
}
53+
],
54+
"upstreams": []
55+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
openapi: 3.0.0
2+
info:
3+
title: OData style API with nullable path params
4+
version: 0.0.1
5+
servers:
6+
- url: http://backend.com/path
7+
paths:
8+
/custom/{customId}:
9+
parameters:
10+
- name: customId
11+
in: path
12+
required: true
13+
description: Custom ID
14+
schema:
15+
type: string
16+
maxLength: 4
17+
get:
18+
summary: Read the custom information
19+
description: Read the custom information of the API
20+
tags:
21+
- Metadata
22+
responses:
23+
"200":
24+
description: Retrieved metadata
25+
4XX:
26+
description: all 4XX errors
27+
operationId: customdata
28+
? "/CustomWarehouseData(Warehouse='{Warehouse}',Product='{Product}',Location='{Location}')"
29+
: parameters:
30+
- name: Warehouse
31+
in: path
32+
required: true
33+
description: ID of warehouse
34+
schema:
35+
type: string
36+
maxLength: 4
37+
minLength: 0
38+
- name: Product
39+
in: path
40+
required: true
41+
description: Product Number
42+
schema:
43+
type: string
44+
maxLength: 40
45+
- name: Location
46+
in: path
47+
required: true
48+
description: Product Number
49+
schema:
50+
type: string
51+
maxLength: 40
52+
get:
53+
summary: List entities from Warehouse based on product ID, location and warehouse ID
54+
parameters:
55+
- name: Location #overrides the param defined in path level
56+
in: path
57+
required: true
58+
description: Product Number
59+
schema:
60+
type: string
61+
maxLength: 40
62+
minLength: 0
63+
tags:
64+
- WarehouseProductData
65+
responses:
66+
"200":
67+
description: Retrieved product entities
68+
4XX:
69+
description: all 4XX errors
70+
operationId: customproductdata

openapi2kong/openapi2kong.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,27 @@ func getForeignKeyPlugins(
521521
return &genericPlugins, &newPluginList
522522
}
523523

524+
// findParameterSchema returns the Schema for given parameter name.
525+
// Path level parameters can be overridden at operation level, so we check operation parameters first
526+
// and then fall back to path.
527+
func findParameterSchema(
528+
operationParameters []*v3.Parameter,
529+
pathParameters []*v3.Parameter,
530+
paramName string,
531+
) *openapibase.Schema {
532+
for _, param := range operationParameters {
533+
if param.Name == paramName {
534+
return param.Schema.Schema()
535+
}
536+
}
537+
for _, param := range pathParameters {
538+
if param.Name == paramName {
539+
return param.Schema.Schema()
540+
}
541+
}
542+
return nil
543+
}
544+
524545
// MustConvert is the same as Convert, but will panic if an error is returned.
525546
func MustConvert(content []byte, opts O2kOptions) map[string]interface{} {
526547
result, err := Convert(content, opts)
@@ -1085,6 +1106,11 @@ func Convert(content []byte, opts O2kOptions) (map[string]interface{}, error) {
10851106
varName, captureName)
10861107
}
10871108
regexMatch := "(?<" + captureName + ">[^#?/]+)"
1109+
paramSchema := findParameterSchema(operation.Parameters, pathitem.Parameters, varName)
1110+
// Check if the parameter has a minLength defined, if 0, allow empty string
1111+
if paramSchema != nil && paramSchema.MinLength != nil && *paramSchema.MinLength == 0 {
1112+
regexMatch = "(?<" + captureName + ">[^#?/]*)"
1113+
}
10881114
placeHolder := "{" + varName + "}"
10891115
logbasics.Debug("replacing path parameter", "parameter", placeHolder, "regex", regexMatch)
10901116
convertedPath = strings.Replace(convertedPath, placeHolder, regexMatch, 1)

0 commit comments

Comments
 (0)