mirror of
https://github.com/versia-pub/versia-go.git
synced 2025-12-06 22:38:20 +01:00
87 lines
2 KiB
Go
87 lines
2 KiB
Go
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}
|
|
}
|