From 2b98025cfff032be5dbc0aef1bfc6ef4a66e51b3 Mon Sep 17 00:00:00 2001 From: Yi Tao Date: Fri, 10 May 2024 13:48:39 +0800 Subject: [PATCH] add SchemaService.Validate to validate arbitrary entity --- CHANGELOG.md | 6 +++++ kong/schema_service.go | 28 +++++++++++++++++++++ kong/schema_service_test.go | 49 +++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba889bd11..f2fc5bc95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,12 @@ - [0.2.0](#020) - [0.1.0](#010) +## Unreleased + +- Add `Validate` method in `SchemaService` to validate arbitrary type of Kong + entities. + [#443](https://github.com/Kong/go-kong/pull/443) + ## [v0.54.0] > Release date: 2024/04/03 diff --git a/kong/schema_service.go b/kong/schema_service.go index 392db5b75..5c77814b6 100644 --- a/kong/schema_service.go +++ b/kong/schema_service.go @@ -2,13 +2,18 @@ package kong import ( "context" + "errors" "fmt" + "net/http" ) // AbstractSchemaService handles schemas in Kong. type AbstractSchemaService interface { // Get fetches an entity schema from Kong. Get(ctx context.Context, entity string) (Schema, error) + // Validate validates an arbitrary entity in Kong. + // Used for custom entities, or entities that does not have a Validate method in the corresponding service. + Validate(ctx context.Context, entityType string, entity interface{}) (bool, string, error) } // SchemaService handles schemas in Kong. @@ -17,6 +22,8 @@ type SchemaService service // Schema represents an entity schema in Kong. type Schema map[string]interface{} +var _ AbstractSchemaService = &SchemaService{} + // Get retrieves the full schema of kong entities. func (s *SchemaService) Get(ctx context.Context, entity string) (Schema, error) { req, err := s.client.NewRequest("GET", fmt.Sprintf("/schemas/%s", entity), nil, nil) @@ -30,3 +37,24 @@ func (s *SchemaService) Get(ctx context.Context, entity string) (Schema, error) } return schema, nil } + +// Validate validates an arbitrary entity in Kong. +func (s *SchemaService) Validate(ctx context.Context, entityType string, entity interface{}) (bool, string, error) { + endpoint := fmt.Sprintf("/schemas/%s/validate", entityType) + req, err := s.client.NewRequest("POST", endpoint, nil, entity) + if err != nil { + return false, "", err + } + resp, err := s.client.Do(ctx, req, nil) + if err != nil { + if resp == nil { + return false, "", err + } + var apiErr *APIError + if ok := errors.As(err, &apiErr); !ok || apiErr.Code() != http.StatusBadRequest { + return false, "", err + } + return false, apiErr.message, nil + } + return true, "", nil +} diff --git a/kong/schema_service_test.go b/kong/schema_service_test.go index c64ee8545..0b3e8f724 100644 --- a/kong/schema_service_test.go +++ b/kong/schema_service_test.go @@ -32,3 +32,52 @@ func TestSchemaService(T *testing.T) { assert.NoError(err) } } + +func TestSchemaServiceValidate(t *testing.T) { + assert := assert.New(t) + + client, err := NewTestClient(nil, nil) + assert.NoError(err) + assert.NotNil(client) + + testCases := []struct { + name string + entityType string + entity any + valid bool + }{ + { + name: "valid service should pass the validation", + entityType: "services", + entity: &Service{ + Name: String("test.service"), + Host: String("foo.com"), + }, + valid: true, + }, + { + name: "invalid service (invalid protocol) should fail the validation", + entity: &Service{ + Name: String("test.service"), + Host: String("foo.com"), + Protocol: String("not-exist-protocol"), + }, + valid: false, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + valid, msg, err := client.Schemas.Validate(defaultCtx, tc.entityType, tc.entity) + assert.NoError(err) + if tc.valid { + assert.True(valid) + assert.Empty(msg) + } else { + assert.False(valid) + assert.NotEmpty(msg) + } + }) + } +}