diff --git a/cover.html b/cover.html
deleted file mode 100644
index dff6d59..0000000
--- a/cover.html
+++ /dev/null
@@ -1,370 +0,0 @@
-
-
-
-
-
-
-
package jsrest
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "net/http"
-
- "github.com/go-resty/resty/v2"
-)
-
-var (
- ErrBadRequest = NewHTTPError(http.StatusBadRequest)
- ErrUnauthorized = NewHTTPError(http.StatusUnauthorized)
- ErrPaymentRequired = NewHTTPError(http.StatusPaymentRequired)
- ErrForbidden = NewHTTPError(http.StatusForbidden)
- ErrNotFound = NewHTTPError(http.StatusNotFound)
- ErrMethodNotAllowed = NewHTTPError(http.StatusMethodNotAllowed)
- ErrNotAcceptable = NewHTTPError(http.StatusNotAcceptable)
- ErrProxyAuthRequired = NewHTTPError(http.StatusProxyAuthRequired)
- ErrRequestTimeout = NewHTTPError(http.StatusRequestTimeout)
- ErrConflict = NewHTTPError(http.StatusConflict)
- ErrGone = NewHTTPError(http.StatusGone)
- ErrLengthRequired = NewHTTPError(http.StatusLengthRequired)
- ErrPreconditionFailed = NewHTTPError(http.StatusPreconditionFailed)
- ErrRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge)
- ErrRequestURITooLong = NewHTTPError(http.StatusRequestURITooLong)
- ErrUnsupportedMediaType = NewHTTPError(http.StatusUnsupportedMediaType)
- ErrRequestedRangeNotSatisfiable = NewHTTPError(http.StatusRequestedRangeNotSatisfiable)
- ErrExpectationFailed = NewHTTPError(http.StatusExpectationFailed)
- ErrTeapot = NewHTTPError(http.StatusTeapot)
- ErrMisdirectedRequest = NewHTTPError(http.StatusMisdirectedRequest)
- ErrUnprocessableEntity = NewHTTPError(http.StatusUnprocessableEntity)
- ErrLocked = NewHTTPError(http.StatusLocked)
- ErrFailedDependency = NewHTTPError(http.StatusFailedDependency)
- ErrTooEarly = NewHTTPError(http.StatusTooEarly)
- ErrUpgradeRequired = NewHTTPError(http.StatusUpgradeRequired)
- ErrPreconditionRequired = NewHTTPError(http.StatusPreconditionRequired)
- ErrTooManyRequests = NewHTTPError(http.StatusTooManyRequests)
- ErrRequestHeaderFieldsTooLarge = NewHTTPError(http.StatusRequestHeaderFieldsTooLarge)
- ErrUnavailableForLegalReasons = NewHTTPError(http.StatusUnavailableForLegalReasons)
-
- ErrInternalServerError = NewHTTPError(http.StatusInternalServerError)
- ErrNotImplemented = NewHTTPError(http.StatusNotImplemented)
- ErrBadGateway = NewHTTPError(http.StatusBadGateway)
- ErrServiceUnavailable = NewHTTPError(http.StatusServiceUnavailable)
- ErrGatewayTimeout = NewHTTPError(http.StatusGatewayTimeout)
- ErrHTTPVersionNotSupported = NewHTTPError(http.StatusHTTPVersionNotSupported)
- ErrVariantAlsoNegotiates = NewHTTPError(http.StatusVariantAlsoNegotiates)
- ErrInsufficientStorage = NewHTTPError(http.StatusInsufficientStorage)
- ErrLoopDetected = NewHTTPError(http.StatusLoopDetected)
- ErrNotExtended = NewHTTPError(http.StatusNotExtended)
- ErrNetworkAuthenticationRequired = NewHTTPError(http.StatusNetworkAuthenticationRequired)
-)
-
-type HTTPError struct {
- Code int
- Message string
-}
-
-func NewHTTPError(code int) *HTTPError {
- return &HTTPError{
- Code: code,
- Message: http.StatusText(code),
- }
-}
-
-func (err *HTTPError) Error() string {
- return fmt.Sprintf("[%d] %s", err.Code, err.Message)
-}
-
-type SilentJoinError struct {
- Wraps []error
-}
-
-func SilentJoin(errs ...error) *SilentJoinError {
- return &SilentJoinError{
- Wraps: errs,
- }
-}
-
-func (err *SilentJoinError) Error() string {
- return err.Wraps[0].Error()
-}
-
-func (err *SilentJoinError) Unwrap() []error {
- return err.Wraps
-}
-
-func WriteError(w http.ResponseWriter, err error) {
- je := ToJSONError(err)
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(je.Code)
-
- enc := json.NewEncoder(w)
- _ = enc.Encode(je) //nolint:errchkjson
-}
-
-func Errorf(he *HTTPError, format string, a ...any) error {
- err := fmt.Errorf(format, a...) //nolint:goerr113
-
- if GetHTTPError(err) != nil {
- return err
- }
-
- return SilentJoin(err, he)
-}
-
-type JSONError struct {
- Code int `json:"-"`
- Messages []string `json:"messages"`
-}
-
-func (je *JSONError) Error() string {
- if len(je.Messages) > 0 {
- return je.Messages[0]
- }
-
- return "no error message"
-}
-
-func (je *JSONError) Unwrap() error {
- if len(je.Messages) > 1 {
- return &JSONError{
- Code: je.Code,
- Messages: je.Messages[1:],
- }
- }
-
- return nil
-}
-
-func ToJSONError(err error) *JSONError {
- je := &JSONError{
- Code: 500,
- }
- je.importError(err)
-
- return je
-}
-
-func ReadError(resp *resty.Response) error {
- jse := &JSONError{}
-
- err := json.Unmarshal(resp.Body(), jse)
- if err == nil {
- return jse
- }
-
- return NewHTTPError(resp.StatusCode())
-}
-
-type singleUnwrap interface {
- Unwrap() error
-}
-
-type multiUnwrap interface {
- Unwrap() []error
-}
-
-func GetHTTPError(err error) *HTTPError {
- hErr := &HTTPError{}
-
- if errors.As(err, &hErr) {
- return hErr
- }
-
- return nil
-}
-
-func (je *JSONError) importError(err error) {
- if he, ok := err.(*HTTPError); ok { //nolint:errorlint
- je.Code = he.Code
- }
-
- if _, is := err.(*SilentJoinError); !is { //nolint:errorlint
- je.Messages = append(je.Messages, err.Error())
- }
-
- if unwrap, ok := err.(singleUnwrap); ok { //nolint:errorlint
- je.importError(unwrap.Unwrap())
- } else if unwrap, ok := err.(multiUnwrap); ok { //nolint:errorlint
- for _, sub := range unwrap.Unwrap() {
- je.importError(sub)
- }
- }
-}
-
-
-
package jsrest
-
-import (
- "encoding/json"
- "errors"
- "net/http"
-
- "github.com/gopatchy/metadata"
- "github.com/vfaronov/httpheader"
-)
-
-var ErrUnsupportedContentType = errors.New("unsupported Content-Type")
-
-func Read(r *http.Request, obj any) error {
- contentType, _ := httpheader.ContentType(r.Header)
-
- switch contentType {
- case "":
- fallthrough
- case "application/json":
- break
-
- default:
- return Errorf(ErrUnsupportedMediaType, "Content-Type: %s", contentType)
- }
-
- dec := json.NewDecoder(r.Body)
- dec.DisallowUnknownFields()
-
- err := dec.Decode(obj)
- if err != nil {
- return Errorf(ErrBadRequest, "decode JSON request body failed (%w)", err)
- }
-
- return nil
-}
-
-func Write(w http.ResponseWriter, obj any) error {
- m := metadata.GetMetadata(obj)
-
- w.Header().Set("Content-Type", "application/json")
- httpheader.SetETag(w.Header(), httpheader.EntityTag{Opaque: m.ETag})
-
- enc := json.NewEncoder(w)
-
- err := enc.Encode(obj)
- if err != nil {
- return Errorf(ErrInternalServerError, "encode JSON response failed (%w)", err)
- }
-
- return nil
-}
-
-func WriteList(w http.ResponseWriter, list []any, etag string) error {
- w.Header().Set("Content-Type", "application/json")
- httpheader.SetETag(w.Header(), httpheader.EntityTag{Opaque: etag})
-
- enc := json.NewEncoder(w)
-
- err := enc.Encode(list)
- if err != nil {
- return Errorf(ErrInternalServerError, "encode JSON response failed (%w)", err)
- }
-
- return nil
-}
-
-
-
-
-
-
diff --git a/cover.out b/cover.out
deleted file mode 100644
index 5494182..0000000
--- a/cover.out
+++ /dev/null
@@ -1,45 +0,0 @@
-mode: atomic
-github.com/gopatchy/jsrest/error.go:61.40,66.2 1 40
-github.com/gopatchy/jsrest/error.go:68.38,70.2 1 2
-github.com/gopatchy/jsrest/error.go:76.49,80.2 1 2
-github.com/gopatchy/jsrest/error.go:82.44,84.2 1 1
-github.com/gopatchy/jsrest/error.go:86.46,88.2 1 7
-github.com/gopatchy/jsrest/error.go:90.51,98.2 5 0
-github.com/gopatchy/jsrest/error.go:100.59,103.30 2 3
-github.com/gopatchy/jsrest/error.go:103.30,105.3 1 1
-github.com/gopatchy/jsrest/error.go:107.2,107.28 1 2
-github.com/gopatchy/jsrest/error.go:115.37,116.26 1 0
-github.com/gopatchy/jsrest/error.go:116.26,118.3 1 0
-github.com/gopatchy/jsrest/error.go:120.2,120.27 1 0
-github.com/gopatchy/jsrest/error.go:123.37,124.26 1 0
-github.com/gopatchy/jsrest/error.go:124.26,129.3 1 0
-github.com/gopatchy/jsrest/error.go:131.2,131.12 1 0
-github.com/gopatchy/jsrest/error.go:134.40,141.2 3 2
-github.com/gopatchy/jsrest/error.go:143.44,147.16 3 0
-github.com/gopatchy/jsrest/error.go:147.16,149.3 1 0
-github.com/gopatchy/jsrest/error.go:151.2,151.40 1 0
-github.com/gopatchy/jsrest/error.go:162.41,165.27 2 3
-github.com/gopatchy/jsrest/error.go:165.27,167.3 1 1
-github.com/gopatchy/jsrest/error.go:169.2,169.12 1 2
-github.com/gopatchy/jsrest/error.go:172.45,173.36 1 9
-github.com/gopatchy/jsrest/error.go:173.36,175.3 1 2
-github.com/gopatchy/jsrest/error.go:177.2,177.42 1 9
-github.com/gopatchy/jsrest/error.go:177.42,179.3 1 7
-github.com/gopatchy/jsrest/error.go:181.2,181.42 1 9
-github.com/gopatchy/jsrest/error.go:181.42,183.3 1 1
-github.com/gopatchy/jsrest/error.go:183.8,183.48 1 8
-github.com/gopatchy/jsrest/error.go:183.48,184.39 1 3
-github.com/gopatchy/jsrest/error.go:184.39,186.4 1 6
-github.com/gopatchy/jsrest/json.go:14.43,17.21 2 2
-github.com/gopatchy/jsrest/json.go:18.10,19.14 1 0
-github.com/gopatchy/jsrest/json.go:20.26,21.8 1 2
-github.com/gopatchy/jsrest/json.go:23.10,24.74 1 0
-github.com/gopatchy/jsrest/json.go:27.2,31.16 4 2
-github.com/gopatchy/jsrest/json.go:31.16,33.3 1 0
-github.com/gopatchy/jsrest/json.go:35.2,35.12 1 2
-github.com/gopatchy/jsrest/json.go:38.50,47.16 6 0
-github.com/gopatchy/jsrest/json.go:47.16,49.3 1 0
-github.com/gopatchy/jsrest/json.go:51.2,51.12 1 0
-github.com/gopatchy/jsrest/json.go:54.70,61.16 5 0
-github.com/gopatchy/jsrest/json.go:61.16,63.3 1 0
-github.com/gopatchy/jsrest/json.go:65.2,65.12 1 0
diff --git a/go.mod b/go.mod
index 7ed6443..3325077 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.19
require (
github.com/go-resty/resty/v2 v2.7.0
- github.com/gopatchy/metadata v0.0.0-20230516041300-fc49e5f775fe
+ github.com/gopatchy/metadata v0.0.0-20230516044939-eed23a0903d5
github.com/stretchr/testify v1.8.2
github.com/vfaronov/httpheader v0.1.0
go.uber.org/goleak v1.2.1
diff --git a/go.sum b/go.sum
index 252921f..6616ae7 100644
--- a/go.sum
+++ b/go.sum
@@ -8,6 +8,8 @@ github.com/gopatchy/metadata v0.0.0-20230424223338-33e58fee42bf h1:HKCbhVEpC3++y
github.com/gopatchy/metadata v0.0.0-20230424223338-33e58fee42bf/go.mod h1:VgD33raUShjDePCDBo55aj+eSXFtUEpMzs+Ie39g2zo=
github.com/gopatchy/metadata v0.0.0-20230516041300-fc49e5f775fe h1:xPnlis/qCAYoxHx9tow1P4pO17c8JH/Hs/lHDmZej/Q=
github.com/gopatchy/metadata v0.0.0-20230516041300-fc49e5f775fe/go.mod h1:VgD33raUShjDePCDBo55aj+eSXFtUEpMzs+Ie39g2zo=
+github.com/gopatchy/metadata v0.0.0-20230516044939-eed23a0903d5 h1:b66b4DOGTqDuw4hbxHSp0WbhXr/xAMaiFkU6iCi4nDg=
+github.com/gopatchy/metadata v0.0.0-20230516044939-eed23a0903d5/go.mod h1:VgD33raUShjDePCDBo55aj+eSXFtUEpMzs+Ie39g2zo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=