Skip to content

Commit

Permalink
feat(errors, validator): improve error handling, added validator
Browse files Browse the repository at this point in the history
  • Loading branch information
frogfromlake committed Feb 14, 2024
1 parent 793b5d6 commit 54414da
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 1 deletion.
81 changes: 81 additions & 0 deletions gapi/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package gapi

import (
"errors"
"strings"

"github.com/jackc/pgx/v5/pgconn"
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

func fieldViolation(field string, err error) *errdetails.BadRequest_FieldViolation {
return &errdetails.BadRequest_FieldViolation{
Field: field,
Description: err.Error(),
}
}

func invalidArgumentError(violations []*errdetails.BadRequest_FieldViolation) error {
badRequest := &errdetails.BadRequest{FieldViolations: violations}
statusInvalid := status.New(codes.InvalidArgument, "invalid parameters")

statusDetails, err := statusInvalid.WithDetails(badRequest)
if err != nil {
return statusInvalid.Err()
}

return statusDetails.Err()
}

type MultiError []error

func (me MultiError) Error() string {
var sb strings.Builder
for _, err := range me {
sb.WriteString(err.Error())
sb.WriteString("\n")
}
return sb.String()
}

func handleDatabaseError(err error) error {
var pgErr *pgconn.PgError
var errs MultiError

if errors.As(err, &pgErr) {
switch pgErr.Code {
case "23505": // unique_violation
errs = append(errs, status.Errorf(codes.AlreadyExists, "unique violation occurred: %v", err))
case "23503": // foreign_key_violation
errs = append(errs, status.Errorf(codes.FailedPrecondition, "foreign key violation occurred: %v", err))
case "23502": // not_null_violation
errs = append(errs, status.Errorf(codes.InvalidArgument, "not null violation occurred: %v", err))
case "23514": // check_violation
errs = append(errs, status.Errorf(codes.OutOfRange, "check violation occurred: %v", err))
case "2200L": // invalid_text_representation
errs = append(errs, status.Errorf(codes.InvalidArgument, "invalid text representation: %v", err))
case "22P02": // invalid_text_representation
errs = append(errs, status.Errorf(codes.InvalidArgument, "invalid text representation: %v", err))
case "23P01": // exclusion_violation
errs = append(errs, status.Errorf(codes.AlreadyExists, "exclusion violation occurred: %v", err))
case "25006": // read_only_sql_transaction
errs = append(errs, status.Errorf(codes.PermissionDenied, "read-only SQL transaction: %v", err))
case "22023": // no_data
errs = append(errs, status.Errorf(codes.NotFound, "no data: %v", err))
case "54000": // too_many_connections
errs = append(errs, status.Errorf(codes.ResourceExhausted, "too many connections: %v", err))
default:
errs = append(errs, status.Errorf(codes.Unknown, "unknown database error: %v", err))
}
} else {
errs = append(errs, status.Errorf(codes.Internal, "internal error: %v", err))
}

if len(errs) > 0 {
return errs
}

return nil
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
golang.org/x/crypto v0.18.0
golang.org/x/net v0.20.0
google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe
google.golang.org/grpc v1.61.0
google.golang.org/protobuf v1.32.0
)
Expand Down Expand Up @@ -65,7 +66,6 @@ require (
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
33 changes: 33 additions & 0 deletions validator/validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package validator

import (
"fmt"
"time"
)

// Function to validate a string value based on the minimum and maximum length
func ValidateString(value string, minLen int, maxLen int) error {
n := len(value)
if n < minLen || n > maxLen {
return fmt.Errorf("must contain %d-%d characters", minLen, maxLen)
}
return nil
}

// Function to validate UserId
func ValidateUserId(userId int64) error {
// Assuming the UserId should be a positive integer
if userId <= 0 {
return fmt.Errorf("UserId must be a positive integer")
}
return nil
}

// ValidateDuration checks if the given string can be parsed as a duration
func ValidateDuration(durationStr string) error {
_, err := time.ParseDuration(durationStr)
if err != nil {
return fmt.Errorf("invalid duration format: %w", err)
}
return nil
}

0 comments on commit 54414da

Please sign in to comment.