versia-go/internal/api_schema/api.go

87 lines
2 KiB
Go
Raw Normal View History

2024-08-11 03:51:22 +02:00
package api_schema
import (
"encoding/json"
"errors"
"fmt"
"net/url"
"strings"
)
type APIError struct {
StatusCode int `json:"status_code"`
Description string `json:"description"`
Metadata map[string]any `json:"metadata,omitempty"`
}
func (e APIError) Error() string {
if e.Metadata == nil || len(e.Metadata) == 0 {
return fmt.Sprintf("APIError: %d - %s", e.StatusCode, e.Description)
}
return fmt.Sprintf("APIError: %d - %s, %s", e.StatusCode, e.Description, stringifyErrorMetadata(e.Metadata))
}
func stringifyErrorMetadata(m map[string]any) string {
sb := strings.Builder{}
for key, value := range m {
sb.WriteString(fmt.Sprintf("%s=%v, ", key, value))
}
return strings.TrimSuffix(sb.String(), ", ")
}
func (e APIError) Equals(other any) bool {
var err *APIError
switch raw := other.(type) {
case *APIError:
err = raw
default:
return false
}
return e.StatusCode == err.StatusCode && e.Description == err.Description
}
func (e APIError) URLEncode() (string, error) {
v := url.Values{}
v.Set("status_code", fmt.Sprintf("%d", e.StatusCode))
v.Set("description", e.Description)
if e.Metadata != nil {
b, err := json.Marshal(e.Metadata)
if err != nil {
return "", err
}
v.Set("metadata", string(b))
}
// Fix up spaces because Golang's net/url.URL encodes " " as "+" instead of "%20"
// https://github.com/golang/go/issues/13982
return strings.ReplaceAll(v.Encode(), "+", "%20"), nil
}
func NewAPIError(code int, description string) func(metadata map[string]any) *APIError {
return func(metadata map[string]any) *APIError {
return &APIError{StatusCode: code, Description: description, Metadata: metadata}
}
}
type APIResponse[T any] struct {
Ok bool `json:"ok"`
Data *T `json:"data"`
Error *APIError `json:"error"`
}
func NewFailedAPIResponse[T any](err error) APIResponse[T] {
var e *APIError
if errors.As(err, &e) {
} else {
e = NewAPIError(500, err.Error())(nil)
}
return APIResponse[T]{Ok: false, Error: e}
}