diff --git a/internal/config/config.go b/internal/config/config.go index cc529d0..81b39ad 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -21,12 +21,12 @@ type Server struct { func (srv *Server) Parse(r io.Reader) error { err := json.NewDecoder(r).Decode(&srv.Services) if err != nil { - return fmt.Errorf("%s: %w", errRead, err) + return fmt.Errorf("%s: %w", ErrRead, err) } err = srv.validate() if err != nil { - return fmt.Errorf("%s: %w", errFormat, err) + return fmt.Errorf("%s: %w", ErrFormat, err) } return nil } @@ -41,7 +41,7 @@ func (server Server) validate(datatypes ...validator.Type) error { } if err := server.collide(); err != nil { - return fmt.Errorf("%s: %w", errFormat, err) + return fmt.Errorf("%s: %w", ErrFormat, err) } return nil } @@ -105,14 +105,14 @@ func checkURICollision(uriA, uriB []string, inputA, inputB map[string]*Parameter // both captures -> as we cannot check, consider a collision if aIsCapture && bIsCapture { - errors = append(errors, fmt.Errorf("%w (path %s and %s)", errPatternCollision, aPart, bPart)) + errors = append(errors, fmt.Errorf("%w (path %s and %s)", ErrPatternCollision, aPart, bPart)) continue } // no capture -> check strict equality if !aIsCapture && !bIsCapture { if aPart == bPart { - errors = append(errors, fmt.Errorf("%w (same path '%s')", errPatternCollision, aPart)) + errors = append(errors, fmt.Errorf("%w (same path '%s')", ErrPatternCollision, aPart)) continue } } @@ -123,13 +123,13 @@ func checkURICollision(uriA, uriB []string, inputA, inputB map[string]*Parameter // fail if no type or no validator if !exists || input.Validator == nil { - errors = append(errors, fmt.Errorf("%w (invalid type for %s)", errPatternCollision, aPart)) + errors = append(errors, fmt.Errorf("%w (invalid type for %s)", ErrPatternCollision, aPart)) continue } // fail if not valid if _, valid := input.Validator(bPart); valid { - errors = append(errors, fmt.Errorf("%w (%s captures '%s')", errPatternCollision, aPart, bPart)) + errors = append(errors, fmt.Errorf("%w (%s captures '%s')", ErrPatternCollision, aPart, bPart)) continue } @@ -139,13 +139,13 @@ func checkURICollision(uriA, uriB []string, inputA, inputB map[string]*Parameter // fail if no type or no validator if !exists || input.Validator == nil { - errors = append(errors, fmt.Errorf("%w (invalid type for %s)", errPatternCollision, bPart)) + errors = append(errors, fmt.Errorf("%w (invalid type for %s)", ErrPatternCollision, bPart)) continue } // fail if not valid if _, valid := input.Validator(aPart); valid { - errors = append(errors, fmt.Errorf("%w (%s captures '%s')", errPatternCollision, bPart, aPart)) + errors = append(errors, fmt.Errorf("%w (%s captures '%s')", ErrPatternCollision, bPart, aPart)) continue } } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 5db787c..9d9dd60 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -21,15 +21,15 @@ func TestLegalServiceName(t *testing.T) { // empty { `[ { "method": "GET", "info": "a", "path": "" } ]`, - errInvalidPattern, + ErrInvalidPattern, }, { `[ { "method": "GET", "info": "a", "path": "no-starting-slash" } ]`, - errInvalidPattern, + ErrInvalidPattern, }, { `[ { "method": "GET", "info": "a", "path": "ending-slash/" } ]`, - errInvalidPattern, + ErrInvalidPattern, }, { `[ { "method": "GET", "info": "a", "path": "/" } ]`, @@ -45,35 +45,35 @@ func TestLegalServiceName(t *testing.T) { }, { `[ { "method": "GET", "info": "a", "path": "/invalid/s{braces}" } ]`, - errInvalidPatternBraceCapture, + ErrInvalidPatternBraceCapture, }, { `[ { "method": "GET", "info": "a", "path": "/invalid/{braces}a" } ]`, - errInvalidPatternBraceCapture, + ErrInvalidPatternBraceCapture, }, { `[ { "method": "GET", "info": "a", "path": "/invalid/{braces}" } ]`, - errUndefinedBraceCapture, + ErrUndefinedBraceCapture, }, { `[ { "method": "GET", "info": "a", "path": "/invalid/s{braces}/abc" } ]`, - errInvalidPatternBraceCapture, + ErrInvalidPatternBraceCapture, }, { `[ { "method": "GET", "info": "a", "path": "/invalid/{braces}s/abc" } ]`, - errInvalidPatternBraceCapture, + ErrInvalidPatternBraceCapture, }, { `[ { "method": "GET", "info": "a", "path": "/invalid/{braces}/abc" } ]`, - errUndefinedBraceCapture, + ErrUndefinedBraceCapture, }, { `[ { "method": "GET", "info": "a", "path": "/invalid/{b{races}s/abc" } ]`, - errInvalidPatternBraceCapture, + ErrInvalidPatternBraceCapture, }, { `[ { "method": "GET", "info": "a", "path": "/invalid/{braces}/}abc" } ]`, - errInvalidPatternBraceCapture, + ErrInvalidPatternBraceCapture, }, } @@ -143,8 +143,8 @@ func TestAvailableMethods(t *testing.T) { t.FailNow() } - if !test.ValidMethod && !errors.Is(err, errUnknownMethod) { - t.Errorf("expected error <%s> got <%s>", errUnknownMethod, err) + if !test.ValidMethod && !errors.Is(err, ErrUnknownMethod) { + t.Errorf("expected error <%s> got <%s>", ErrUnknownMethod, err) t.FailNow() } }) @@ -184,7 +184,7 @@ func TestParseMissingMethodDescription(t *testing.T) { `[ { "method": "GET", "path": "/" }]`, false, }, - { // missing description + { // missing descriptiontype `[ { "method": "GET", "path": "/subservice" }]`, false, }, @@ -217,8 +217,8 @@ func TestParseMissingMethodDescription(t *testing.T) { t.FailNow() } - if !test.ValidDescription && !errors.Is(err, errMissingDescription) { - t.Errorf("expected error <%s> got <%s>", errMissingDescription, err) + if !test.ValidDescription && !errors.Is(err, ErrMissingDescription) { + t.Errorf("expected error <%s> got <%s>", ErrMissingDescription, err) t.FailNow() } }) @@ -321,7 +321,7 @@ func TestParseParameters(t *testing.T) { } } ]`, - errMissingParamDesc, + ErrMissingParamDesc, }, { // invalid param name suffix `[ @@ -334,7 +334,7 @@ func TestParseParameters(t *testing.T) { } } ]`, - errMissingParamDesc, + ErrMissingParamDesc, }, { // missing param description @@ -348,7 +348,7 @@ func TestParseParameters(t *testing.T) { } } ]`, - errMissingParamDesc, + ErrMissingParamDesc, }, { // empty param description `[ @@ -361,7 +361,7 @@ func TestParseParameters(t *testing.T) { } } ]`, - errMissingParamDesc, + ErrMissingParamDesc, }, { // missing param type @@ -375,7 +375,7 @@ func TestParseParameters(t *testing.T) { } } ]`, - errMissingParamType, + ErrMissingParamType, }, { // empty param type `[ @@ -388,7 +388,7 @@ func TestParseParameters(t *testing.T) { } } ]`, - errMissingParamType, + ErrMissingParamType, }, { // invalid type (optional mark only) `[ @@ -402,7 +402,7 @@ func TestParseParameters(t *testing.T) { } ]`, - errMissingParamType, + ErrMissingParamType, }, { // valid description + valid type `[ @@ -444,7 +444,7 @@ func TestParseParameters(t *testing.T) { } ]`, // 2 possible errors as map order is not deterministic - errParamNameConflict, + ErrParamNameConflict, }, { // rename conflict with name `[ @@ -459,7 +459,7 @@ func TestParseParameters(t *testing.T) { } ]`, // 2 possible errors as map order is not deterministic - errParamNameConflict, + ErrParamNameConflict, }, { // rename conflict with rename `[ @@ -474,7 +474,7 @@ func TestParseParameters(t *testing.T) { } ]`, // 2 possible errors as map order is not deterministic - errParamNameConflict, + ErrParamNameConflict, }, { // both renamed with no conflict @@ -503,7 +503,7 @@ func TestParseParameters(t *testing.T) { } } ]`, - errMandatoryRename, + ErrMandatoryRename, }, { `[ @@ -516,7 +516,7 @@ func TestParseParameters(t *testing.T) { } } ]`, - errMandatoryRename, + ErrMandatoryRename, }, { `[ @@ -556,7 +556,7 @@ func TestParseParameters(t *testing.T) { } } ]`, - errIllegalOptionalURIParam, + ErrIllegalOptionalURIParam, }, { // URI parameter not specified `[ @@ -569,7 +569,7 @@ func TestParseParameters(t *testing.T) { } } ]`, - errUnspecifiedBraceCapture, + ErrUnspecifiedBraceCapture, }, { // URI parameter not defined `[ @@ -580,7 +580,7 @@ func TestParseParameters(t *testing.T) { "in": { } } ]`, - errUndefinedBraceCapture, + ErrUndefinedBraceCapture, }, } @@ -637,7 +637,7 @@ func TestServiceCollision(t *testing.T) { "info": "info", "in": {} } ]`, - errPatternCollision, + ErrPatternCollision, }, { `[ @@ -672,7 +672,7 @@ func TestServiceCollision(t *testing.T) { } } ]`, - errPatternCollision, + ErrPatternCollision, }, { `[ @@ -698,7 +698,7 @@ func TestServiceCollision(t *testing.T) { } } ]`, - errPatternCollision, + ErrPatternCollision, }, { `[ @@ -711,7 +711,7 @@ func TestServiceCollision(t *testing.T) { } } ]`, - errPatternCollision, + ErrPatternCollision, }, { `[ @@ -750,7 +750,7 @@ func TestServiceCollision(t *testing.T) { } } ]`, - errPatternCollision, + ErrPatternCollision, }, { `[ @@ -789,7 +789,7 @@ func TestServiceCollision(t *testing.T) { } } ]`, - errPatternCollision, + ErrPatternCollision, }, { `[ @@ -804,7 +804,7 @@ func TestServiceCollision(t *testing.T) { } } ]`, - errPatternCollision, + ErrPatternCollision, }, { `[ diff --git a/internal/config/errors.go b/internal/config/errors.go index 91f4997..96fe253 100644 --- a/internal/config/errors.go +++ b/internal/config/errors.go @@ -1,59 +1,61 @@ package config -// cerr allows you to create constant "const" error with type boxing. -type cerr string +// Err allows you to create constant "const" error with type boxing. +type Err string -func (err cerr) Error() string { +func (err Err) Error() string { return string(err) } -// errRead - read error -const errRead = cerr("cannot read config") +const ( + // ErrRead - read error + ErrRead = Err("cannot read config") -// errUnknownMethod - unknown http method -const errUnknownMethod = cerr("unknown HTTP method") + // ErrUnknownMethod - unknown http method + ErrUnknownMethod = Err("unknown HTTP method") -// errFormat - invalid format -const errFormat = cerr("invalid config format") + // ErrFormat - invalid format + ErrFormat = Err("invalid config format") -// errPatternCollision - collision between 2 services' patterns -const errPatternCollision = cerr("pattern collision") + // ErrPatternCollision - collision between 2 services' patterns + ErrPatternCollision = Err("pattern collision") -// errInvalidPattern - malformed service pattern -const errInvalidPattern = cerr("malformed service path: must begin with a '/' and not end with") + // ErrInvalidPattern - malformed service pattern + ErrInvalidPattern = Err("malformed service path: must begin with a '/' and not end with") -// errInvalidPatternBraceCapture - invalid brace capture -const errInvalidPatternBraceCapture = cerr("invalid uri parameter") + // ErrInvalidPatternBraceCapture - invalid brace capture + ErrInvalidPatternBraceCapture = Err("invalid uri parameter") -// errUnspecifiedBraceCapture - missing path brace capture -const errUnspecifiedBraceCapture = cerr("missing uri parameter") + // ErrUnspecifiedBraceCapture - missing path brace capture + ErrUnspecifiedBraceCapture = Err("missing uri parameter") -// errUndefinedBraceCapture - missing capturing brace definition -const errUndefinedBraceCapture = cerr("missing uri parameter definition") + // ErrUndefinedBraceCapture - missing capturing brace definition + ErrUndefinedBraceCapture = Err("missing uri parameter definition") -// errMandatoryRename - capture/query parameters must be renamed -const errMandatoryRename = cerr("uri and query parameters must be renamed") + // ErrMandatoryRename - capture/query parameters must be renamed + ErrMandatoryRename = Err("uri and query parameters must be renamed") -// errMissingDescription - a service is missing its description -const errMissingDescription = cerr("missing description") + // ErrMissingDescription - a service is missing its description + ErrMissingDescription = Err("missing description") -// errIllegalOptionalURIParam - uri parameter cannot optional -const errIllegalOptionalURIParam = cerr("uri parameter cannot be optional") + // ErrIllegalOptionalURIParam - uri parameter cannot optional + ErrIllegalOptionalURIParam = Err("uri parameter cannot be optional") -// errOptionalOption - cannot have optional output -const errOptionalOption = cerr("output cannot be optional") + // ErrOptionalOption - cannot have optional output + ErrOptionalOption = Err("output cannot be optional") -// errMissingParamDesc - missing parameter description -const errMissingParamDesc = cerr("missing parameter description") + // ErrMissingParamDesc - missing parameter description + ErrMissingParamDesc = Err("missing parameter description") -// errUnknownDataType - unknown parameter datatype -const errUnknownDataType = cerr("unknown parameter datatype") + // ErrUnknownParamType - unknown parameter type + ErrUnknownParamType = Err("unknown parameter datatype") -// errIllegalParamName - illegal parameter name -const errIllegalParamName = cerr("illegal parameter name") + // ErrIllegalParamName - illegal parameter name + ErrIllegalParamName = Err("illegal parameter name") -// errMissingParamType - missing parameter type -const errMissingParamType = cerr("missing parameter type") + // ErrMissingParamType - missing parameter type + ErrMissingParamType = Err("missing parameter type") -// errParamNameConflict - name/rename conflict -const errParamNameConflict = cerr("parameter name conflict") + // ErrParamNameConflict - name/rename conflict + ErrParamNameConflict = Err("parameter name conflict") +) diff --git a/internal/config/parameter.go b/internal/config/parameter.go index a22227b..9e13e77 100644 --- a/internal/config/parameter.go +++ b/internal/config/parameter.go @@ -20,11 +20,11 @@ type Parameter struct { func (param *Parameter) validate(datatypes ...validator.Type) error { if len(param.Description) < 1 { - return errMissingParamDesc + return ErrMissingParamDesc } if len(param.Type) < 1 || param.Type == "?" { - return errMissingParamType + return ErrMissingParamType } // optional type @@ -42,7 +42,7 @@ func (param *Parameter) validate(datatypes ...validator.Type) error { } } if param.Validator == nil { - return errUnknownDataType + return ErrUnknownParamType } return nil } diff --git a/internal/config/service.go b/internal/config/service.go index 6d10d27..5349ed8 100644 --- a/internal/config/service.go +++ b/internal/config/service.go @@ -113,7 +113,7 @@ func (svc *Service) validate(datatypes ...validator.Type) error { // check description if len(strings.Trim(svc.Description, " \t\r\n")) < 1 { - return fmt.Errorf("field 'description': %w", errMissingDescription) + return fmt.Errorf("field 'description': %w", ErrMissingDescription) } // check input parameters @@ -125,7 +125,7 @@ func (svc *Service) validate(datatypes ...validator.Type) error { // fail if a brace capture remains undefined for _, capture := range svc.Captures { if capture.Ref == nil { - return fmt.Errorf("field 'in': %s: %w", capture.Name, errUndefinedBraceCapture) + return fmt.Errorf("field 'in': %s: %w", capture.Name, ErrUndefinedBraceCapture) } } @@ -144,7 +144,7 @@ func (svc *Service) isMethodAvailable() error { return nil } } - return errUnknownMethod + return ErrUnknownMethod } func (svc *Service) isPatternValid() error { @@ -152,13 +152,13 @@ func (svc *Service) isPatternValid() error { // empty pattern if length < 1 { - return errInvalidPattern + return ErrInvalidPattern } if length > 1 { // pattern not starting with '/' or ending with '/' if svc.Pattern[0] != '/' || svc.Pattern[length-1] == '/' { - return errInvalidPattern + return ErrInvalidPattern } } @@ -166,7 +166,7 @@ func (svc *Service) isPatternValid() error { parts := SplitURL(svc.Pattern) for i, part := range parts { if len(part) < 1 { - return errInvalidPattern + return ErrInvalidPattern } // if brace capture @@ -187,7 +187,7 @@ func (svc *Service) isPatternValid() error { // fail on invalid format if strings.ContainsAny(part, "{}") { - return errInvalidPatternBraceCapture + return ErrInvalidPatternBraceCapture } } @@ -206,7 +206,7 @@ func (svc *Service) validateInput(types []validator.Type) error { // for each parameter for paramName, param := range svc.Input { if len(paramName) < 1 { - return fmt.Errorf("%s: %w", paramName, errIllegalParamName) + return fmt.Errorf("%s: %w", paramName, ErrIllegalParamName) } // fail if brace capture does not exists in pattern @@ -223,7 +223,7 @@ func (svc *Service) validateInput(types []validator.Type) error { } } if !found { - return fmt.Errorf("%s: %w", paramName, errUnspecifiedBraceCapture) + return fmt.Errorf("%s: %w", paramName, ErrUnspecifiedBraceCapture) } iscapture = true @@ -246,7 +246,7 @@ func (svc *Service) validateInput(types []validator.Type) error { // fail if capture or query without rename if len(param.Rename) < 1 && (iscapture || isquery) { - return fmt.Errorf("%s: %w", paramName, errMandatoryRename) + return fmt.Errorf("%s: %w", paramName, ErrMandatoryRename) } // use param name if no rename @@ -261,7 +261,7 @@ func (svc *Service) validateInput(types []validator.Type) error { // capture parameter cannot be optional if iscapture && param.Optional { - return fmt.Errorf("%s: %w", paramName, errIllegalOptionalURIParam) + return fmt.Errorf("%s: %w", paramName, ErrIllegalOptionalURIParam) } // fail on name/rename conflict @@ -275,7 +275,7 @@ func (svc *Service) validateInput(types []validator.Type) error { // 3.2.2. Not-renamed field matches a renamed field // 3.2.3. Renamed field matches name if param.Rename == param2.Rename || paramName == param2.Rename || paramName2 == param.Rename { - return fmt.Errorf("%s: %w", paramName, errParamNameConflict) + return fmt.Errorf("%s: %w", paramName, ErrParamNameConflict) } } @@ -296,7 +296,7 @@ func (svc *Service) validateOutput(types []validator.Type) error { // for each parameter for paramName, param := range svc.Output { if len(paramName) < 1 { - return fmt.Errorf("%s: %w", paramName, errIllegalParamName) + return fmt.Errorf("%s: %w", paramName, ErrIllegalParamName) } // use param name if no rename @@ -310,7 +310,7 @@ func (svc *Service) validateOutput(types []validator.Type) error { } if param.Optional { - return fmt.Errorf("%s: %w", paramName, errOptionalOption) + return fmt.Errorf("%s: %w", paramName, ErrOptionalOption) } // fail on name/rename conflict @@ -324,7 +324,7 @@ func (svc *Service) validateOutput(types []validator.Type) error { // 3.2.2. Not-renamed field matches a renamed field // 3.2.3. Renamed field matches name if param.Rename == param2.Rename || paramName == param2.Rename || paramName2 == param.Rename { - return fmt.Errorf("%s: %w", paramName, errParamNameConflict) + return fmt.Errorf("%s: %w", paramName, ErrParamNameConflict) } }