github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/pkg/jsonapi/errors.go (about)

     1  package jsonapi
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"strconv"
     7  )
     8  
     9  // SourceError contains references to the source of the error
    10  type SourceError struct {
    11  	Pointer   string `json:"pointer,omitempty"`
    12  	Parameter string `json:"parameter,omitempty"`
    13  }
    14  
    15  // Error objects provide additional information about problems encountered
    16  // while performing an operation.
    17  // See http://jsonapi.org/format/#error-objects
    18  type Error struct {
    19  	Status int         `json:"status,string"`
    20  	Title  string      `json:"title"`
    21  	Code   string      `json:"code,omitempty"`
    22  	Detail string      `json:"detail,omitempty"`
    23  	Source SourceError `json:"source,omitempty"`
    24  	Links  *LinksList  `json:"links,omitempty"`
    25  }
    26  
    27  // ErrorList is just an array of error objects
    28  type ErrorList []*Error
    29  
    30  func (e *Error) Error() string {
    31  	return e.Title + "(" + strconv.Itoa(e.Status) + ")" + ": " + e.Detail
    32  }
    33  
    34  // NewError creates a new generic Error
    35  func NewError(status int, detail string) *Error {
    36  	return &Error{
    37  		Status: status,
    38  		Title:  http.StatusText(status),
    39  		Detail: detail,
    40  	}
    41  }
    42  
    43  // Errorf creates a new generic Error with detail build as Sprintf
    44  func Errorf(status int, format string, args ...interface{}) *Error {
    45  	detail := fmt.Sprintf(format, args...)
    46  	return NewError(status, detail)
    47  }
    48  
    49  // NotFound returns a 404 formatted error
    50  func NotFound(err error) *Error {
    51  	return &Error{
    52  		Status: http.StatusNotFound,
    53  		Title:  "Not Found",
    54  		Detail: err.Error(),
    55  	}
    56  }
    57  
    58  // BadRequest returns a 400 formatted error
    59  func BadRequest(err error) *Error {
    60  	return &Error{
    61  		Status: http.StatusBadRequest,
    62  		Title:  "Bad Request",
    63  		Detail: err.Error(),
    64  	}
    65  }
    66  
    67  // Unauthorized returns a 401 formatted error
    68  func Unauthorized(err error) *Error {
    69  	return &Error{
    70  		Status: http.StatusUnauthorized,
    71  		Title:  "Unauthorized",
    72  		Detail: err.Error(),
    73  	}
    74  }
    75  
    76  // BadJSON returns a 400 formatted error meaning the json input is
    77  // malformed.
    78  func BadJSON() *Error {
    79  	return &Error{
    80  		Status: http.StatusBadRequest,
    81  		Title:  "Bad Request",
    82  		Detail: "JSON input is malformed or is missing mandatory fields",
    83  	}
    84  }
    85  
    86  // MethodNotAllowed returns a 405 formatted error
    87  func MethodNotAllowed(method string) *Error {
    88  	return &Error{
    89  		Status: http.StatusMethodNotAllowed,
    90  		Title:  "Method Not Allowed",
    91  		Detail: method + " is not allowed on this endpoint",
    92  	}
    93  }
    94  
    95  // Conflict returns a 409 formatted error representing a conflict
    96  func Conflict(err error) *Error {
    97  	return &Error{
    98  		Status: http.StatusConflict,
    99  		Title:  "Conflict",
   100  		Detail: err.Error(),
   101  	}
   102  }
   103  
   104  // InternalServerError returns a 500 formatted error
   105  func InternalServerError(err error) *Error {
   106  	return &Error{
   107  		Status: http.StatusInternalServerError,
   108  		Title:  "Internal Server Error",
   109  		Detail: err.Error(),
   110  	}
   111  }
   112  
   113  // PreconditionFailed returns a 412 formatted error when an expectation from an
   114  // HTTP header is not matched
   115  func PreconditionFailed(parameter string, err error) *Error {
   116  	return &Error{
   117  		Status: http.StatusPreconditionFailed,
   118  		Title:  "Precondition Failed",
   119  		Detail: err.Error(),
   120  		Source: SourceError{
   121  			Parameter: parameter,
   122  		},
   123  	}
   124  }
   125  
   126  // InvalidParameter returns a 422 formatted error when an HTTP or Query-String
   127  // parameter is invalid
   128  func InvalidParameter(parameter string, err error) *Error {
   129  	return &Error{
   130  		Status: http.StatusUnprocessableEntity,
   131  		Title:  "Invalid Parameter",
   132  		Detail: err.Error(),
   133  		Source: SourceError{
   134  			Parameter: parameter,
   135  		},
   136  	}
   137  }
   138  
   139  // InvalidAttribute returns a 422 formatted error when an attribute is invalid
   140  func InvalidAttribute(attribute string, err error) *Error {
   141  	return &Error{
   142  		Status: http.StatusUnprocessableEntity,
   143  		Title:  "Invalid Attribute",
   144  		Detail: err.Error(),
   145  		Source: SourceError{
   146  			Pointer: "/data/attributes/" + attribute,
   147  		},
   148  	}
   149  }
   150  
   151  // Forbidden returns a 403 Forbidden error formatted when an action is
   152  // fobidden.
   153  func Forbidden(err error) *Error {
   154  	return &Error{
   155  		Status: http.StatusForbidden,
   156  		Title:  "Forbidden",
   157  		Detail: err.Error(),
   158  	}
   159  }
   160  
   161  // BadGateway returns a 502 formatted error
   162  func BadGateway(err error) *Error {
   163  	return &Error{
   164  		Status: http.StatusBadGateway,
   165  		Title:  "Bad Gateway",
   166  		Detail: err.Error(),
   167  	}
   168  }