apidef/oas/README.md
This package provides support for OpenAPI Specification (OAS) schema validation and integration with Tyk's custom extensions.
The OAS package handles:
x-tyk-api-gateway) into OAS schemasWhen a new OAS version is released (e.g., OAS 4.0), follow these steps to add support:
apidef/oas/schema/ directory with the naming convention: {major}.{minor}.json
3.1.json for OAS 3.1.x4.0.json for OAS 4.0.x# Example
curl -o apidef/oas/schema/4.0.json https://spec.openapis.org/oas/4.0/schema/...
Different OAS/JSON Schema versions may use different keys for definitions:
"definitions" (JSON Schema Draft 04)"$defs" (JSON Schema 2020-12)Check the schema file to identify which key is used:
# Check for definitions key
grep -E '"definitions"|"\$defs"' apidef/oas/schema/4.0.json | head -5
The code is designed to automatically detect and handle different definition keys using the GetDefinitionsKey() function.
If the new version uses an existing key (definitions or $defs):
If the new version uses a NEW key (e.g., $schemas):
GetDefinitionsKey() function in validator.go to detect the new key:func GetDefinitionsKey(schemaData []byte) string {
// Try newest format first
if _, _, _, err := jsonparser.Get(schemaData, "new-key"); err == nil {
return "new-key"
}
// Try OAS 3.1+ format
if _, _, _, err := jsonparser.Get(schemaData, keyDefs); err == nil {
return keyDefs
}
// Fall back to OAS 3.0 format
return keyDefinitions
}
Add comprehensive tests to ensure the new schema loads correctly:
Test_loadOASSchemaThe test will automatically verify the new version if the schema file exists. It:
Create a new test function to validate documents with the new version:
func TestValidateOASObject_4_0(t *testing.T) {
t.Parallel()
// Create minimal valid OAS 4.0 document
validOAS40Doc := []byte(`{
"openapi": "4.0.0",
"info": {
"title": "Test API 4.0",
"version": "1.0.0"
},
"paths": {
"/test": {
"get": {
"responses": {
"200": {
"description": "Success"
}
}
}
}
},
"x-tyk-api-gateway": {
"info": {
"name": "test-api-4.0",
"state": {
"active": true
}
},
"upstream": {
"url": "http://localhost:8080"
},
"server": {
"listenPath": {
"value": "/test-api-4.0/"
}
}
}
}`)
t.Run("valid OAS 4.0 document with version 4.0.0", func(t *testing.T) {
t.Parallel()
err := ValidateOASObject(validOAS40Doc, "4.0.0")
assert.NoError(t, err)
})
t.Run("valid OAS 4.0 document with version 4.0", func(t *testing.T) {
t.Parallel()
err := ValidateOASObject(validOAS40Doc, "4.0")
assert.NoError(t, err)
})
}
func TestValidateOASTemplate_4_0(t *testing.T) {
t.Parallel()
// Minimal OAS 4.0 template (missing required x-tyk fields)
template40 := []byte(`{
"openapi": "4.0.0",
"info": {
"title": "Template API 4.0",
"version": "1.0.0"
},
"paths": {},
"x-tyk-api-gateway": {}
}`)
t.Run("valid OAS 4.0 template", func(t *testing.T) {
t.Parallel()
err := ValidateOASTemplate(template40, "4.0")
assert.NoError(t, err)
})
}
Update TestGetOASSchema with new test cases:
t.Run("return 4.0 schema when version 4.0 is requested", func(t *testing.T) {
schema, err := GetOASSchema("4.0")
assert.NoError(t, err)
assert.NotEmpty(t, schema)
// Verify it's the 4.0 schema by checking the definitions key
defsKey := GetDefinitionsKey(schema)
assert.Equal(t, "expected-key", defsKey, "OAS 4.0 should use 'expected-key'")
})
t.Run("return 4.0 schema when version 4.0.0 is requested", func(t *testing.T) {
schema, err := GetOASSchema("4.0.0")
assert.NoError(t, err)
assert.NotEmpty(t, schema)
defsKey := GetDefinitionsKey(schema)
assert.Equal(t, "expected-key", defsKey)
})
Run all tests to ensure the new version works correctly:
# Run all OAS package tests
cd apidef/oas
go test -v
# Run specific tests
go test -v -run "Test_loadOASSchema|TestValidateOASObject_4_0|TestGetOASSchema"
The default OAS version is controlled in the setDefaultVersion() function in validator.go.
To keep the current default version:
To make the new version the default:
setDefaultVersion():func setDefaultVersion() {
var versions []string
for k := range oasJSONSchemas {
versions = append(versions, k)
}
latestVersion := findDefaultVersion(versions)
// Remove or update this override when ready to use newer version
if latestVersion == "4.0" {
defaultVersion = "3.0" // Keep 3.0 as default for now
} else {
defaultVersion = latestVersion
}
}
If the new OAS version has breaking changes or requires updates to existing code:
Here's what was done to add OAS 3.1 support:
schema/3.1.json file$defs instead of definitionsGetDefinitionsKey() to detect $defsloadOASSchema() to use detected keyValidateOASTemplate() to use detected keyTestGetDefinitionsKey - Tests the helper functionTestValidateOASObject_3_1 - Tests validation of 3.1 documentsTestValidateOASTemplate_3_1 - Tests template validationTest_loadOASSchema - Verifies both 3.0 and 3.1TestGetOASSchema - Added 3.1 retrieval testsThe GetDefinitionsKey() function automatically detects which key a schema uses, making the code robust across versions.
GetDefinitionsKey() is a public function, allowing other products to leverage this detection logic.
3.0, 3.1)3.1.2) map to their minor versionX-Tyk extensions are injected from schema/x-tyk-api-gateway.json into each OAS schema during load time, ensuring all schemas have consistent Tyk-specific validation.
Problem: New schema file is not being loaded.
Solutions:
{major}.{minor}.jsonschema/ directoryvalidator.goProblem: X-Tyk extensions are not being validated.
Solutions:
GetDefinitionsKey() correctly detects the schema's definitions keyx-tyk-api-gateway.json uses the correct definitions keyloadOASSchema() to see which key is being usedProblem: Existing tests fail after adding new schema.
Solutions:
Test_setDefaultVersion needs updating (it may expect a specific default)go test -vWhen adding a new OAS version: