-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15 from ashbeelghouri/0.5
0.4
- Loading branch information
Showing
25 changed files
with
1,586 additions
and
824 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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")) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
Oops, something went wrong.