diff --git a/go.mod b/go.mod
index 97abf8a7e8ecfa30df469cb43f47287bf46b8f5b..b8461cd55d2c97ac440dcd625e4b58039f80d775 100644
--- a/go.mod
+++ b/go.mod
@@ -14,6 +14,7 @@ require (
 	github.com/aws/aws-sdk-go-v2/service/batch v1.36.1
 	github.com/aws/aws-sdk-go-v2/service/s3 v1.53.1
 	github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.28.6
+	github.com/aws/aws-sdk-go-v2/service/ses v1.23.1
 	github.com/aws/aws-sdk-go-v2/service/sqs v1.31.4
 	github.com/aws/aws-secretsmanager-caching-go v1.1.0
 	github.com/aws/smithy-go v1.20.2
@@ -30,6 +31,7 @@ require (
 	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
 	github.com/opensearch-project/opensearch-go/v2 v2.2.0
 	github.com/pkg/errors v0.9.1
+	github.com/prozz/aws-embedded-metrics-golang v1.2.0
 	github.com/r3labs/diff/v2 v2.14.2
 	github.com/samber/lo v1.38.1
 	github.com/sirupsen/logrus v1.8.1
@@ -38,6 +40,7 @@ require (
 	golang.ngrok.com/ngrok v1.4.1
 	golang.org/x/crypto v0.22.0
 	golang.org/x/text v0.14.0
+	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
 )
 
 require (
@@ -52,7 +55,6 @@ require (
 	github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.7 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 // indirect
 	github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.5 // indirect
-	github.com/aws/aws-sdk-go-v2/service/ses v1.23.1 // indirect
 	github.com/aws/aws-sdk-go-v2/service/sso v1.20.4 // indirect
 	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect
 	github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 // indirect
@@ -73,7 +75,6 @@ require (
 	github.com/mattn/go-runewidth v0.0.10 // indirect
 	github.com/olekukonko/tablewriter v0.0.5 // indirect
 	github.com/pborman/uuid v1.2.1 // indirect
-	github.com/prozz/aws-embedded-metrics-golang v1.2.0 // indirect
 	github.com/rivo/uniseg v0.1.0 // indirect
 	github.com/smartystreets/goconvey v1.7.2 // indirect
 	github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
@@ -92,6 +93,5 @@ require (
 	google.golang.org/appengine v1.6.6 // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
 	gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
-	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
 	mellium.im/sasl v0.2.1 // indirect
 )
diff --git a/go.sum b/go.sum
index 82ebf050f317ffa1e5efe28a40a210022df883b7..cb29536ba98516e6d496bdc8d9ad14ac2fb890c0 100644
--- a/go.sum
+++ b/go.sum
@@ -12,8 +12,6 @@ github.com/aws/aws-sdk-go v1.19.23/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpi
 github.com/aws/aws-sdk-go v1.44.180 h1:VLZuAHI9fa/3WME5JjpVjcPCNfpGHVMiHx8sLHWhMgI=
 github.com/aws/aws-sdk-go v1.44.180/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
 github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
-github.com/aws/aws-sdk-go-v2 v1.27.1 h1:xypCL2owhog46iFxBKKpBcw+bPTX/RJzwNj8uSilENw=
-github.com/aws/aws-sdk-go-v2 v1.27.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
 github.com/aws/aws-sdk-go-v2 v1.30.0 h1:6qAwtzlfcTtcL8NHtbDQAqgM5s6NDipQTkPxyH/6kAA=
 github.com/aws/aws-sdk-go-v2 v1.30.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
 github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to=
@@ -28,13 +26,9 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21/go.mod h1:ugwW57Z5Z48bpvU
 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 h1:FVJ0r5XTHSmIHJV6KuDmdYhEpvlHpiSd38RQWhut5J4=
 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1/go.mod h1:zusuAeqezXzAB24LGuzuekqMAEgWkVYukBec3kr3jUg=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBBerajpnP5nGZa9mGzsBn5cOKxm6NWQsvoI=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.8 h1:RnLB7p6aaFMRfyQkD6ckxR7myCC9SABIqSz4czYUUbU=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.8/go.mod h1:XH7dQJd+56wEbP1I4e4Duo+QhSMxNArE8VP7NuUOTeM=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12 h1:SJ04WXGTwnHlWIODtC5kJzKbeuHt+OUNOgKg7nfnUGw=
 github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12/go.mod h1:FkpvXhA92gb3GE9LD6Og0pHHycTxW7xGpnEh5E7Opwo=
 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21/go.mod h1:+Gxn8jYn5k9ebfHEqlhrMirFjSW0v0C9fI+KN5vk2kE=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.8 h1:jzApk2f58L9yW9q1GEab3BMMFWUkkiZhyrRUtbwUbKU=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.8/go.mod h1:WqO+FftfO3tGePUtQxPXM6iODVfqMwsVMgTbG/ZXIdQ=
 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12 h1:hb5KgeYfObi5MHkSSZMEudnIvX30iB+E21evI4r6BnQ=
 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12/go.mod h1:CroKe/eWJdyfy9Vx4rljP5wTUjNJfb+fPz1uMYUhEGM=
 github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28/go.mod h1:yRZVr/iT0AqyHeep00SZ4YfBAKojXz08w3XMBscdi0c=
@@ -171,6 +165,7 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/kinbiko/jsonassert v1.0.1 h1:8gdLmUaPWuxk2TzQSofKRqatFH6zwTF6AsUH4bugJYY=
 github.com/kinbiko/jsonassert v1.0.1/go.mod h1:QRwBwiAsrcJpjw+L+Q4WS8psLxuUY+HylVZS/4j74TM=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
diff --git a/struct_utils/named_values_to_struct_test.go b/struct_utils/named_values_to_struct_test.go
index 653cb0256d48ceea4db3da4690e09e0e18e8b767..114c45fada028253bebba18d13ad560541a1e8ad 100644
--- a/struct_utils/named_values_to_struct_test.go
+++ b/struct_utils/named_values_to_struct_test.go
@@ -10,13 +10,12 @@ import (
 	"time"
 
 	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/errors"
-	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/logs"
 	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/struct_utils"
 )
 
 func TestEnv(t *testing.T) {
-	logs.SetGlobalFormat(logs.NewConsole())
-	logs.SetGlobalLevel(logs.LevelDebug)
+	//logs.SetGlobalFormat(logs.NewConsole())
+	//logs.SetGlobalLevel(logs.LevelDebug)
 	// booleans
 	os.Setenv("TEST_VALUE_ENABLE_CACHE", "true")
 	os.Setenv("TEST_VALUE_DISABLE_LOG", "true")
@@ -43,8 +42,8 @@ func TestEnv(t *testing.T) {
 }
 
 func TestURL1(t *testing.T) {
-	logs.SetGlobalFormat(logs.NewConsole())
-	logs.SetGlobalLevel(logs.LevelDebug)
+	//logs.SetGlobalFormat(logs.NewConsole())
+	//logs.SetGlobalLevel(logs.LevelDebug)
 
 	queryParams := map[string]string{
 		"enable_cache": "true",
@@ -63,8 +62,8 @@ func TestURL1(t *testing.T) {
 }
 
 func TestURL2(t *testing.T) {
-	logs.SetGlobalFormat(logs.NewConsole())
-	logs.SetGlobalLevel(logs.LevelDebug)
+	//logs.SetGlobalFormat(logs.NewConsole())
+	//logs.SetGlobalLevel(logs.LevelDebug)
 
 	queryParams := map[string]string{
 		"disable_log": "true",
diff --git a/struct_utils/required_fields_test.go b/struct_utils/required_fields_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..f8d54fcc41f54c0af6995a171de9d972ecae9a83
--- /dev/null
+++ b/struct_utils/required_fields_test.go
@@ -0,0 +1,653 @@
+package struct_utils
+
+import (
+	"encoding/json"
+	"fmt"
+	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/errors"
+	"reflect"
+	"testing"
+)
+
+// Basic field types
+type OptionalFieldStruct struct {
+	OptionalField string `json:"field"`
+}
+
+type RequiredFieldStruct struct {
+	RequiredField string `json:"field" required:"true"`
+}
+
+// Basic pointer field types
+type OptionalPointerFieldStruct struct {
+	OptionalField *string `json:"pointer_field"`
+}
+
+type RequiredPointerFieldStruct struct {
+	RequiredField *string `json:"pointer_field" required:"true"`
+}
+
+type NotNilPointerFieldStruct struct {
+	RequiredField *string `json:"pointer_field" required:"not-nil"`
+}
+
+// Basic slice field types
+type OptionalSliceStruct struct {
+	OptionalSlice []string `json:"slice_field"`
+}
+
+type OptionalDeepSliceStruct struct {
+	OptionalSlice []string `json:"slice_field" required:"deep"`
+}
+
+type RequiredSliceStruct struct {
+	RequiredSlice []string `json:"slice_field" required:"true"`
+}
+
+type RequiredDeepSliceStruct struct {
+	RequiredSlice []string `json:"slice_field" required:"true,deep"`
+}
+
+type NotNilSliceStruct struct {
+	RequiredSlice []string `json:"slice_field" required:"not-nil"`
+}
+
+type NotNilDeepSliceStruct struct {
+	RequiredSlice []string `json:"slice_field" required:"not-nil,deep"`
+}
+
+// Custom slice type
+type RequiredFieldSliceType []RequiredFieldStruct
+
+// Basic map field types
+type OptionalMapStruct struct {
+	OptionalMap map[string]any `json:"map_field"`
+}
+
+type RequiredMapStruct struct {
+	RequiredMap map[string]any `json:"map_field" required:"true"`
+}
+
+type NotNilMapStruct struct {
+	RequiredMap map[string]any `json:"map_field" required:"not-nil"`
+}
+
+// Structs with optional nested fields
+type OptionalNestedOptionalFieldStruct struct {
+	OptionalNested OptionalFieldStruct `json:"optional_field_nested"`
+}
+
+type OptionalNestedPointerOptionalFieldStruct struct {
+	OptionalNested *OptionalFieldStruct `json:"optional_field_nested"`
+}
+
+type RequiredNestedOptionalFieldStruct struct {
+	RequiredNested OptionalFieldStruct `json:"optional_field_nested" required:"true"`
+}
+
+type RequiredNestedPointerOptionalFieldStruct struct {
+	RequiredNested *OptionalFieldStruct `json:"optional_field_nested" required:"true"`
+}
+
+type NotNilNestedPointerOptionalFieldStruct struct {
+	RequiredNested *OptionalFieldStruct `json:"optional_field_nested" required:"not-nil"`
+}
+
+// Structs with required nested fields
+type OptionalNestedRequiredFieldStruct struct {
+	OptionalNested RequiredFieldStruct `json:"required_field_nested"`
+}
+
+type OptionalNestedPointerRequiredFieldStruct struct {
+	OptionalNested *RequiredFieldStruct `json:"required_field_nested"`
+}
+
+type RequiredNestedRequiredFieldStruct struct {
+	RequiredNested RequiredFieldStruct `json:"required_field_nested" required:"true"`
+}
+
+type RequiredNestedPointerRequiredFieldStruct struct {
+	RequiredNested *RequiredFieldStruct `json:"required_field_nested" required:"true"`
+}
+
+type NotNilNestedPointerRequiredFieldStruct struct {
+	RequiredNested *RequiredFieldStruct `json:"required_field_nested" required:"not-nil"`
+}
+
+// Structs with optional nested pointer fields
+type OptionalNestedOptionalPointerFieldStruct struct {
+	OptionalNested OptionalPointerFieldStruct `json:"optional_field_nested"`
+}
+
+type OptionalNestedPointerOptionalPointerFieldStruct struct {
+	OptionalNested *OptionalPointerFieldStruct `json:"optional_field_nested"`
+}
+
+type RequiredNestedOptionalPointerFieldStruct struct {
+	RequiredNested OptionalPointerFieldStruct `json:"optional_field_nested" required:"true"`
+}
+
+type RequiredNestedPointerOptionalPointerFieldStruct struct {
+	RequiredNested *OptionalPointerFieldStruct `json:"optional_field_nested" required:"true"`
+}
+
+type NotNilNestedPointerOptionalPointerFieldStruct struct {
+	RequiredNested *OptionalPointerFieldStruct `json:"optional_field_nested" required:"not-nil"`
+}
+
+// Structs with required nested pointer fields
+type OptionalNestedRequiredPointerFieldStruct struct {
+	OptionalNested RequiredPointerFieldStruct `json:"required_field_nested"`
+}
+
+type OptionalNestedPointerRequiredPointerFieldStruct struct {
+	OptionalNested *RequiredPointerFieldStruct `json:"required_field_nested"`
+}
+
+type RequiredNestedRequiredPointerFieldStruct struct {
+	RequiredNested RequiredPointerFieldStruct `json:"required_field_nested" required:"true"`
+}
+
+type RequiredNestedPointerRequiredPointerFieldStruct struct {
+	RequiredNested *RequiredPointerFieldStruct `json:"required_field_nested" required:"true"`
+}
+
+type NotNilNestedPointerRequiredPointerFieldStruct struct {
+	RequiredNested *RequiredPointerFieldStruct `json:"required_field_nested" required:"not-nil"`
+}
+
+// Deep test
+type DeepFieldStruct struct {
+	OptionalField string `json:"optional_field"`
+	RequiredField string `json:"required_field" required:"true"`
+}
+
+type OptionalNestedDeepRequiredDeepFieldStruct struct {
+	OptionalNested DeepFieldStruct `json:"deep_field_nested" required:"deep"`
+}
+
+type OptionalNestedPointerDeepRequiredDeepFieldPointerStruct struct {
+	OptionalNested *DeepFieldStruct `json:"deep_field_nested" required:"deep"`
+}
+
+type RequiredNestedDeepRequiredDeepFieldStruct struct {
+	RequiredNested DeepFieldStruct `json:"deep_field_nested" required:"true,deep"`
+}
+
+type RequiredNestedPointerDeepRequiredDeepFieldStruct struct {
+	RequiredNested *DeepFieldStruct `json:"deep_field_nested" required:"true,deep"`
+}
+
+type NotNilNestedPointerRequiredDeepFieldStruct struct {
+	RequiredNested *DeepFieldStruct `json:"deep_field_nested" required:"not-nil"`
+}
+
+type NotNilNestedPointerDeepRequiredDeepFieldStruct struct {
+	RequiredNested *DeepFieldStruct `json:"deep_field_nested" required:"not-nil,deep"`
+}
+
+// Complex test
+type ComplexChildStruct struct {
+	OptionalField           string           `json:"optional_field"`
+	RequiredField           string           `json:"required_field" required:"true"`
+	RequiredSliceField      []string         `json:"required_slice_field" required:"not-nil"`
+	OptionalDeepFieldStruct *DeepFieldStruct `json:"optional_deep_field_struct" required:"not-nil,deep"`
+}
+
+type ComplexParentStruct struct {
+	OptionalField                    string               `json:"optional_field"`
+	RequiredField                    string               `json:"required_field" required:"true"`
+	RequiredComplexChildStructSlice  []ComplexChildStruct `json:"required_complex_child_struct_slice" required:"true,deep"`
+	NonNilComplexChildStructSlice    []ComplexChildStruct `json:"non_nil_complex_child_struct_slice" required:"not-nil,deep"`
+	DeepRequiredDeepFieldStructSlice []DeepFieldStruct    `json:"deep_required_deep_field_struct_slice" required:"deep"`
+	OptionalDeepComplexChildStruct   *ComplexChildStruct  `json:"optional_complex_child_struct" required:"deep"`
+}
+
+// Embed test
+type OptionalEmbedFieldStruct struct {
+	RequiredFieldStruct
+}
+
+type RequiredEmbedFieldStruct struct {
+	RequiredFieldStruct `required:"deep"`
+}
+
+type MultiRequiredEmbedFieldStruct struct {
+	RequiredEmbedFieldStruct `required:"deep"`
+}
+
+func TestRequiredFieldsValidation(t *testing.T) {
+	var emptyJsonString, zeroValueJsonString, nonZeroValueJsonString string
+
+	// ****************************************************************************************************
+	// 	Basic field types - Checked
+	// ****************************************************************************************************
+	var optionalFieldStruct OptionalFieldStruct
+	var requiredFieldStruct RequiredFieldStruct
+
+	// Empty json string
+	emptyJsonString = `{}`
+	CheckValidation(t, "Basic.A", emptyJsonString, reflect.TypeOf(optionalFieldStruct), "")
+	CheckValidation(t, "Basic.B", emptyJsonString, reflect.TypeOf(requiredFieldStruct), "field is required")
+
+	// Json string with zero value
+	zeroValueJsonString = `{"field":""}`
+	CheckValidation(t, "Basic.C", zeroValueJsonString, reflect.TypeOf(optionalFieldStruct), "")
+	CheckValidation(t, "Basic.D", zeroValueJsonString, reflect.TypeOf(requiredFieldStruct), "field is required")
+
+	// Json string with non-zero value
+	nonZeroValueJsonString = `{"field":"value"}`
+	CheckValidation(t, "Basic.E", nonZeroValueJsonString, reflect.TypeOf(optionalFieldStruct), "")
+	CheckValidation(t, "Basic.F", nonZeroValueJsonString, reflect.TypeOf(requiredFieldStruct), "")
+
+	// ****************************************************************************************************
+	// 	Basic pointer field types - Checked
+	// ****************************************************************************************************
+	var optionalPointerFieldStruct OptionalPointerFieldStruct
+	var requiredPointerFieldStruct RequiredPointerFieldStruct
+	var notNilPointerFieldStruct NotNilPointerFieldStruct
+
+	// Empty json string
+	emptyJsonString = `{}`
+	CheckValidation(t, "Pointer.A", emptyJsonString, reflect.TypeOf(optionalPointerFieldStruct), "")
+	CheckValidation(t, "Pointer.B", emptyJsonString, reflect.TypeOf(requiredPointerFieldStruct), "pointer_field is required")
+	CheckValidation(t, "Pointer.C", emptyJsonString, reflect.TypeOf(notNilPointerFieldStruct), "pointer_field is required")
+
+	// Json string with zero value
+	zeroValueJsonString = `{"pointer_field": ""}`
+	CheckValidation(t, "Pointer.D", zeroValueJsonString, reflect.TypeOf(optionalPointerFieldStruct), "")
+	CheckValidation(t, "Pointer.E", zeroValueJsonString, reflect.TypeOf(requiredPointerFieldStruct), "pointer_field is required")
+	CheckValidation(t, "Pointer.F", zeroValueJsonString, reflect.TypeOf(notNilPointerFieldStruct), "")
+
+	// Json string with non-zero value
+	nonZeroValueJsonString = `{"pointer_field": "value"}`
+	CheckValidation(t, "Pointer.G", nonZeroValueJsonString, reflect.TypeOf(optionalPointerFieldStruct), "")
+	CheckValidation(t, "Pointer.H", nonZeroValueJsonString, reflect.TypeOf(requiredPointerFieldStruct), "")
+	CheckValidation(t, "Pointer.I", nonZeroValueJsonString, reflect.TypeOf(notNilPointerFieldStruct), "")
+
+	// ****************************************************************************************************
+	// 	Basic slice field types - Checked
+	// ****************************************************************************************************
+	var optionalSliceStruct OptionalSliceStruct
+	var optionalDeepSliceStruct OptionalDeepSliceStruct
+	var requiredSliceStruct RequiredSliceStruct
+	var requiredDeepSliceStruct RequiredDeepSliceStruct
+	var notNilSliceStruct NotNilSliceStruct
+	var notNilDeepSliceStruct NotNilDeepSliceStruct
+
+	// Empty json string
+	emptyJsonString = `{}`
+	CheckValidation(t, "Slice.A", emptyJsonString, reflect.TypeOf(optionalSliceStruct), "")
+	CheckValidation(t, "Slice.B", emptyJsonString, reflect.TypeOf(optionalDeepSliceStruct), "")
+	CheckValidation(t, "Slice.C", emptyJsonString, reflect.TypeOf(requiredSliceStruct), "slice_field is required")
+	CheckValidation(t, "Slice.D", emptyJsonString, reflect.TypeOf(requiredDeepSliceStruct), "slice_field is required")
+	CheckValidation(t, "Slice.E", emptyJsonString, reflect.TypeOf(notNilSliceStruct), "slice_field is required")
+	CheckValidation(t, "Slice.F", emptyJsonString, reflect.TypeOf(notNilDeepSliceStruct), "slice_field is required")
+
+	// Json string with zero value slice
+	zeroValueJsonString = `{"slice_field": []}`
+	CheckValidation(t, "Slice.G", zeroValueJsonString, reflect.TypeOf(optionalSliceStruct), "")
+	CheckValidation(t, "Slice.H", zeroValueJsonString, reflect.TypeOf(optionalDeepSliceStruct), "")
+	CheckValidation(t, "Slice.I", zeroValueJsonString, reflect.TypeOf(requiredSliceStruct), "slice_field may not be empty")
+	CheckValidation(t, "Slice.J", zeroValueJsonString, reflect.TypeOf(requiredDeepSliceStruct), "slice_field may not be empty")
+	CheckValidation(t, "Slice.K", zeroValueJsonString, reflect.TypeOf(notNilSliceStruct), "")
+	CheckValidation(t, "Slice.L", zeroValueJsonString, reflect.TypeOf(notNilDeepSliceStruct), "")
+
+	// Json string with single zero-value item
+	zeroValueJsonString = `{"slice_field": [""]}`
+	CheckValidation(t, "Slice.M", zeroValueJsonString, reflect.TypeOf(optionalSliceStruct), "")
+	CheckValidation(t, "Slice.N", zeroValueJsonString, reflect.TypeOf(optionalDeepSliceStruct), "slice_field is required")
+	CheckValidation(t, "Slice.O", zeroValueJsonString, reflect.TypeOf(requiredSliceStruct), "")
+	CheckValidation(t, "Slice.P", zeroValueJsonString, reflect.TypeOf(requiredDeepSliceStruct), "slice_field is required")
+	CheckValidation(t, "Slice.Q", zeroValueJsonString, reflect.TypeOf(notNilSliceStruct), "")
+	CheckValidation(t, "Slice.R", zeroValueJsonString, reflect.TypeOf(notNilDeepSliceStruct), "slice_field is required")
+
+	// Json string with non-zero value
+	nonZeroValueJsonString = `{"slice_field": ["value"]}`
+	CheckValidation(t, "Slice.S", nonZeroValueJsonString, reflect.TypeOf(optionalSliceStruct), "")
+	CheckValidation(t, "Slice.T", nonZeroValueJsonString, reflect.TypeOf(optionalDeepSliceStruct), "")
+	CheckValidation(t, "Slice.U", nonZeroValueJsonString, reflect.TypeOf(requiredSliceStruct), "")
+	CheckValidation(t, "Slice.V", nonZeroValueJsonString, reflect.TypeOf(requiredDeepSliceStruct), "")
+	CheckValidation(t, "Slice.W", nonZeroValueJsonString, reflect.TypeOf(notNilSliceStruct), "")
+	CheckValidation(t, "Slice.X", nonZeroValueJsonString, reflect.TypeOf(notNilDeepSliceStruct), "")
+
+	// ****************************************************************************************************
+	// 	Custom slice type - Checked
+	// ****************************************************************************************************
+	var requiredFieldSliceType RequiredFieldSliceType
+
+	// Empty Json array
+	emptyJsonString = `[]`
+	CheckValidation(t, "SliceType.A", emptyJsonString, reflect.TypeOf(requiredFieldSliceType), "")
+
+	// Json array with zero value
+	zeroValueJsonString = `[{}]`
+	CheckValidation(t, "SliceType.B", zeroValueJsonString, reflect.TypeOf(requiredFieldSliceType), "")
+
+	// ****************************************************************************************************
+	// 	Basic map field types - Checked
+	// ****************************************************************************************************
+	var optionalMapStruct OptionalMapStruct
+	var requiredMapStruct RequiredMapStruct
+	var notNilMapStruct NotNilMapStruct
+
+	// Empty json string
+	emptyJsonString = `{}`
+	CheckValidation(t, "Map.A", emptyJsonString, reflect.TypeOf(optionalMapStruct), "")
+	CheckValidation(t, "Map.B", emptyJsonString, reflect.TypeOf(requiredMapStruct), "map_field is required")
+	CheckValidation(t, "Map.C", emptyJsonString, reflect.TypeOf(notNilMapStruct), "map_field is required")
+
+	// Json string with zero value slice
+	zeroValueJsonString = `{"map_field": {}}`
+	CheckValidation(t, "Map.D", zeroValueJsonString, reflect.TypeOf(optionalMapStruct), "")
+	CheckValidation(t, "Map.E", zeroValueJsonString, reflect.TypeOf(requiredMapStruct), "map_field may not be empty")
+	CheckValidation(t, "Map.F", zeroValueJsonString, reflect.TypeOf(notNilMapStruct), "")
+
+	// Json string with non-zero value
+	nonZeroValueJsonString = `{"map_field": {"key": "value"}}`
+	CheckValidation(t, "Map.G", nonZeroValueJsonString, reflect.TypeOf(optionalMapStruct), "")
+	CheckValidation(t, "Map.H", nonZeroValueJsonString, reflect.TypeOf(requiredMapStruct), "")
+	CheckValidation(t, "Map.I", nonZeroValueJsonString, reflect.TypeOf(notNilMapStruct), "")
+
+	// ****************************************************************************************************
+	// 	Structs with optional nested fields - Checked
+	// ****************************************************************************************************
+	var optionalNestedOptionalFieldStruct OptionalNestedOptionalFieldStruct
+	var optionalNestedPointerOptionalFieldStruct OptionalNestedPointerOptionalFieldStruct
+	var requiredNestedOptionalFieldStruct RequiredNestedOptionalFieldStruct
+	var requiredNestedPointerOptionalFieldStruct RequiredNestedPointerOptionalFieldStruct
+	var notNilNestedPointerOptionalFieldStruct NotNilNestedPointerOptionalFieldStruct
+
+	// Empty json string
+	emptyJsonString = `{}`
+	CheckValidation(t, "OptionalNestedFields.A", emptyJsonString, reflect.TypeOf(optionalNestedOptionalFieldStruct), "")
+	CheckValidation(t, "OptionalNestedFields.B", emptyJsonString, reflect.TypeOf(optionalNestedPointerOptionalFieldStruct), "")
+	CheckValidation(t, "OptionalNestedFields.C", emptyJsonString, reflect.TypeOf(requiredNestedOptionalFieldStruct), "optional_field_nested is required")
+	CheckValidation(t, "OptionalNestedFields.D", emptyJsonString, reflect.TypeOf(requiredNestedPointerOptionalFieldStruct), "optional_field_nested is required")
+	CheckValidation(t, "OptionalNestedFields.E", emptyJsonString, reflect.TypeOf(notNilNestedPointerOptionalFieldStruct), "optional_field_nested is required")
+
+	// Json string with zero value
+	zeroValueJsonString = `{"optional_field_nested": {}}`
+	CheckValidation(t, "OptionalNestedFields.F", zeroValueJsonString, reflect.TypeOf(optionalNestedOptionalFieldStruct), "")
+	CheckValidation(t, "OptionalNestedFields.G", zeroValueJsonString, reflect.TypeOf(optionalNestedPointerOptionalFieldStruct), "")
+	CheckValidation(t, "OptionalNestedFields.H", zeroValueJsonString, reflect.TypeOf(requiredNestedOptionalFieldStruct), "optional_field_nested is required")
+	CheckValidation(t, "OptionalNestedFields.I", zeroValueJsonString, reflect.TypeOf(requiredNestedPointerOptionalFieldStruct), "optional_field_nested is required")
+	CheckValidation(t, "OptionalNestedFields.J", zeroValueJsonString, reflect.TypeOf(notNilNestedPointerOptionalFieldStruct), "")
+
+	// Json string with non-zero value
+	nonZeroValueJsonString = `{"optional_field_nested": {"field": "value"}}`
+	CheckValidation(t, "OptionalNestedFields.K", nonZeroValueJsonString, reflect.TypeOf(optionalNestedOptionalFieldStruct), "")
+	CheckValidation(t, "OptionalNestedFields.L", nonZeroValueJsonString, reflect.TypeOf(optionalNestedPointerOptionalFieldStruct), "")
+	CheckValidation(t, "OptionalNestedFields.M", nonZeroValueJsonString, reflect.TypeOf(requiredNestedOptionalFieldStruct), "")
+	CheckValidation(t, "OptionalNestedFields.N", nonZeroValueJsonString, reflect.TypeOf(requiredNestedPointerOptionalFieldStruct), "")
+	CheckValidation(t, "OptionalNestedFields.O", nonZeroValueJsonString, reflect.TypeOf(notNilNestedPointerOptionalFieldStruct), "")
+
+	// ****************************************************************************************************
+	// 	Structs with required nested fields - Checked
+	// ****************************************************************************************************
+	var optionalNestedRequiredFieldStruct OptionalNestedRequiredFieldStruct
+	var optionalNestedPointerRequiredFieldStruct OptionalNestedPointerRequiredFieldStruct
+	var requiredNestedRequiredFieldStruct RequiredNestedRequiredFieldStruct
+	var requiredNestedPointerRequiredFieldStruct RequiredNestedPointerRequiredFieldStruct
+	var notNilNestedPointerRequiredFieldStruct NotNilNestedPointerRequiredFieldStruct
+
+	// Empty json string
+	emptyJsonString = `{}`
+	CheckValidation(t, "RequiredNestedFields.A", emptyJsonString, reflect.TypeOf(optionalNestedRequiredFieldStruct), "")
+	CheckValidation(t, "RequiredNestedFields.B", emptyJsonString, reflect.TypeOf(optionalNestedPointerRequiredFieldStruct), "")
+	CheckValidation(t, "RequiredNestedFields.C", emptyJsonString, reflect.TypeOf(requiredNestedRequiredFieldStruct), "required_field_nested is required")
+	CheckValidation(t, "RequiredNestedFields.D", emptyJsonString, reflect.TypeOf(requiredNestedPointerRequiredFieldStruct), "required_field_nested is required")
+	CheckValidation(t, "RequiredNestedFields.E", emptyJsonString, reflect.TypeOf(notNilNestedPointerRequiredFieldStruct), "required_field_nested is required")
+
+	// Json string with zero value
+	zeroValueJsonString = `{"required_field_nested": {}}`
+	CheckValidation(t, "RequiredNestedFields.F", zeroValueJsonString, reflect.TypeOf(optionalNestedRequiredFieldStruct), "")
+	CheckValidation(t, "RequiredNestedFields.G", zeroValueJsonString, reflect.TypeOf(optionalNestedPointerRequiredFieldStruct), "")
+	CheckValidation(t, "RequiredNestedFields.H", zeroValueJsonString, reflect.TypeOf(requiredNestedRequiredFieldStruct), "required_field_nested is required")
+	CheckValidation(t, "RequiredNestedFields.I", zeroValueJsonString, reflect.TypeOf(requiredNestedPointerRequiredFieldStruct), "required_field_nested is required")
+	CheckValidation(t, "RequiredNestedFields.J", zeroValueJsonString, reflect.TypeOf(notNilNestedPointerRequiredFieldStruct), "")
+
+	// Json string with non-zero value
+	nonZeroValueJsonString = `{"required_field_nested": {"field": "value"}}`
+	CheckValidation(t, "RequiredNestedFields.K", nonZeroValueJsonString, reflect.TypeOf(optionalNestedRequiredFieldStruct), "")
+	CheckValidation(t, "RequiredNestedFields.L", nonZeroValueJsonString, reflect.TypeOf(optionalNestedPointerRequiredFieldStruct), "")
+	CheckValidation(t, "RequiredNestedFields.M", nonZeroValueJsonString, reflect.TypeOf(requiredNestedRequiredFieldStruct), "")
+	CheckValidation(t, "RequiredNestedFields.N", nonZeroValueJsonString, reflect.TypeOf(requiredNestedPointerRequiredFieldStruct), "")
+	CheckValidation(t, "RequiredNestedFields.O", nonZeroValueJsonString, reflect.TypeOf(notNilNestedPointerRequiredFieldStruct), "")
+
+	// ****************************************************************************************************
+	// 	Structs with optional nested pointer fields - Checked
+	// ****************************************************************************************************
+	var optionalNestedOptionalPointerFieldStruct OptionalNestedOptionalPointerFieldStruct
+	var optionalNestedPointerOptionalPointerFieldStruct OptionalNestedPointerOptionalPointerFieldStruct
+	var requiredNestedOptionalPointerFieldStruct RequiredNestedOptionalPointerFieldStruct
+	var requiredNestedPointerOptionalPointerFieldStruct RequiredNestedPointerOptionalPointerFieldStruct
+	var notNilNestedPointerOptionalPointerFieldStruct NotNilNestedPointerOptionalPointerFieldStruct
+
+	// Empty json string
+	emptyJsonString = `{}`
+	CheckValidation(t, "OptionalNestedPointers.A", emptyJsonString, reflect.TypeOf(optionalNestedOptionalPointerFieldStruct), "")
+	CheckValidation(t, "OptionalNestedPointers.B", emptyJsonString, reflect.TypeOf(optionalNestedPointerOptionalPointerFieldStruct), "")
+	CheckValidation(t, "OptionalNestedPointers.C", emptyJsonString, reflect.TypeOf(requiredNestedOptionalPointerFieldStruct), "optional_field_nested is required")
+	CheckValidation(t, "OptionalNestedPointers.D", emptyJsonString, reflect.TypeOf(requiredNestedPointerOptionalPointerFieldStruct), "optional_field_nested is required")
+	CheckValidation(t, "OptionalNestedPointers.E", emptyJsonString, reflect.TypeOf(notNilNestedPointerOptionalPointerFieldStruct), "optional_field_nested is required")
+
+	// Json string with zero value
+	zeroValueJsonString = `{"optional_field_nested": {}}`
+	CheckValidation(t, "OptionalNestedPointers.F", zeroValueJsonString, reflect.TypeOf(optionalNestedOptionalPointerFieldStruct), "")
+	CheckValidation(t, "OptionalNestedPointers.G", zeroValueJsonString, reflect.TypeOf(optionalNestedPointerOptionalPointerFieldStruct), "")
+	CheckValidation(t, "OptionalNestedPointers.H", zeroValueJsonString, reflect.TypeOf(requiredNestedOptionalPointerFieldStruct), "optional_field_nested is required")
+	CheckValidation(t, "OptionalNestedPointers.I", zeroValueJsonString, reflect.TypeOf(requiredNestedPointerOptionalPointerFieldStruct), "optional_field_nested is required")
+	CheckValidation(t, "OptionalNestedPointers.J", zeroValueJsonString, reflect.TypeOf(notNilNestedPointerOptionalPointerFieldStruct), "")
+
+	// Json string with non-nil pointer value
+	nonZeroValueJsonString = `{"optional_field_nested": {"pointer_field": ""}}`
+	CheckValidation(t, "OptionalNestedPointers.K", nonZeroValueJsonString, reflect.TypeOf(optionalNestedOptionalPointerFieldStruct), "")
+	CheckValidation(t, "OptionalNestedPointers.L", nonZeroValueJsonString, reflect.TypeOf(optionalNestedPointerOptionalPointerFieldStruct), "")
+	CheckValidation(t, "OptionalNestedPointers.M", nonZeroValueJsonString, reflect.TypeOf(requiredNestedOptionalPointerFieldStruct), "")
+	CheckValidation(t, "OptionalNestedPointers.N", nonZeroValueJsonString, reflect.TypeOf(requiredNestedPointerOptionalPointerFieldStruct), "")
+	CheckValidation(t, "OptionalNestedPointers.O", nonZeroValueJsonString, reflect.TypeOf(notNilNestedPointerOptionalPointerFieldStruct), "")
+
+	// Json string with non-zero value
+	nonZeroValueJsonString = `{"optional_field_nested": {"pointer_field": "value"}}`
+	CheckValidation(t, "OptionalNestedPointers.P", nonZeroValueJsonString, reflect.TypeOf(optionalNestedOptionalPointerFieldStruct), "")
+	CheckValidation(t, "OptionalNestedPointers.Q", nonZeroValueJsonString, reflect.TypeOf(optionalNestedPointerOptionalPointerFieldStruct), "")
+	CheckValidation(t, "OptionalNestedPointers.R", nonZeroValueJsonString, reflect.TypeOf(requiredNestedOptionalPointerFieldStruct), "")
+	CheckValidation(t, "OptionalNestedPointers.S", nonZeroValueJsonString, reflect.TypeOf(requiredNestedPointerOptionalPointerFieldStruct), "")
+	CheckValidation(t, "OptionalNestedPointers.T", nonZeroValueJsonString, reflect.TypeOf(notNilNestedPointerOptionalPointerFieldStruct), "")
+
+	// ****************************************************************************************************
+	// 	Structs with required nested pointer fields - Checked
+	// ****************************************************************************************************
+	var optionalNestedRequiredPointerFieldStruct OptionalNestedRequiredPointerFieldStruct
+	var optionalNestedPointerRequiredPointerFieldStruct OptionalNestedPointerRequiredPointerFieldStruct
+	var requiredNestedRequiredPointerFieldStruct RequiredNestedRequiredPointerFieldStruct
+	var requiredNestedPointerRequiredPointerFieldStruct RequiredNestedPointerRequiredPointerFieldStruct
+	var notNilNestedPointerRequiredPointerFieldStruct NotNilNestedPointerRequiredPointerFieldStruct
+
+	// Empty json string
+	emptyJsonString = `{}`
+	CheckValidation(t, "RequiredNestedPointers.A", emptyJsonString, reflect.TypeOf(optionalNestedRequiredPointerFieldStruct), "")
+	CheckValidation(t, "RequiredNestedPointers.B", emptyJsonString, reflect.TypeOf(optionalNestedPointerRequiredPointerFieldStruct), "")
+	CheckValidation(t, "RequiredNestedPointers.C", emptyJsonString, reflect.TypeOf(requiredNestedRequiredPointerFieldStruct), "required_field_nested is required")
+	CheckValidation(t, "RequiredNestedPointers.D", emptyJsonString, reflect.TypeOf(requiredNestedPointerRequiredPointerFieldStruct), "required_field_nested is required")
+	CheckValidation(t, "RequiredNestedPointers.E", emptyJsonString, reflect.TypeOf(notNilNestedPointerRequiredPointerFieldStruct), "required_field_nested is required")
+
+	// Json string with zero value
+	zeroValueJsonString = `{"required_field_nested": {}}`
+	CheckValidation(t, "RequiredNestedPointers.F", zeroValueJsonString, reflect.TypeOf(optionalNestedRequiredPointerFieldStruct), "")
+	CheckValidation(t, "RequiredNestedPointers.G", zeroValueJsonString, reflect.TypeOf(optionalNestedPointerRequiredPointerFieldStruct), "")
+	CheckValidation(t, "RequiredNestedPointers.H", zeroValueJsonString, reflect.TypeOf(requiredNestedRequiredPointerFieldStruct), "required_field_nested is required")
+	CheckValidation(t, "RequiredNestedPointers.I", zeroValueJsonString, reflect.TypeOf(requiredNestedPointerRequiredPointerFieldStruct), "required_field_nested is required")
+	CheckValidation(t, "RequiredNestedPointers.J", zeroValueJsonString, reflect.TypeOf(notNilNestedPointerRequiredPointerFieldStruct), "")
+
+	// Json string with non-nil pointer value
+	nonZeroValueJsonString = `{"required_field_nested": {"pointer_field": ""}}`
+	CheckValidation(t, "RequiredNestedPointers.K", nonZeroValueJsonString, reflect.TypeOf(optionalNestedRequiredPointerFieldStruct), "")
+	CheckValidation(t, "RequiredNestedPointers.L", nonZeroValueJsonString, reflect.TypeOf(optionalNestedPointerRequiredPointerFieldStruct), "")
+	CheckValidation(t, "RequiredNestedPointers.M", nonZeroValueJsonString, reflect.TypeOf(requiredNestedRequiredPointerFieldStruct), "")
+	CheckValidation(t, "RequiredNestedPointers.N", nonZeroValueJsonString, reflect.TypeOf(requiredNestedPointerRequiredPointerFieldStruct), "")
+	CheckValidation(t, "RequiredNestedPointers.O", nonZeroValueJsonString, reflect.TypeOf(notNilNestedPointerRequiredPointerFieldStruct), "")
+
+	// Json string with non-zero value
+	nonZeroValueJsonString = `{"required_field_nested": {"pointer_field": "value"}}`
+	CheckValidation(t, "RequiredNestedPointers.P", nonZeroValueJsonString, reflect.TypeOf(optionalNestedRequiredPointerFieldStruct), "")
+	CheckValidation(t, "RequiredNestedPointers.Q", nonZeroValueJsonString, reflect.TypeOf(optionalNestedPointerRequiredPointerFieldStruct), "")
+	CheckValidation(t, "RequiredNestedPointers.R", nonZeroValueJsonString, reflect.TypeOf(requiredNestedRequiredPointerFieldStruct), "")
+	CheckValidation(t, "RequiredNestedPointers.S", nonZeroValueJsonString, reflect.TypeOf(requiredNestedPointerRequiredPointerFieldStruct), "")
+	CheckValidation(t, "RequiredNestedPointers.T", nonZeroValueJsonString, reflect.TypeOf(notNilNestedPointerRequiredPointerFieldStruct), "")
+
+	// ****************************************************************************************************
+	// 	Deep test - Checked
+	// ****************************************************************************************************
+	var optionalNestedDeepRequiredDeepFieldStruct OptionalNestedDeepRequiredDeepFieldStruct
+	var optionalNestedPointerDeepRequiredDeepFieldPointerStruct OptionalNestedPointerDeepRequiredDeepFieldPointerStruct
+	var requiredNestedDeepRequiredDeepFieldStruct RequiredNestedDeepRequiredDeepFieldStruct
+	var requiredNestedPointerDeepRequiredDeepFieldStruct RequiredNestedPointerDeepRequiredDeepFieldStruct
+	var notNilNestedPointerRequiredDeepFieldStruct NotNilNestedPointerRequiredDeepFieldStruct
+	var notNilNestedPointerDeepRequiredDeepFieldStruct NotNilNestedPointerDeepRequiredDeepFieldStruct
+
+	// Empty json string
+	emptyJsonString = `{}`
+	CheckValidation(t, "Deep.A", emptyJsonString, reflect.TypeOf(optionalNestedDeepRequiredDeepFieldStruct), "deep_field_nested.required_field is required")
+	CheckValidation(t, "Deep.B", emptyJsonString, reflect.TypeOf(optionalNestedPointerDeepRequiredDeepFieldPointerStruct), "")
+	CheckValidation(t, "Deep.C", emptyJsonString, reflect.TypeOf(requiredNestedDeepRequiredDeepFieldStruct), "deep_field_nested is required")
+	CheckValidation(t, "Deep.D", emptyJsonString, reflect.TypeOf(requiredNestedPointerDeepRequiredDeepFieldStruct), "deep_field_nested is required")
+	CheckValidation(t, "Deep.E", emptyJsonString, reflect.TypeOf(notNilNestedPointerRequiredDeepFieldStruct), "deep_field_nested is required")
+	CheckValidation(t, "Deep.F", emptyJsonString, reflect.TypeOf(notNilNestedPointerDeepRequiredDeepFieldStruct), "deep_field_nested is required")
+
+	// Json string with zero value
+	zeroValueJsonString = `{"deep_field_nested": {}}`
+	CheckValidation(t, "Deep.G", zeroValueJsonString, reflect.TypeOf(optionalNestedDeepRequiredDeepFieldStruct), "deep_field_nested.required_field is required")
+	CheckValidation(t, "Deep.H", zeroValueJsonString, reflect.TypeOf(optionalNestedPointerDeepRequiredDeepFieldPointerStruct), "deep_field_nested.required_field is required")
+	CheckValidation(t, "Deep.I", zeroValueJsonString, reflect.TypeOf(requiredNestedDeepRequiredDeepFieldStruct), "deep_field_nested is required")
+	CheckValidation(t, "Deep.J", zeroValueJsonString, reflect.TypeOf(requiredNestedPointerDeepRequiredDeepFieldStruct), "deep_field_nested is required")
+	CheckValidation(t, "Deep.K", zeroValueJsonString, reflect.TypeOf(notNilNestedPointerRequiredDeepFieldStruct), "")
+	CheckValidation(t, "Deep.L", zeroValueJsonString, reflect.TypeOf(notNilNestedPointerDeepRequiredDeepFieldStruct), "deep_field_nested.required_field is required")
+
+	// Json string with non-zero optional value
+	nonZeroValueJsonString = `{"deep_field_nested": {"optional_field": "value"}}`
+	CheckValidation(t, "Deep.M", nonZeroValueJsonString, reflect.TypeOf(optionalNestedDeepRequiredDeepFieldStruct), "deep_field_nested.required_field is required")
+	CheckValidation(t, "Deep.N", nonZeroValueJsonString, reflect.TypeOf(optionalNestedPointerDeepRequiredDeepFieldPointerStruct), "deep_field_nested.required_field is required")
+	CheckValidation(t, "Deep.O", nonZeroValueJsonString, reflect.TypeOf(requiredNestedDeepRequiredDeepFieldStruct), "deep_field_nested.required_field is required")
+	CheckValidation(t, "Deep.P", nonZeroValueJsonString, reflect.TypeOf(requiredNestedPointerDeepRequiredDeepFieldStruct), "deep_field_nested.required_field is required")
+	CheckValidation(t, "Deep.Q", nonZeroValueJsonString, reflect.TypeOf(notNilNestedPointerRequiredDeepFieldStruct), "")
+	CheckValidation(t, "Deep.R", nonZeroValueJsonString, reflect.TypeOf(notNilNestedPointerDeepRequiredDeepFieldStruct), "deep_field_nested.required_field is required")
+
+	// Json string with non-zero required value
+	nonZeroValueJsonString = `{"deep_field_nested": {"required_field": "value"}}`
+	CheckValidation(t, "Deep.S", nonZeroValueJsonString, reflect.TypeOf(optionalNestedDeepRequiredDeepFieldStruct), "")
+	CheckValidation(t, "Deep.T", nonZeroValueJsonString, reflect.TypeOf(optionalNestedPointerDeepRequiredDeepFieldPointerStruct), "")
+	CheckValidation(t, "Deep.U", nonZeroValueJsonString, reflect.TypeOf(requiredNestedDeepRequiredDeepFieldStruct), "")
+	CheckValidation(t, "Deep.V", nonZeroValueJsonString, reflect.TypeOf(requiredNestedPointerDeepRequiredDeepFieldStruct), "")
+	CheckValidation(t, "Deep.W", nonZeroValueJsonString, reflect.TypeOf(notNilNestedPointerRequiredDeepFieldStruct), "")
+	CheckValidation(t, "Deep.X", nonZeroValueJsonString, reflect.TypeOf(notNilNestedPointerDeepRequiredDeepFieldStruct), "")
+
+	// ****************************************************************************************************
+	// 	Complex test
+	// ****************************************************************************************************
+	var complexParentStruct ComplexParentStruct
+
+	// This test will gradually fix errors until all required fields are filled
+
+	// Empty json string
+	emptyJsonString = `{}`
+	CheckValidation(t, "Complex.A", emptyJsonString, reflect.TypeOf(complexParentStruct), "required_field is required")
+
+	// required_field is filled
+	nonZeroValueJsonString = `{"required_field": "value"}`
+	CheckValidation(t, "Complex.B", nonZeroValueJsonString, reflect.TypeOf(complexParentStruct), "required_complex_child_struct_slice is required")
+
+	// previous fields filled, and required_complex_child_struct_slice is present, but empty
+	zeroValueJsonString = `{"required_field": "value", "required_complex_child_struct_slice": []}`
+	CheckValidation(t, "Complex.C", zeroValueJsonString, reflect.TypeOf(complexParentStruct), "required_complex_child_struct_slice may not be empty")
+
+	// previous fields filled, and required_complex_child_struct_slice with one empty object
+	zeroValueJsonString = `{"required_field": "value", "required_complex_child_struct_slice": [{}]}`
+	CheckValidation(t, "Complex.D", zeroValueJsonString, reflect.TypeOf(complexParentStruct), "required_complex_child_struct_slice.required_field is required")
+
+	// previous fields filled, and required_complex_child_struct_slice with one object with required_field filled
+	nonZeroValueJsonString = `{"required_field": "value", "required_complex_child_struct_slice": [{"required_field": "value"}]}`
+	CheckValidation(t, "Complex.E", nonZeroValueJsonString, reflect.TypeOf(complexParentStruct), "required_complex_child_struct_slice.required_slice_field is required")
+
+	// previous fields filled, and required_complex_child_struct_slice with one object with required_field and required_slice_field present
+	zeroValueJsonString = `{"required_field": "value", "required_complex_child_struct_slice": [{"required_field": "value", "required_slice_field": []}]}`
+	CheckValidation(t, "Complex.F", zeroValueJsonString, reflect.TypeOf(complexParentStruct), "required_complex_child_struct_slice.optional_deep_field_struct is required")
+
+	// previous fields filled, and required_complex_child_struct_slice with one object with required_field, required_slice_field and optional_deep_field_struct present
+	nonZeroValueJsonString = `{"required_field": "value", "required_complex_child_struct_slice": [{"required_field": "value", "required_slice_field": [], "optional_deep_field_struct": {}}]}`
+	CheckValidation(t, "Complex.G", nonZeroValueJsonString, reflect.TypeOf(complexParentStruct), "required_complex_child_struct_slice.optional_deep_field_struct.required_field is required")
+
+	// previous fields filled, and required_complex_child_struct_slice with one object with required_field, required_slice_field, optional_deep_field_struct and required_field present
+	nonZeroValueJsonString = `{"required_field": "value", "required_complex_child_struct_slice": [{"required_field": "value", "required_slice_field": [], "optional_deep_field_struct": {"required_field": "value"}}]}`
+	CheckValidation(t, "Complex.H", nonZeroValueJsonString, reflect.TypeOf(complexParentStruct), "non_nil_complex_child_struct_slice is required")
+
+	// previous fields filled, and not_nil_complex_child_struct_slice is present, but empty
+	zeroValueJsonString = `{"required_field": "value", "required_complex_child_struct_slice": [{"required_field": "value", "required_slice_field": [], "optional_deep_field_struct": {"required_field": "value"}}], "non_nil_complex_child_struct_slice": []}`
+	CheckValidation(t, "Complex.I", zeroValueJsonString, reflect.TypeOf(complexParentStruct), "")
+
+	// previous fields filled, and deep_complex_child_struct_slice is present, but empty
+	zeroValueJsonString = `{"required_field": "value", "required_complex_child_struct_slice": [{"required_field": "value", "required_slice_field": [], "optional_deep_field_struct": {"required_field": "value"}}], "non_nil_complex_child_struct_slice": [], "deep_complex_child_struct_slice": []}`
+	CheckValidation(t, "Complex.J", zeroValueJsonString, reflect.TypeOf(complexParentStruct), "")
+
+	// previous fields filled, and deep_complex_child_struct_slice is present with one empty object
+	zeroValueJsonString = `{"required_field": "value", "required_complex_child_struct_slice": [{"required_field": "value", "required_slice_field": [], "optional_deep_field_struct": {"required_field": "value"}}], "non_nil_complex_child_struct_slice": [], "deep_required_deep_field_struct_slice": [{}]}`
+	CheckValidation(t, "Complex.K", zeroValueJsonString, reflect.TypeOf(complexParentStruct), "deep_required_deep_field_struct_slice.required_field is required")
+
+	// previous fields filled, and deep_complex_child_struct_slice is present with one object with required_field filled, and one without
+	zeroValueJsonString = `{"required_field": "value", "required_complex_child_struct_slice": [{"required_field": "value", "required_slice_field": [], "optional_deep_field_struct": {"required_field": "value"}}], "non_nil_complex_child_struct_slice": [], "deep_required_deep_field_struct_slice": [{"required_field": "value"}, {"optional_field": "value"}]}`
+	CheckValidation(t, "Complex.L", zeroValueJsonString, reflect.TypeOf(complexParentStruct), "deep_required_deep_field_struct_slice.required_field is required")
+
+	// previous fields filled, and optional_complex_child_struct is present, but empty
+	zeroValueJsonString = `{"required_field": "value", "required_complex_child_struct_slice": [{"required_field": "value", "required_slice_field": [], "optional_deep_field_struct": {"required_field": "value"}}], "non_nil_complex_child_struct_slice": [], "optional_complex_child_struct": {}}`
+	CheckValidation(t, "Complex.M", zeroValueJsonString, reflect.TypeOf(complexParentStruct), "optional_complex_child_struct.required_field is required")
+
+	// ****************************************************************************************************
+	// 	Embed test
+	// ****************************************************************************************************
+	var optionalEmbedFieldStruct OptionalEmbedFieldStruct
+	var requiredEmbedFieldStruct RequiredEmbedFieldStruct
+	var multiRequiredEmbedFieldStruct MultiRequiredEmbedFieldStruct
+
+	// Empty json string
+	emptyJsonString = `{}`
+	CheckValidation(t, "Embed.A", emptyJsonString, reflect.TypeOf(optionalEmbedFieldStruct), "")
+	CheckValidation(t, "Embed.B", emptyJsonString, reflect.TypeOf(requiredEmbedFieldStruct), "field is required")
+	CheckValidation(t, "Embed.C", emptyJsonString, reflect.TypeOf(multiRequiredEmbedFieldStruct), "field is required")
+
+	// Json string with zero value
+	zeroValueJsonString = `{"field":""}`
+	CheckValidation(t, "Embed.D", zeroValueJsonString, reflect.TypeOf(optionalEmbedFieldStruct), "")
+	CheckValidation(t, "Embed.E", zeroValueJsonString, reflect.TypeOf(requiredEmbedFieldStruct), "field is required")
+	CheckValidation(t, "Embed.F", zeroValueJsonString, reflect.TypeOf(multiRequiredEmbedFieldStruct), "field is required")
+
+	// Json string with non-zero value
+	nonZeroValueJsonString = `{"field":"value"}`
+	CheckValidation(t, "Embed.G", nonZeroValueJsonString, reflect.TypeOf(optionalEmbedFieldStruct), "")
+	CheckValidation(t, "Embed.H", nonZeroValueJsonString, reflect.TypeOf(requiredEmbedFieldStruct), "")
+	CheckValidation(t, "Embed.I", nonZeroValueJsonString, reflect.TypeOf(multiRequiredEmbedFieldStruct), "")
+}
+
+func CheckValidation(t *testing.T, testNumber string, jsonString string, objectType reflect.Type, expectedResult string) {
+	objectValuePtr := reflect.New(objectType)
+	err := json.Unmarshal([]byte(jsonString), objectValuePtr.Interface())
+	if err != nil {
+		panic(errors.Errorf("Error unmarshalling json string for test %s: %s", testNumber, err.Error()))
+	}
+
+	err = ValidateRequiredFields(objectValuePtr.Interface())
+	if expectedResult == "" {
+		if err != nil {
+			fmt.Printf("%#v\n", objectValuePtr.Interface())
+			t.Errorf("%s: Expected no error, got %s", testNumber, err)
+		}
+	} else {
+		if err == nil {
+			fmt.Printf("%#v\n", objectValuePtr.Interface())
+			t.Errorf("%s: Expected error, got nil", testNumber)
+		}
+		if err != nil && err.Error() != expectedResult {
+			fmt.Printf("%#v\n", objectValuePtr.Interface())
+			t.Errorf("%s: Expected error %s, got %s", testNumber, expectedResult, err.Error())
+		}
+	}
+}
diff --git a/struct_utils/struct_utils.go b/struct_utils/struct_utils.go
index 1f25d4387f057ba2f466d12301d7f1f202382ef6..30a16412d1095447140ee62eab055aaac8751c21 100644
--- a/struct_utils/struct_utils.go
+++ b/struct_utils/struct_utils.go
@@ -1,6 +1,11 @@
 package struct_utils
 
-import "strings"
+import (
+	"github.com/samber/lo"
+	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/errors"
+	"reflect"
+	"strings"
+)
 
 // KeyValuePair defines a key/value pair derived from form data
 type KeyValuePair struct {
@@ -46,3 +51,179 @@ func GetValue(key string, kv []KeyValuePair) string {
 
 	return ""
 }
+
+// ValidateRequiredFields checks the required tag on struct fields and returns an error if any are set to zero.
+func ValidateRequiredFields(object any, parentFieldKeys ...string) error {
+	objectValue := reflect.ValueOf(object)
+
+	if objectValue.Kind() == reflect.Interface {
+		objectValue = objectValue.Elem()
+	}
+
+	if objectValue.Kind() == reflect.Ptr {
+		objectValue = objectValue.Elem()
+	}
+
+	if objectValue.Kind() != reflect.Struct {
+		if objectValue.IsZero() {
+			errorKey := strings.Join(parentFieldKeys, ".")
+			return errors.Error(errorKey + " is required")
+		}
+		return nil
+	}
+
+	for i := 0; i < objectValue.NumField(); i++ {
+		field := objectValue.Field(i)
+		fieldType := objectValue.Type().Field(i)
+		requiredTag := fieldType.Tag.Get("required")
+		requiredOptions := strings.Split(requiredTag, ",")
+		required := lo.Contains(requiredOptions, "true")
+		notNil := lo.Contains(requiredOptions, "not-nil")
+		deep := lo.Contains(requiredOptions, "deep")
+
+		thisFieldKey := getRequiredKey(fieldType)
+		err := validateFieldByKind(field, required, notNil, deep, thisFieldKey, parentFieldKeys...)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func validateFieldByKind(field reflect.Value, required bool, notNil bool, deep bool, thisFieldKey string, parentFieldKeys ...string) error {
+	switch field.Kind() {
+	case reflect.Struct:
+		if required &&
+			field.IsZero() {
+			return errors.Error(getErrorKey(thisFieldKey, parentFieldKeys) + " is required")
+		}
+
+		if deep {
+			parentFieldKeys = append(parentFieldKeys, thisFieldKey)
+			err := ValidateRequiredFields(field.Interface(), parentFieldKeys...)
+			if err != nil {
+				return err
+			}
+		}
+	case reflect.Slice:
+		if (required || notNil) &&
+			field.IsZero() {
+			return errors.Error(getErrorKey(thisFieldKey, parentFieldKeys) + " is required")
+		}
+
+		if required &&
+			field.Len() == 0 {
+			return errors.Error(getErrorKey(thisFieldKey, parentFieldKeys) + " may not be empty")
+		}
+
+		if deep {
+			for j := 0; j < field.Len(); j++ {
+				sliceField := field.Index(j)
+				if sliceField.Kind() == reflect.Ptr {
+					sliceField = sliceField.Elem()
+				}
+
+				if sliceField.Kind() == reflect.Struct {
+					err := ValidateRequiredFields(sliceField.Interface(), append(parentFieldKeys, thisFieldKey)...)
+					if err != nil {
+						return err
+					}
+				} else {
+					err := validateFieldByKind(sliceField, true, notNil, deep, thisFieldKey, parentFieldKeys...)
+					if err != nil {
+						return err
+					}
+				}
+			}
+		}
+	case reflect.Map:
+		if (required || notNil) &&
+			field.IsZero() {
+			return errors.Error(getErrorKey(thisFieldKey, parentFieldKeys) + " is required")
+		}
+
+		if required &&
+			field.Len() == 0 {
+			return errors.Error(getErrorKey(thisFieldKey, parentFieldKeys) + " may not be empty")
+		}
+
+		if deep {
+			for _, key := range field.MapKeys() {
+				mapField := field.MapIndex(key)
+				if mapField.Kind() == reflect.Ptr {
+					mapField = mapField.Elem()
+				}
+
+				if mapField.Kind() == reflect.Struct {
+					err := ValidateRequiredFields(mapField.Interface(), append(parentFieldKeys, thisFieldKey)...)
+					if err != nil {
+						return err
+					}
+				} else {
+					err := validateFieldByKind(mapField, required, notNil, deep, thisFieldKey, parentFieldKeys...)
+					if err != nil {
+						return err
+					}
+				}
+			}
+		}
+	case reflect.Ptr:
+		if (required || notNil) &&
+			field.IsZero() {
+			return errors.Error(getErrorKey(thisFieldKey, parentFieldKeys) + " is required")
+		}
+
+		if field.Elem().Kind() == reflect.Struct {
+			if required &&
+				field.Elem().IsZero() {
+				return errors.Error(getErrorKey(thisFieldKey, parentFieldKeys) + " is required")
+			}
+
+			if deep {
+				parentFieldKeys = append(parentFieldKeys, thisFieldKey)
+				err := ValidateRequiredFields(field.Interface(), parentFieldKeys...)
+				if err != nil {
+					return err
+				}
+			}
+		} else if required {
+			return validateFieldByKind(field.Elem(), required, notNil, deep, thisFieldKey, parentFieldKeys...)
+		}
+	default:
+		if required &&
+			field.IsZero() {
+			return errors.Error(getErrorKey(thisFieldKey, parentFieldKeys) + " is required")
+		}
+	}
+
+	return nil
+}
+
+func getRequiredKey(fieldType reflect.StructField) string {
+	if fieldType.Anonymous {
+		return ""
+	}
+
+	jsonTag := fieldType.Tag.Get("json")
+	if jsonTag != "" && jsonTag != "-" {
+		commaIdx := strings.Index(jsonTag, ",")
+		if commaIdx > 0 {
+			// Tag is in the format "key,omitempty"
+			return jsonTag[:commaIdx]
+		} else {
+			return jsonTag
+		}
+	}
+
+	return fieldType.Name
+}
+
+func getErrorKey(thisKey string, parentKeys []string) string {
+	parentKeys = append(parentKeys, thisKey)
+	parentKeys = lo.Filter(parentKeys, func(key string, _ int) bool {
+		return key != ""
+	})
+
+	return strings.Join(parentKeys, ".")
+}