docs/dev/oas_only_feature_development.md
This guide outlines the standard approach for developing new features that exclusively use OpenAPI Specification (OAS) in Tyk. This approach helps reduce technical debt by moving away from dual configurations (classic API definition and OAS) to a single source of truth using OAS.
type APISpec struct {
*apidef.APIDefinition
OAS oas.OAS
// Helper method for retrieving OAS features
func (s *APISpec) GetTykExtension() *XTykAPIGateway {
...
}
}
type XTykAPIGateway struct {
Info Info `json:"info"`
Upstream Upstream `json:"upstream"`
Server Server `json:"server"`
Middleware *Middleware `json:"middleware,omitempty"`
}
XTykAPIGateway structure:type XTykAPIGateway struct {
// Existing fields...
Middleware *Middleware `json:"middleware,omitempty"`
// New feature configuration
MyNewFeature *MyNewFeatureConfig `json:"myNewFeature,omitempty"`
}
type MyNewFeatureConfig struct {
Enabled bool `json:"enabled"`
// Feature-specific configuration
}
type MyFeatureMiddleware struct {
BaseMiddleware
}
func NewMyFeatureMiddleware() *MyFeatureMiddleware {
return &MyFeatureMiddleware{}
}
func (m *MyFeatureMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, conf interface{}) (error, int) {
if !m.Spec.APIDefinition.IsOAS {
// Feature only available for OAS APIs
return nil, http.StatusOK
}
tykExt := m.Spec.GetTykExtension()
if tykExt.MyNewFeature == nil || !tykExt.MyNewFeature.Enabled {
return nil, http.StatusOK
}
// Implement feature logic here
return m.handleFeature(w, r, tykExt.MyNewFeature)
}
Testing OAS-only features requires special attention to how the feature behaves with different API definition types. Focus on these key scenarios:
func TestMyFeatureMiddleware(t *testing.T) {
tests := []struct {
name string
setupAPI func() *APISpec
expectedCode int
expectedError error
description string
}{
{
name: "classic_api_definition",
setupAPI: func() *APISpec {
return &APISpec{
APIDefinition: &apidef.APIDefinition{
IsOAS: false,
},
}
},
expectedCode: http.StatusOK,
expectedError: nil,
description: "Should pass through silently for classic APIs",
},
{
name: "nil_oas_definition",
setupAPI: func() *APISpec {
return &APISpec{
APIDefinition: &apidef.APIDefinition{
IsOAS: true,
},
OAS: oas.OAS{}, // Empty OAS
}
},
expectedCode: http.StatusOK,
expectedError: nil,
description: "Should handle nil OAS gracefully",
},
{
name: "valid_oas_definition",
setupAPI: func() *APISpec {
return &APISpec{
APIDefinition: &apidef.APIDefinition{
IsOAS: true,
},
OAS: createValidOAS(), // Helper to create OAS with your feature enabled
}
},
expectedCode: http.StatusOK,
expectedError: nil,
description: "Should process feature when properly configured",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
mw := NewMyFeatureMiddleware()
mw.Spec = tc.setupAPI()
err, code := mw.ProcessRequest(nil, &http.Request{}, nil)
assert.Equal(t, tc.expectedError, err)
assert.Equal(t, tc.expectedCode, code)
})
}
}
The test cases above cover:
Each test verifies that the middleware:
API Documentation
Code Documentation
2Testing
While OAS-only features don't need classic API definition support, ensure:
1Migration