...

Source file src/go.einride.tech/aip/validation/error.go

Documentation: go.einride.tech/aip/validation

     1  package validation
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"google.golang.org/genproto/googleapis/rpc/errdetails"
     8  	"google.golang.org/grpc/codes"
     9  	"google.golang.org/grpc/status"
    10  )
    11  
    12  // Error represents a message validation error.
    13  type Error struct {
    14  	fieldViolations []*errdetails.BadRequest_FieldViolation
    15  	grpcStatus      *status.Status
    16  	str             string
    17  }
    18  
    19  // NewError creates a new validation error from the provided field violations.
    20  func NewError(fieldViolations []*errdetails.BadRequest_FieldViolation) error {
    21  	if len(fieldViolations) == 0 {
    22  		panic("validation.NewError: must provide at least one field violation")
    23  	}
    24  	return &Error{
    25  		fieldViolations: fieldViolations,
    26  	}
    27  }
    28  
    29  // GRPCStatus converts the validation error to a gRPC status with code INVALID_ARGUMENT.
    30  func (e *Error) GRPCStatus() *status.Status {
    31  	if e.grpcStatus == nil {
    32  		var fields strings.Builder
    33  		for i, fieldViolation := range e.fieldViolations {
    34  			_, _ = fields.WriteString(fieldViolation.GetField())
    35  			if i < len(e.fieldViolations)-1 {
    36  				_, _ = fields.WriteString(", ")
    37  			}
    38  		}
    39  		withoutDetails := status.Newf(codes.InvalidArgument, "invalid fields: %s", fields.String())
    40  		if withDetails, err := withoutDetails.WithDetails(&errdetails.BadRequest{
    41  			FieldViolations: e.fieldViolations,
    42  		}); err != nil {
    43  			e.grpcStatus = withoutDetails
    44  		} else {
    45  			e.grpcStatus = withDetails
    46  		}
    47  	}
    48  	return e.grpcStatus
    49  }
    50  
    51  // Error implements the error interface.
    52  func (e *Error) Error() string {
    53  	if e.str == "" {
    54  		if len(e.fieldViolations) == 1 {
    55  			e.str = fmt.Sprintf(
    56  				"field violation on %s: %s",
    57  				e.fieldViolations[0].GetField(),
    58  				e.fieldViolations[0].GetDescription(),
    59  			)
    60  		} else {
    61  			var result strings.Builder
    62  			_, _ = result.WriteString("field violation on multiple fields:\n")
    63  			for i, fieldViolation := range e.fieldViolations {
    64  				_, _ = result.WriteString(fmt.Sprintf(" | %s: %s", fieldViolation.GetField(), fieldViolation.GetDescription()))
    65  				if i < len(e.fieldViolations)-1 {
    66  					_ = result.WriteByte('\n')
    67  				}
    68  			}
    69  			e.str = result.String()
    70  		}
    71  	}
    72  	return e.str
    73  }
    74  

View as plain text