diff --git a/openapi2kong/oas3_testfiles/01-names-inferred.expected.json b/openapi2kong/oas3_testfiles/01-names-inferred.expected.json index 0b3de0a..e25a99c 100644 --- a/openapi2kong/oas3_testfiles/01-names-inferred.expected.json +++ b/openapi2kong/oas3_testfiles/01-names-inferred.expected.json @@ -96,11 +96,11 @@ ] }, { - "id": "47527799-6eee-56a4-9f70-fd4e0b1a5867", + "id": "0879ed2e-2aa4-57ce-8359-733a266f3ab9", "methods": [ "POST" ], - "name": "Simple_API_overview-application~-post", + "name": "Simple_API_overview-application-~-post", "paths": [ "~/application/$" ], diff --git a/openapi2kong/oas3_testfiles/01-names-inferred.expected_noid.json b/openapi2kong/oas3_testfiles/01-names-inferred.expected_noid.json index 0e7abcb..28943fe 100644 --- a/openapi2kong/oas3_testfiles/01-names-inferred.expected_noid.json +++ b/openapi2kong/oas3_testfiles/01-names-inferred.expected_noid.json @@ -93,7 +93,7 @@ "methods": [ "POST" ], - "name": "Simple_API_overview-application~-post", + "name": "Simple_API_overview-application-~-post", "paths": [ "~/application/$" ], diff --git a/openapi2kong/oas3_testfiles/02-names-set.expected.json b/openapi2kong/oas3_testfiles/02-names-set.expected.json index 52080f6..d15b339 100644 --- a/openapi2kong/oas3_testfiles/02-names-set.expected.json +++ b/openapi2kong/oas3_testfiles/02-names-set.expected.json @@ -45,11 +45,11 @@ ] }, { - "id": "6c573ebb-44d2-5e36-be1a-6aa5e6fc8868", + "id": "de13eea4-754a-5219-9dad-ee16f9632d63", "methods": [ "PUT" ], - "name": "oas-spec-name-path-name-my-put-operation", + "name": "oas-spec-name-my-put-operation", "paths": [ "~/app1$" ], @@ -96,11 +96,11 @@ ] }, { - "id": "b9b808a1-29e6-596e-8980-f5218aee5440", + "id": "de13eea4-754a-5219-9dad-ee16f9632d63", "methods": [ "PUT" ], - "name": "oas-spec-name-app2-my-put-operation", + "name": "oas-spec-name-my-put-operation", "paths": [ "~/app2$" ], diff --git a/openapi2kong/oas3_testfiles/02-names-set.expected_noid.json b/openapi2kong/oas3_testfiles/02-names-set.expected_noid.json index 34410d3..a9cee61 100644 --- a/openapi2kong/oas3_testfiles/02-names-set.expected_noid.json +++ b/openapi2kong/oas3_testfiles/02-names-set.expected_noid.json @@ -45,7 +45,7 @@ "methods": [ "PUT" ], - "name": "oas-spec-name-path-name-my-put-operation", + "name": "oas-spec-name-my-put-operation", "paths": [ "~/app1$" ], @@ -93,7 +93,7 @@ "methods": [ "PUT" ], - "name": "oas-spec-name-app2-my-put-operation", + "name": "oas-spec-name-my-put-operation", "paths": [ "~/app2$" ], diff --git a/openapi2kong/oas3_testfiles/02a-names-inso-compat.expected.json b/openapi2kong/oas3_testfiles/02a-names-inso-compat.expected.json new file mode 100644 index 0000000..924c402 --- /dev/null +++ b/openapi2kong/oas3_testfiles/02a-names-inso-compat.expected.json @@ -0,0 +1,208 @@ +{ + "_format_version": "3.0", + "services": [ + { + "host": "somewhere", + "id": "30e5c201-0b51-5880-a95d-014814c44d57", + "name": "documentname", + "path": "/", + "plugins": [], + "port": 80, + "protocol": "http", + "routes": [ + { + "id": "0b8e9904-c8d8-504e-902c-773f7a39a466", + "methods": [ + "PUT" + ], + "name": "documentname-put", + "paths": [ + "~/$" + ], + "plugins": [], + "regex_priority": 200, + "strip_path": false, + "tags": [ + "OAS3_import", + "OAS3file_02a-names-inso-compat.yaml" + ] + }, + { + "id": "fe2a90f4-707a-555c-a7d4-209102271d67", + "methods": [ + "GET" + ], + "name": "documentname-Ops2", + "paths": [ + "~/named/path$" + ], + "plugins": [], + "regex_priority": 200, + "strip_path": false, + "tags": [ + "OAS3_import", + "OAS3file_02a-names-inso-compat.yaml" + ] + }, + { + "id": "afe41500-ce49-5eba-96d4-8eae0488da45", + "methods": [ + "POST" + ], + "name": "documentname-x-kong-ops", + "paths": [ + "~/named/path$" + ], + "plugins": [], + "regex_priority": 200, + "strip_path": false, + "tags": [ + "OAS3_import", + "OAS3file_02a-names-inso-compat.yaml" + ] + }, + { + "id": "182d482c-e725-58b3-8f99-02d2e156d4cd", + "methods": [ + "PUT" + ], + "name": "documentname-x-kong-path-put", + "paths": [ + "~/named/path$" + ], + "plugins": [], + "regex_priority": 200, + "strip_path": false, + "tags": [ + "OAS3_import", + "OAS3file_02a-names-inso-compat.yaml" + ] + }, + { + "id": "2fc8f8e6-c18c-5426-844d-03c19c1b2821", + "methods": [ + "GET" + ], + "name": "documentname-Ops1", + "paths": [ + "~/plain/path$" + ], + "plugins": [], + "regex_priority": 200, + "strip_path": false, + "tags": [ + "OAS3_import", + "OAS3file_02a-names-inso-compat.yaml" + ] + }, + { + "id": "afe41500-ce49-5eba-96d4-8eae0488da45", + "methods": [ + "POST" + ], + "name": "documentname-x-kong-ops", + "paths": [ + "~/plain/path$" + ], + "plugins": [], + "regex_priority": 200, + "strip_path": false, + "tags": [ + "OAS3_import", + "OAS3file_02a-names-inso-compat.yaml" + ] + }, + { + "id": "3672d50d-732d-5088-901d-0398f438f1b9", + "methods": [ + "PUT" + ], + "name": "documentname-plain-path-put", + "paths": [ + "~/plain/path$" + ], + "plugins": [], + "regex_priority": 200, + "strip_path": false, + "tags": [ + "OAS3_import", + "OAS3file_02a-names-inso-compat.yaml" + ] + }, + { + "id": "a7c25823-da0f-569d-8c6d-a6a1237d81bc", + "methods": [ + "GET" + ], + "name": "documentname-Ops3", + "paths": [ + "~/regex/path/(?[^#?/]+)$" + ], + "plugins": [], + "regex_priority": 100, + "strip_path": false, + "tags": [ + "OAS3_import", + "OAS3file_02a-names-inso-compat.yaml" + ] + }, + { + "id": "afe41500-ce49-5eba-96d4-8eae0488da45", + "methods": [ + "POST" + ], + "name": "documentname-x-kong-ops", + "paths": [ + "~/regex/path/(?[^#?/]+)$" + ], + "plugins": [], + "regex_priority": 100, + "strip_path": false, + "tags": [ + "OAS3_import", + "OAS3file_02a-names-inso-compat.yaml" + ] + }, + { + "id": "6a9f90dd-78ef-5fab-928b-06a2ebf0d8b4", + "methods": [ + "PUT" + ], + "name": "documentname-regex-path-userid-put", + "paths": [ + "~/regex/path/(?[^#?/]+)$" + ], + "plugins": [], + "regex_priority": 100, + "strip_path": false, + "tags": [ + "OAS3_import", + "OAS3file_02a-names-inso-compat.yaml" + ] + }, + { + "id": "8648ed96-027e-5d7f-b7d2-22d7709d1f93", + "methods": [ + "PUT" + ], + "name": "documentname-weird-p-a_th-put", + "paths": [ + "~/weird/p-a_th$" + ], + "plugins": [], + "regex_priority": 200, + "strip_path": false, + "tags": [ + "OAS3_import", + "OAS3file_02a-names-inso-compat.yaml" + ] + } + ], + "tags": [ + "OAS3_import", + "OAS3file_02a-names-inso-compat.yaml" + ] + } + ], + "upstreams": [] +} \ No newline at end of file diff --git a/openapi2kong/oas3_testfiles/02a-names-inso-compat.yaml b/openapi2kong/oas3_testfiles/02a-names-inso-compat.yaml new file mode 100644 index 0000000..1ee4dc9 --- /dev/null +++ b/openapi2kong/oas3_testfiles/02a-names-inso-compat.yaml @@ -0,0 +1,103 @@ +# top-name +# - path +# - x-kong-name set +# - no x-kong-name (defaults to path) +# - no x-kong-name + regex (defaults to path) +# - Operation +# - operationId set +# - x-kong-name set +# - neither set (defaults to method) + + +openapi: 3.0.0 + +info: + description: Learn service + version: 1.0.0 + title: Learn Service + contact: {} + +servers: +- url: http://somewhere + +x-kong-name: documentname + +paths: + /: + put: + responses: + '200': + description: description + + /weird/p-a_th: + put: + responses: + '200': + description: description + + /plain/path: + get: + operationId: Ops1 + responses: + '200': + description: description + put: + responses: + '200': + description: description + post: + x-kong-name: "x-kong-ops" + responses: + '200': + description: description + + /named/path: + x-kong-name: "x-kong-path" + get: + operationId: Ops2 + responses: + '200': + description: description + put: + responses: + '200': + description: description + post: + x-kong-name: "x-kong-ops" + responses: + '200': + description: description + + /regex/path/{userid}: + get: + operationId: Ops3 + parameters: + - name: userid + in: path + description: Id of the Track to delete + required: true + schema: {} + responses: + '200': + description: description + put: + parameters: + - name: userid + in: path + description: Id of the Track to delete + required: true + schema: {} + responses: + '200': + description: description + post: + x-kong-name: "x-kong-ops" + parameters: + - name: userid + in: path + description: Id of the Track to delete + required: true + schema: {} + responses: + '200': + description: description diff --git a/openapi2kong/oas3_testfiles/12-path-parameter-regex.expected.json b/openapi2kong/oas3_testfiles/12-path-parameter-regex.expected.json index db53744..1f60977 100644 --- a/openapi2kong/oas3_testfiles/12-path-parameter-regex.expected.json +++ b/openapi2kong/oas3_testfiles/12-path-parameter-regex.expected.json @@ -86,4 +86,4 @@ } ], "upstreams": [] -} +} \ No newline at end of file diff --git a/openapi2kong/oas3_testfiles/13-request-validator-plugin.expected.json b/openapi2kong/oas3_testfiles/13-request-validator-plugin.expected.json index 25e44f3..990ada2 100644 --- a/openapi2kong/oas3_testfiles/13-request-validator-plugin.expected.json +++ b/openapi2kong/oas3_testfiles/13-request-validator-plugin.expected.json @@ -78,11 +78,11 @@ ] }, { - "id": "26d60104-349e-5fa3-af66-5d08ff5c4fbe", + "id": "5dc78738-8b9d-5035-85b8-db5c3e9375e7", "methods": [ "GET" ], - "name": "Example-params__path-id-get", + "name": "Example-params-path-id-get", "paths": [ "~/params/(?[^#?/]+)$" ], @@ -127,7 +127,7 @@ "version": "draft4" }, "enabled": true, - "id": "c5bbae2e-9948-5a51-93b2-9051187cb543", + "id": "c0aefbd1-4a52-503a-aa5c-5e14a4e6a184", "name": "request-validator", "tags": [ "OAS3_import", @@ -150,4 +150,4 @@ } ], "upstreams": [] -} +} \ No newline at end of file diff --git a/openapi2kong/oas3_testfiles/_fixup_expected.sh b/openapi2kong/oas3_testfiles/_fixup_expected.sh new file mode 100755 index 0000000..e0c999a --- /dev/null +++ b/openapi2kong/oas3_testfiles/_fixup_expected.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +# This script is used to fix up the expected output files in the +# oas3_testfiles directory. +# Often when making small changes, a lot of test files are being impacted. +# This script can be used to fix up the expected output files all at once. +# +# 1. make sure the changes have their own tests which succeed, indicating that +# the failures in the other files are false-positives now. +# 2. commit your changes to ensure you can revert the changes by this script!! +# 3. run the tests with `make test`, to generate all the '*.generated.json' files. +# 4. run this script to copy the generated files over the expected files. +# 5. run the tests again with `make test` to verify that the expected files are +# now correct. + +set -e +# set -x + +if [ -d "openapi2kong" ]; then + pushd openapi2kong +fi +if [ -d "oas3_testfiles" ]; then + pushd oas3_testfiles +fi + +function singlefile() { + filename="$1" + postfix="$2" + destname="${filename%.generated"$postfix".json}.expected$postfix.json" + echo "$filename -> $destname" + cat "$filename" | sed 's/\\u003c//g' > "$destname" +} + +# ls -la + +for f in ./*.generated.json; do + singlefile "$f" "" +done +for f in ./*.generated_noid.json; do + singlefile "$f" "_noid" +done + diff --git a/openapi2kong/openapi2kong.go b/openapi2kong/openapi2kong.go index 5602cf9..288766f 100644 --- a/openapi2kong/openapi2kong.go +++ b/openapi2kong/openapi2kong.go @@ -50,6 +50,27 @@ func Slugify(name ...string) string { return strings.Join(name, "-") } +// SlugifyPath will slugify a path similar to Inso did for compatibility reasons. +func SlugifyPath(path string) string { + // first deal with path parameters in curly braces (drop the curly braces) + re, _ := regexp.Compile("{([^}]+)}") + result := path + if matches := re.FindAllStringSubmatch(path, -1); matches != nil { + for _, match := range matches { + varName := match[1] + result = strings.Replace(result, "{"+varName+"}", varName, 1) + } + } + + // strip the leading slash + result = strings.TrimPrefix(result, "/") + + // replace all '/' characters + result = strings.ReplaceAll(result, "/", "-") + + return Slugify(result) +} + // sanitizeRegexCapture will remove illegal characters from the path-variable name. // The returned name will be valid for PCRE regex captures; Alphanumeric + '_', starting // with [a-zA-Z]. @@ -569,7 +590,7 @@ func Convert(content []byte, opts O2kOptions) (map[string]interface{}, error) { // there is no path, so skip it pathBaseName = docBaseName } else { - pathBaseName = Slugify(path) + pathBaseName = SlugifyPath(path) if strings.HasSuffix(path, "/") { // a common case is 2 paths, one with and one without a trailing "/" so to prevent // duplicate names being generated, we add a "~" suffix as a special case to cater @@ -708,8 +729,8 @@ func Convert(content []byte, opts O2kOptions) (map[string]interface{}, error) { return nil, err } if operationBaseName != "" { - // an x-kong-name was provided, so build as "doc-path-name" - operationBaseName = pathBaseName + "-" + Slugify(operationBaseName) + // an x-kong-name was provided, so build as "doc-name" + operationBaseName = docBaseName + "-" + Slugify(operationBaseName) } else { operationBaseName = operation.OperationID if operationBaseName == "" {