github.com/cozy/cozy-stack@v0.0.0-20240327093429-939e4a21320e/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  // BadJSON returns a 400 formatted error meaning the json input is
    68  // malformed.
    69  func BadJSON() *Error {
    70  	return &Error{
    71  		Status: http.StatusBadRequest,
    72  		Title:  "Bad Request",
    73  		Detail: "JSON input is malformed or is missing mandatory fields",
    74  	}
    75  }
    76  
    77  // MethodNotAllowed returns a 405 formatted error
    78  func MethodNotAllowed(method string) *Error {
    79  	return &Error{
    80  		Status: http.StatusMethodNotAllowed,
    81  		Title:  "Method Not Allowed",
    82  		Detail: method + " is not allowed on this endpoint",
    83  	}
    84  }
    85  
    86  // Conflict returns a 409 formatted error representing a conflict
    87  func Conflict(err error) *Error {
    88  	return &Error{
    89  		Status: http.StatusConflict,
    90  		Title:  "Conflict",
    91  		Detail: err.Error(),
    92  	}
    93  }
    94  
    95  // InternalServerError returns a 500 formatted error
    96  func InternalServerError(err error) *Error {
    97  	return &Error{
    98  		Status: http.StatusInternalServerError,
    99  		Title:  "Internal Server Error",
   100  		Detail: err.Error(),
   101  	}
   102  }
   103  
   104  // PreconditionFailed returns a 412 formatted error when an expectation from an
   105  // HTTP header is not matched
   106  func PreconditionFailed(parameter string, err error) *Error {
   107  	return &Error{
   108  		Status: http.StatusPreconditionFailed,
   109  		Title:  "Precondition Failed",
   110  		Detail: err.Error(),
   111  		Source: SourceError{
   112  			Parameter: parameter,
   113  		},
   114  	}
   115  }
   116  
   117  // InvalidParameter returns a 422 formatted error when an HTTP or Query-String
   118  // parameter is invalid
   119  func InvalidParameter(parameter string, err error) *Error {
   120  	return &Error{
   121  		Status: http.StatusUnprocessableEntity,
   122  		Title:  "Invalid Parameter",
   123  		Detail: err.Error(),
   124  		Source: SourceError{
   125  			Parameter: parameter,
   126  		},
   127  	}
   128  }
   129  
   130  // InvalidAttribute returns a 422 formatted error when an attribute is invalid
   131  func InvalidAttribute(attribute string, err error) *Error {
   132  	return &Error{
   133  		Status: http.StatusUnprocessableEntity,
   134  		Title:  "Invalid Attribute",
   135  		Detail: err.Error(),
   136  		Source: SourceError{
   137  			Pointer: "/data/attributes/" + attribute,
   138  		},
   139  	}
   140  }
   141  
   142  // Forbidden returns a 403 Forbidden error formatted when an action is
   143  // fobidden.
   144  func Forbidden(err error) *Error {
   145  	return &Error{
   146  		Status: http.StatusForbidden,
   147  		Title:  "Forbidden",
   148  		Detail: err.Error(),
   149  	}
   150  }
   151  
   152  // BadGateway returns a 502 formatted error
   153  func BadGateway(err error) *Error {
   154  	return &Error{
   155  		Status: http.StatusBadGateway,
   156  		Title:  "Bad Gateway",
   157  		Detail: err.Error(),
   158  	}
   159  }