Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.4 #15

Merged
merged 4 commits into from
Jul 1, 2024
Merged

0.4 #15

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 9 additions & 132 deletions Basic_test.go
Original file line number Diff line number Diff line change
@@ -1,149 +1,26 @@
package jsonschematics

import (
"encoding/json"
v2 "github.com/ashbeelghouri/jsonschematics/data/v2"
"github.com/ashbeelghouri/jsonschematics/utils"
"log"
"os"
"testing"
"time"
)

func TestForObjData(t *testing.T) {
fnTimeStart := time.Now()
var schema Schematics
err := schema.LoadSchemaFromFile("json/schema.json")
schema.Logging.PrintErrorLogs = true
schema.Logging.PrintDebugLogs = true
func TestV2Validate(t *testing.T) {
schematics, err := v2.LoadJsonSchemaFile("test-data/schema/direct/v2/example-1.json")
if err != nil {
t.Error(err)
}
data, err := GetJson("json/data.json")
content, err := os.ReadFile("test-data/data/direct/v2/example-2.json")
if err != nil {
t.Error(err)
}
start := time.Now()
errs := schema.Validate(data)
log.Printf("[SINGLE OBJ] Validation Time: %v", time.Since(start))
log.Print("[SINGLE OBJ] have single errors: ", errs.HaveSingleError("", ""))
errorsFromValidate, err := json.Marshal(errs)
if err != nil {
log.Fatalf("err: %v", err)
}
log.Println("[SINGLE OBJ] errorsFromValidate: ", string(errorsFromValidate))
start = time.Now()
newData := schema.Operate(data)
log.Printf("[SINGLE OBJ] Operaions Time: %v", time.Since(start))
log.Printf("[SINGLE OBJ] Updated DATA: %v", newData)

log.Printf("[SINGLE OBJ] total time taken: %v", time.Since(fnTimeStart))
log.Println("-------------------------------------------")
}

func TestForArrayData(t *testing.T) {
fnTimeStart := time.Now()
var schema1 Schematics
schema1.Logging.PrintErrorLogs = true
schema1.Logging.PrintDebugLogs = true
err := schema1.LoadSchemaFromFile("json/schema.json")
schema1.ArrayIdKey = "user.id"
if err != nil {
t.Error(err)
}
data, err := GetJson("json/arr-data.json")
if err != nil {
t.Error(err)
}
start := time.Now()
errs := schema1.Validate(data)
log.Printf("[ARRAY OF OBJ] Validation Time: %v", time.Since(start))
if errs != nil {
obj, err := json.Marshal(errs)
if err != nil {
log.Fatalf("err: %v", err)
}
log.Printf("array validations >>>> %v", string(obj))
} else {
start = time.Now()
newData := schema1.Operate(data)
log.Printf("[ARRAY OF OBJ] Operation Time: %v", time.Since(start))
log.Printf("[ARRAY OF OBJ] Updated Data: %v", newData)
}
log.Printf("[ARRAY OF OBJ] total time taken: %v", time.Since(fnTimeStart))
log.Println("-------------------------------------------")
}

func TestNestedArrays(t *testing.T) {
fnTimeStart := time.Now()
var schema Schematics
schema.Logging.PrintErrorLogs = true
schema.Logging.PrintDebugLogs = true
err := schema.LoadSchemaFromFile("json/arr-inside-obj-schema.json")
jsonData, err := utils.BytesToMap(content)
if err != nil {
t.Error(err)
}
data, err := GetJson("json/arr-inside-obj-data.json")
if err != nil {
t.Error(err)
}
start := time.Now()
errs := schema.Validate(data)
log.Printf("[TestNestedArrays] Validation Time: %v", time.Since(start))
if errs != nil {
jsonErrors, err := json.Marshal(errs)
if err != nil {
log.Fatalf("[TestNestedArrays] err: %v", err)
}
log.Println("[TestNestedArrays] json errors:", string(jsonErrors))
}

start = time.Now()
newData := schema.Operate(data)
log.Printf("[TestNestedArrays] Operation Time: %v", time.Since(start))
log.Println("[TestNestedArrays] after operations:", newData)
log.Println("[TestNestedArrays] total time taken:", time.Since(fnTimeStart))
}

func TestDeepValidationInArray(t *testing.T) {
fnTimeStart := time.Now()
var schema Schematics
schema.Logging.PrintErrorLogs = true
schema.Logging.PrintDebugLogs = true
err := schema.LoadSchemaFromFile("json/arr-inside-obj-schema.json")
if err != nil {
log.Println("[TestDeepValidationInArray] unable to load the schema from json file: ", err)
t.Error(err)
}
data, err := GetJson("json/arr-inside-arr-obj-data.json")
if err != nil {
log.Println("[TestDeepValidationInArray] unable to load the data from json file: ", err)
t.Error(err)
}
start := time.Now()
errs := schema.Validate(data)
log.Printf("[TestDeepValidationInArray] Validation Time: %v", time.Since(start))

if errs != nil {
jsonErrors, err := json.Marshal(errs)
if err != nil {
log.Fatalf("[TestDeepValidationInArray] err: %v", err)
}
log.Println("[TestDeepValidationInArray] json errors:", string(jsonErrors))
}
start = time.Now()
newData := schema.Operate(data)
log.Printf("[TestDeepValidationInArray] Operation Time: %v", time.Since(start))
log.Println("[TestDeepValidationInArray] after operations:", newData)
log.Println("[TestDeepValidationInArray] total time taken:", time.Since(fnTimeStart))
}

func TestSchemaVersioning(t *testing.T) {
fnTimeStart := time.Now()
var schema Schematics
err := schema.LoadSchemaFromFile("json/schema-v1.1.json")
if err != nil {
log.Println("[TestSchemaVersioning] unable to load the schema from json file: ", err)
t.Error(err)
}
log.Println("Schema Version 1.1", schema)

log.Println("[TestSchemaVersioning] total time taken:", time.Since(fnTimeStart))
errs := schematics.Validate(jsonData)
log.Println(errs.GetStrings("en", "%data\n"))
}
47 changes: 47 additions & 0 deletions api/parsers/request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package parsers

import (
"encoding/json"
"github.com/ashbeelghouri/jsonschematics"
"io"
"net/http"
"strings"
)

func ParseRequest(r *http.Request) (map[string]interface{}, error) {
var headers map[string]string
for key, values := range r.Header {
headers[key] = values[0]
}
var body map[string]interface{}
if r.Body != nil {
bodyBytes, err := io.ReadAll(r.Body)
if err != nil {
return nil, err
}
err = json.Unmarshal(bodyBytes, &body)
if err != nil {
return nil, err
}
}
body = jsonschematics.DeflateMap(body, ".")
splitPath := strings.Split(r.RequestURI, "?")
// get query parameters
query := map[string]interface{}{}
if splitPath[1] != "" {
for _, param := range strings.Split(splitPath[1], "&") {
kv := strings.Split(param, "=")
if len(kv) == 2 {
query[kv[0]] = kv[1]
}
}
}
// already in the FLAT mode
return map[string]interface{}{
"headers": headers,
"body": body,
"path": splitPath[0],
"method": r.Method,
"query": query,
}, nil
}
176 changes: 176 additions & 0 deletions api/v0/schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package v0

import (
"github.com/ashbeelghouri/jsonschematics/api/parsers"
jsonschematics "github.com/ashbeelghouri/jsonschematics/data/v0"
"github.com/ashbeelghouri/jsonschematics/errorHandler"
"github.com/ashbeelghouri/jsonschematics/utils"
"net/http"
"regexp"
"strings"
)

type TargetKey string
type EndpointKey string
type Name string

type Field struct {
DependsOn []string
Name string
Type string
Required bool
Validators map[TargetKey]Constant
Operators map[TargetKey]Constant
L10n map[string]interface{}
}

type Constant struct {
Attributes map[string]interface{} `json:"attributes"`
ErrMsg string `json:"error"`
L10n map[string]interface{} `json:"l10n"`
}

type Global struct {
Headers map[TargetKey]Field
}

type Endpoint struct {
Type string
Body map[TargetKey]Field
Headers map[TargetKey]Field
Query map[TargetKey]Field
}

type Schema struct {
Version string
Global Global
Locale string
Logger utils.Logger
Endpoints map[EndpointKey]Endpoint
}

func (s *Schema) GetSchematics(fieldType string, fields *map[TargetKey]Field) (*jsonschematics.Schematics, error) {
var schematics jsonschematics.Schematics
FieldKeys := jsonschematics.Field{
DependsOn: []string{},
Type: fieldType,
Validators: map[string]jsonschematics.Constant{},
Operators: map[string]jsonschematics.Constant{},
}

schema := jsonschematics.Schema{
Version: s.Version,
Fields: make(map[jsonschematics.TargetKey]jsonschematics.Field),
}

for target, f := range *fields {
var allValidators map[string]jsonschematics.Constant

for key, validator := range f.Validators {
allValidators[string(key)] = jsonschematics.Constant{
Attributes: validator.Attributes,
Error: validator.ErrMsg,
L10n: validator.L10n,
}
}
var allOperations map[string]jsonschematics.Constant
for key, operator := range f.Operators {
allOperations[string(key)] = jsonschematics.Constant{
Attributes: operator.Attributes,
Error: operator.ErrMsg,
L10n: operator.L10n,
}
}
FieldKeys.Type = f.Type
FieldKeys.Validators = allValidators
FieldKeys.Operators = allOperations
FieldKeys.L10n = s.Global.Headers[target].L10n
schema.Fields[jsonschematics.TargetKey(target)] = FieldKeys
}

schematics.Schema = schema
return &schematics, nil
}

func (s *Schema) ValidateRequest(r *http.Request) *errorHandler.Errors {
internalErrors := "internal-errors"

var errorMessages errorHandler.Errors
var errMsg errorHandler.Error
errMsg.Validator = "request"
errMsg.Value = "all"
transformedRequest, err := parsers.ParseRequest(r)
if err != nil {
s.Logger.ERROR(err.Error())
errMsg.AddMessage("en", "unable to transform request")
errorMessages.AddError(internalErrors, errMsg)
return &errorMessages
}

globalHeadersSchematics, err := s.GetSchematics("Global Headers", &s.Global.Headers)
if err != nil {
s.Logger.ERROR(err.Error())
errMsg.AddMessage("en", "schema conversion error")
errorMessages.AddError(internalErrors, errMsg)
return &errorMessages
}
errs := globalHeadersSchematics.Validate(transformedRequest["headers"])
if errs.HasErrors() {
s.Logger.ERROR("all errors", err.Error())
return errs
}

for path, endpoint := range s.Endpoints {
regex := utils.GetPathRegex(string(path))
matched, err := regexp.MatchString(regex, transformedRequest["path"].(string))
if err != nil {
errMsg.AddMessage("en", "path not matched - regex not matched")
errorMessages.AddError(internalErrors, errMsg)
return &errorMessages
}
if matched {
s.Logger.DEBUG("url not matched")
return nil
}

if strings.ToLower(endpoint.Type) == strings.ToLower(transformedRequest["method"].(string)) {
headerSchematics, err := s.GetSchematics("Headers", &endpoint.Headers)
if err != nil {
s.Logger.ERROR(err.Error())
errMsg.AddMessage("en", err.Error())
errorMessages.AddError(internalErrors, errMsg)
return &errorMessages
}
errs := headerSchematics.Validate(transformedRequest["headers"])
if errs.HasErrors() {
s.Logger.ERROR("validation errors on headers:", errs.GetStrings("en", "%validator: %message"))
return errs
}
bodySchematics, err := s.GetSchematics("Body", &endpoint.Body)
if err != nil {
s.Logger.ERROR(err.Error())
errMsg.AddMessage("en", err.Error())
errorMessages.AddError(internalErrors, errMsg)
return &errorMessages
}
errs = bodySchematics.Validate(transformedRequest["body"])
if errs.HasErrors() {
s.Logger.ERROR("validation errors on body:", errs.GetStrings("en", "%validator: %message"))
return errs
}
querySchematics, err := s.GetSchematics("Query", &endpoint.Query)
if err != nil {
s.Logger.ERROR(err.Error())
errMsg.AddMessage("en", err.Error())
errorMessages.AddError(internalErrors, errMsg)
return &errorMessages
}
errs = querySchematics.Validate(transformedRequest["query"])
if errs.HasErrors() {
s.Logger.ERROR("validation errors on query:", errs.GetStrings("en", "%validator: %message"))
return errs
}
}
}
return nil
}
Loading