Skip to content
This repository has been archived by the owner on Oct 13, 2023. It is now read-only.

Latest commit

 

History

History
72 lines (59 loc) · 3.23 KB

README.md

File metadata and controls

72 lines (59 loc) · 3.23 KB

maperr

maperr is a library that allow you to define a list of errors which you want to map to some other errors.

Motivation

When writing a service which adopts a multi-layer architecture (e.g.: presentation, domain and storage) errors which are returned in lower layers of the application are often wrapped with other errors. This not only add context but also allow you to assertion in your higher layer (e.g.: presentation) without having to directly perform checks for errors which are held withing the lower layers of your application (e.g.: storage).

This works fine if all your error will be mapped to a 5xx error. However, sometimes some of this error are more user errors which have been detected lower down the application layers which could fall in the 4xx range.

This requires a mapping of errors, between layers, and if you have many errors to map, you would end up with one if statement for each error. This library allow you to handle all of them in a single if statement.

Mapping errors to status code

var errMapper = maperr.NewMultiErr(
	maperr.NewListMapper().
		Append(domain.ErrOne, maperr.WithStatus("err one happened", http.StatusInternalServerError)).
		Append(domain.ErrTwo, maperr.WithStatus("err two happened", http.StatusBadRequest)).
		Append(domain.ErrThree, maperr.WithStatus("err three happened", http.StatusConflict)).
		Append(domain.ErrDeadlineExceeded, maperr.WithStatus("deadline exceeded", http.StatusBadRequest)).
		Append(domain.ErrCanceled, maperr.WithStatus("context was cancelled", http.StatusBadRequest)),
    
	maperr.NewIgnoreListMapper().
        Append(domain.ErrThatNeedsIgnored),
)

func (h Handler) Update(rw http.ResponseWriter, r *http.Request) {
    ...
    entity, err := h.Controller.Update(r.Context(), id)
    if mappedErr := errMapper.MappedWithStatus(err, maperr.WithStatusInternalServerError); mappedErr != nil {
    	 // mappedErr.Error() -> error to send in response
         // mappedErr.Status() -> status code for response
         // mappedErr.Unwrap() -> cause to log
    }

Mapping errors to other errors

    var errMapper = maperr.NewMultiErr(
        maperr.NewHashableMapper()
            Append(storage.ErrOne, ErrOne).
            Append(storage.ErrTwo, ErrTwo).
            Append(storage.ErrThree, ErrThree).
            Append(context.DeadlineExceeded, ErrDeadlineExceeded).
            Append(context.Canceled, ErrCanceled).
            Append(sql.ErrNoRows, ErrorUserNotFound))

    func (c Controller) Update(ctx context.Context, user User) error {
        ...
        err := s.storage.Update(user)
        if appendedErr := errMapper.Mapped(err, ErrSomethingBadHappened); appendedErr != nil {
            return appendedErr
        }
    }