diff --git a/model/endpoint.go b/model/endpoint.go index 38e2cea..cd9ee88 100644 --- a/model/endpoint.go +++ b/model/endpoint.go @@ -95,8 +95,9 @@ func (u *LiteralUri) GetValue() interface{} { } type EndpointConfiguration struct { - URI URITemplate `json:"uri" validate:"required"` - Authentication *ReferenceableAuthenticationPolicy `json:"authentication,omitempty"` + RuntimeExpression *RuntimeExpression `json:"-"` + URI URITemplate `json:"uri" validate:"required"` + Authentication *ReferenceableAuthenticationPolicy `json:"authentication,omitempty"` } // UnmarshalJSON implements custom unmarshalling for EndpointConfiguration. @@ -116,12 +117,35 @@ func (e *EndpointConfiguration) UnmarshalJSON(data []byte) error { // Unmarshal the URI field into the appropriate URITemplate implementation uri, err := UnmarshalURITemplate(temp.URI) - if err != nil { - return fmt.Errorf("invalid URI in EndpointConfiguration: %w", err) + if err == nil { + e.URI = uri + return nil + } + + var runtimeExpr RuntimeExpression + if err := json.Unmarshal(temp.URI, &runtimeExpr); err == nil && runtimeExpr.IsValid() { + e.RuntimeExpression = &runtimeExpr + return nil } - e.URI = uri - return nil + return errors.New("failed to unmarshal EndpointConfiguration: data does not match any known schema") +} + +// MarshalJSON implements custom marshalling for Endpoint. +func (e *EndpointConfiguration) MarshalJSON() ([]byte, error) { + m := make(map[string]interface{}) + if e.Authentication != nil { + m["authentication"] = e.Authentication + } + + if e.RuntimeExpression != nil { + m["uri"] = e.RuntimeExpression + } else if e.URI != nil { + m["uri"] = e.URI + } + + // Return an empty JSON object when no fields are set + return json.Marshal(m) } type Endpoint struct { diff --git a/model/endpoint_test.go b/model/endpoint_test.go index 974216e..db2fce5 100644 --- a/model/endpoint_test.go +++ b/model/endpoint_test.go @@ -71,6 +71,48 @@ func TestEndpoint_UnmarshalJSON(t *testing.T) { assert.Equal(t, "admin", endpoint.EndpointConfig.Authentication.AuthenticationPolicy.Basic.Password, "Authentication Password should match") }) + t.Run("Valid EndpointConfiguration with reference", func(t *testing.T) { + input := `{ + "uri": "http://example.com/{id}", + "authentication": { + "oauth2": { "use": "secret" } + } + }` + + var endpoint Endpoint + err := json.Unmarshal([]byte(input), &endpoint) + + assert.NoError(t, err, "Unmarshal should not return an error") + assert.NotNil(t, endpoint.EndpointConfig, "EndpointConfig should be set") + assert.NotNil(t, endpoint.EndpointConfig.URI, "EndpointConfig URI should be set") + assert.Nil(t, endpoint.EndpointConfig.RuntimeExpression, "EndpointConfig Expression should not be set") + assert.Equal(t, "secret", endpoint.EndpointConfig.Authentication.AuthenticationPolicy.OAuth2.Use, "Authentication secret should match") + b, err := json.Marshal(&endpoint) + assert.NoError(t, err, "Marshal should not return an error") + assert.JSONEq(t, input, string(b), "Output JSON should match") + }) + + t.Run("Valid EndpointConfiguration with reference and expression", func(t *testing.T) { + input := `{ + "uri": "${example}", + "authentication": { + "oauth2": { "use": "secret" } + } + }` + + var endpoint Endpoint + err := json.Unmarshal([]byte(input), &endpoint) + + assert.NoError(t, err, "Unmarshal should not return an error") + assert.NotNil(t, endpoint.EndpointConfig, "EndpointConfig should be set") + assert.Nil(t, endpoint.EndpointConfig.URI, "EndpointConfig URI should not be set") + assert.NotNil(t, endpoint.EndpointConfig.RuntimeExpression, "EndpointConfig Expression should be set") + assert.Equal(t, "secret", endpoint.EndpointConfig.Authentication.AuthenticationPolicy.OAuth2.Use, "Authentication secret should match") + b, err := json.Marshal(&endpoint) + assert.NoError(t, err, "Marshal should not return an error") + assert.JSONEq(t, input, string(b), "Output JSON should match") + }) + t.Run("Invalid JSON Structure", func(t *testing.T) { input := `{"invalid": "data"}` var endpoint Endpoint