Skip to content

Commit

Permalink
enhance schema source
Browse files Browse the repository at this point in the history
  • Loading branch information
agungdwiprasetyo committed Jun 19, 2024
1 parent 0b5f83c commit 01e55d1
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 52 deletions.
30 changes: 29 additions & 1 deletion candihelper/file_loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ package candihelper

import (
"bytes"
"io/fs"
"os"
"path/filepath"
"strings"
)

// LoadAllFile from path
func LoadAllFile(path, formatFile string) []byte {
var buff bytes.Buffer
buff := bytes.NewBuffer(make([]byte, 128))
buff.Reset()
filepath.Walk(path, func(p string, info os.FileInfo, err error) error {
if err != nil {
panic(err)
Expand All @@ -31,3 +33,29 @@ func LoadAllFile(path, formatFile string) []byte {

return buff.Bytes()
}

// LoadAllFileFromFS helper for load all file from file system
func LoadAllFileFromFS(fileSystem fs.FS, sourcePath, formatFile string) []byte {
buff := bytes.NewBuffer(make([]byte, 128))
buff.Reset()
fs.WalkDir(fileSystem, sourcePath, func(path string, info fs.DirEntry, err error) error {
if err != nil {
panic(err)
}
if info.IsDir() {
return nil
}

fileName := info.Name()
if strings.HasSuffix(fileName, formatFile) {
s, err := fs.ReadFile(fileSystem, path)
if err != nil {
panic(err)
}
buff.Write(s)
}
return nil
})

return buff.Bytes()
}
1 change: 1 addition & 0 deletions codebase/app/cron_worker/cron_worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ func (c *cronWorker) processJob(job *Job) {
trace.Finish(tracer.FinishWithError(err))
}()

trace.SetTag("cron_expr", job.Interval)
trace.SetTag("job_name", job.HandlerName)
trace.Log("job_param", job.Params)

Expand Down
11 changes: 7 additions & 4 deletions codebase/app/graphql_server/graphql_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ type Handler interface {

// ConstructHandlerFromService for create public graphql handler (maybe inject to rest handler)
func ConstructHandlerFromService(service factory.ServiceFactory, opt Option) Handler {
gqlSchema := candihelper.LoadAllFile(os.Getenv(candihelper.WORKDIR)+"api/graphql", ".graphql")
if len(opt.schemaSource) == 0 {
opt.schemaSource = candihelper.LoadAllFile(os.Getenv(candihelper.WORKDIR)+"api/graphql", ".graphql")
}
var resolver rootResolver

if opt.rootResolver == nil {
Expand All @@ -54,7 +56,7 @@ func ConstructHandlerFromService(service factory.ServiceFactory, opt Option) Han
subscriptionResolverValues[rootName] = subscription

if schema := resolverModule.Schema(); schema != "" {
gqlSchema = append(gqlSchema, schema+"\n"...)
opt.schemaSource = append(opt.schemaSource, schema+"\n"...)
}
}
}
Expand All @@ -64,7 +66,7 @@ func ConstructHandlerFromService(service factory.ServiceFactory, opt Option) Han
rootSubscription: constructStruct(subscriptionResolverFields, subscriptionResolverValues),
}
} else {
gqlSchema = append(gqlSchema, opt.rootResolver.Schema()+"\n"...)
opt.schemaSource = append(opt.schemaSource, opt.rootResolver.Schema()+"\n"...)
resolver = rootResolver{
rootQuery: opt.rootResolver.Query(),
rootMutation: opt.rootResolver.Mutation(),
Expand Down Expand Up @@ -99,7 +101,7 @@ func ConstructHandlerFromService(service factory.ServiceFactory, opt Option) Han
logger.LogYellow(fmt.Sprintf("[GraphQL] voyager\t\t\t: http://127.0.0.1:%d%s/voyager", opt.httpPort, opt.RootPath))

return &handlerImpl{
schema: graphql.MustParseSchema((string(gqlSchema)), &resolver, schemaOpts...),
schema: graphql.MustParseSchema(string(opt.schemaSource), &resolver, schemaOpts...),
option: opt,
}
}
Expand All @@ -109,6 +111,7 @@ type handlerImpl struct {
option Option
}

// NewHandler init new graphql http handler
func NewHandler(schema *graphql.Schema, opt Option) Handler {
return &handlerImpl{
schema: schema,
Expand Down
1 change: 0 additions & 1 deletion codebase/app/graphql_server/graphql_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ type graphqlServer struct {

// NewServer create new GraphQL server
func NewServer(service factory.ServiceFactory, opts ...OptionFunc) factory.AppServerFactory {

httpEngine := new(http.Server)
server := &graphqlServer{
httpEngine: httpEngine,
Expand Down
8 changes: 8 additions & 0 deletions codebase/app/graphql_server/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type (
rootResolver interfaces.GraphQLHandler
directiveFuncs map[string]types.DirectiveFunc
tlsConfig *tls.Config
schemaSource []byte
}

// OptionFunc type
Expand Down Expand Up @@ -115,3 +116,10 @@ func SetTLSConfig(tlsConfig *tls.Config) OptionFunc {
o.tlsConfig = tlsConfig
}
}

// SetSchemaSource option func
func SetSchemaSource(schema []byte) OptionFunc {
return func(o *Option) {
o.schemaSource = schema
}
}
34 changes: 15 additions & 19 deletions validator/json_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,35 @@ import (
"github.com/golangid/gojsonschema"
)

// JSONSchemaValidator abstraction
type JSONSchemaValidator interface {
ValidateDocument(schemaID string, documentSource interface{}) error
}

// JSONSchemaValidatorOptionFunc type
type JSONSchemaValidatorOptionFunc func(*jsonSchemaValidator)
type JSONSchemaValidatorOptionFunc func(*JSONSchemaValidator)

// SetSchemaStorageJSONSchemaValidatorOption option func
func SetSchemaStorageJSONSchemaValidatorOption(s Storage) JSONSchemaValidatorOptionFunc {
return func(v *jsonSchemaValidator) {
v.schemaStorage = s
return func(v *JSONSchemaValidator) {
v.SchemaStorage = s
}
}

// AddHideErrorListTypeJSONSchemaValidatorOption option func
func AddHideErrorListTypeJSONSchemaValidatorOption(descType ...string) JSONSchemaValidatorOptionFunc {
return func(v *jsonSchemaValidator) {
return func(v *JSONSchemaValidator) {
for _, e := range descType {
v.notShowErrorListType[e] = struct{}{}
}
}
}

// jsonSchemaValidator validator
type jsonSchemaValidator struct {
schemaStorage Storage
// JSONSchemaValidator validator
type JSONSchemaValidator struct {
SchemaStorage Storage
notShowErrorListType map[string]struct{}
}

// NewJSONSchemaValidator constructor
func NewJSONSchemaValidator(opts ...JSONSchemaValidatorOptionFunc) JSONSchemaValidator {
v := &jsonSchemaValidator{
schemaStorage: NewInMemStorage(os.Getenv(candihelper.WORKDIR) + "api/jsonschema"),
func NewJSONSchemaValidator(opts ...JSONSchemaValidatorOptionFunc) *JSONSchemaValidator {
v := &JSONSchemaValidator{
SchemaStorage: NewInMemStorage(os.Getenv(candihelper.WORKDIR) + "api/jsonschema"),
notShowErrorListType: map[string]struct{}{
"condition_else": {}, "condition_then": {},
},
Expand All @@ -57,11 +52,12 @@ func NewJSONSchemaValidator(opts ...JSONSchemaValidatorOptionFunc) JSONSchemaVal
}

// ValidateDocument based on schema id
func (v *jsonSchemaValidator) ValidateDocument(schemaSource string, documentSource interface{}) error {
s, err := v.schemaStorage.Get(schemaSource)
if err == nil {
schemaSource = strings.ReplaceAll(s, "{{WORKDIR}}", os.Getenv(candihelper.WORKDIR))
func (v *JSONSchemaValidator) ValidateDocument(schemaSource string, documentSource interface{}) error {
s, err := v.SchemaStorage.Get(schemaSource)
if err != nil {
return err
}
schemaSource = strings.ReplaceAll(s, "{{WORKDIR}}", os.Getenv(candihelper.WORKDIR))

schema, err := gojsonschema.NewSchema(gojsonschema.NewStringLoader(schemaSource))
if err != nil {
Expand Down
61 changes: 61 additions & 0 deletions validator/json_schema_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"database/sql"
"encoding/json"
"fmt"
"io/fs"
"log"
"os"
"path/filepath"
"strings"
Expand All @@ -24,6 +26,11 @@ type (
storage map[string]string
}

fsStorage struct {
sourceMap map[string]string
storage fs.FS
}

sqlStorage struct {
db *sql.DB
}
Expand Down Expand Up @@ -131,3 +138,57 @@ func (i *inMemStorage) Store(schemaID string, schema string) error {
i.storage[schemaID] = schema
return nil
}

// NewFileSystemStorage constructor
func NewFileSystemStorage(fileSystem fs.FS, rootPath string) Storage {
storage := &fsStorage{
sourceMap: make(map[string]string),
storage: fileSystem,
}

fs.WalkDir(fileSystem, rootPath, func(path string, info fs.DirEntry, err error) error {
if err != nil {
log.Panicf("json schema: %s", err.Error())
}
if info.IsDir() {
return nil
}

fileName := info.Name()
if strings.HasSuffix(fileName, ".json") {
s, err := fs.ReadFile(fileSystem, path)
if err != nil {
return fmt.Errorf("%s: %v", fileName, err)
}

var data map[string]interface{}
if err := json.Unmarshal(s, &data); err != nil {
return fmt.Errorf("%s: %v", fileName, err)
}

id, ok := data["$id"].(string)
if !ok {
id = strings.Trim(strings.TrimSuffix(strings.TrimPrefix(path, rootPath), ".json"), "/")
}
storage.sourceMap[id] = path
}
return nil
})

fmt.Println(storage.sourceMap)
return storage
}

func (i *fsStorage) Get(schemaID string) (string, error) {
schemaPath, ok := i.sourceMap[schemaID]
if !ok {
return "", fmt.Errorf("schema '%s' not found", schemaID)
}

s, err := fs.ReadFile(i.storage, schemaPath)
return string(s), err
}

func (i *fsStorage) Store(schemaID string, schema string) error {
return nil
}
29 changes: 12 additions & 17 deletions validator/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,46 @@ import (
"github.com/golangid/candi/candihelper"
)

// StructValidator abstraction
type StructValidator interface {
ValidateStruct(data interface{}) error
}

// StructValidatorOptionFunc type
type StructValidatorOptionFunc func(*structValidator)
type StructValidatorOptionFunc func(*StructValidator)

// SetCoreStructValidatorOption option func
func SetCoreStructValidatorOption(additionalConfigFunc ...func(*validatorengine.Validate)) StructValidatorOptionFunc {
return func(v *structValidator) {
return func(v *StructValidator) {
ve := validatorengine.New()
for _, additionalFunc := range additionalConfigFunc {
additionalFunc(ve)
}
v.validator = ve
v.Validator = ve
}
}

// structValidator struct
type structValidator struct {
validator *validatorengine.Validate
// StructValidator struct
type StructValidator struct {
Validator *validatorengine.Validate
}

// NewStructValidator using go library
// https://github.com/go-playground/validator (all struct tags will be here)
// https://godoc.org/github.com/go-playground/validator (documentation using it)
// NewStructValidator function
func NewStructValidator(opts ...StructValidatorOptionFunc) StructValidator {
func NewStructValidator(opts ...StructValidatorOptionFunc) *StructValidator {
// set struct validator
sv := &structValidator{}
sv := &StructValidator{}
for _, opt := range opts {
opt(sv)
}

if sv.validator == nil {
sv.validator = validatorengine.New()
if sv.Validator == nil {
sv.Validator = validatorengine.New()
}

return sv
}

// ValidateStruct function
func (v *structValidator) ValidateStruct(data interface{}) error {
if err := v.validator.Struct(data); err != nil {
func (v *StructValidator) ValidateStruct(data interface{}) error {
if err := v.Validator.Struct(data); err != nil {
switch errs := err.(type) {
case validatorengine.ValidationErrors:
multiError := candihelper.NewMultiError()
Expand Down
20 changes: 10 additions & 10 deletions validator/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,31 @@ package validator
type OptionFunc func(*Validator)

// SetJSONSchemaValidator option func
func SetJSONSchemaValidator(jsonSchema JSONSchemaValidator) OptionFunc {
func SetJSONSchemaValidator(jsonSchema *JSONSchemaValidator) OptionFunc {
return func(v *Validator) {
v.jsonSchema = jsonSchema
v.JSONSchema = jsonSchema
}
}

// SetStructValidator option func
func SetStructValidator(structValidator StructValidator) OptionFunc {
func SetStructValidator(structValidator *StructValidator) OptionFunc {
return func(v *Validator) {
v.structValidator = structValidator
v.StructValidator = structValidator
}
}

// Validator instance
type Validator struct {
jsonSchema JSONSchemaValidator
structValidator StructValidator
JSONSchema *JSONSchemaValidator
StructValidator *StructValidator
}

// NewValidator constructor, using jsonschema & struct validator (github.com/go-playground/validator),
// jsonschema source file load from "api/jsonschema" directory
func NewValidator(opts ...OptionFunc) *Validator {
v := &Validator{
jsonSchema: NewJSONSchemaValidator(),
structValidator: NewStructValidator(),
JSONSchema: NewJSONSchemaValidator(),
StructValidator: NewStructValidator(),
}

for _, opt := range opts {
Expand All @@ -39,10 +39,10 @@ func NewValidator(opts ...OptionFunc) *Validator {

// ValidateDocument method using jsonschema with input is json source
func (v *Validator) ValidateDocument(reference string, document interface{}) error {
return v.jsonSchema.ValidateDocument(reference, document)
return v.JSONSchema.ValidateDocument(reference, document)
}

// ValidateStruct method, rules from struct tag using github.com/go-playground/validator
func (v *Validator) ValidateStruct(data interface{}) error {
return v.structValidator.ValidateStruct(data)
return v.StructValidator.ValidateStruct(data)
}

0 comments on commit 01e55d1

Please sign in to comment.