Files
catalyst/generated/api/api.go
Jonas Plum fb69a1a07b Replace interface{} with any (#538)
Co-authored-by: Jonas Plum <git@jonasplum.de>
2022-10-22 14:50:09 +02:00

193 lines
4.3 KiB
Go
Executable File

package api
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"
"strconv"
"github.com/go-chi/chi/v5"
"github.com/xeipuuv/gojsonschema"
)
type HTTPError struct {
Status int
Internal error
}
func (e *HTTPError) Error() string {
return fmt.Sprintf("HTTPError(%d): %s", e.Status, e.Internal)
}
func (e *HTTPError) Unwrap() error {
return e.Internal
}
func parseURLInt64(r *http.Request, s string) (int64, error) {
i, err := strconv.ParseInt(chi.URLParam(r, s), 10, 64)
if err != nil {
return 0, fmt.Errorf("%w", &HTTPError{http.StatusUnprocessableEntity, err})
}
return i, nil
}
func parseURLInt(r *http.Request, s string) (int, error) {
i, err := strconv.Atoi(chi.URLParam(r, s))
if err != nil {
return 0, fmt.Errorf("%w", &HTTPError{http.StatusUnprocessableEntity, err})
}
return i, nil
}
func parseQueryInt(r *http.Request, s string) (int, error) {
i, err := strconv.Atoi(r.URL.Query().Get(s))
if err != nil {
return 0, fmt.Errorf("%w", &HTTPError{http.StatusUnprocessableEntity, err})
}
return i, nil
}
func parseQueryBool(r *http.Request, s string) (bool, error) {
b, err := strconv.ParseBool(r.URL.Query().Get(s))
if err != nil {
return false, fmt.Errorf("%w", &HTTPError{http.StatusUnprocessableEntity, err})
}
return b, nil
}
func parseQueryStringArray(r *http.Request, key string) ([]string, error) {
stringArray, ok := r.URL.Query()[key]
if !ok {
return nil, nil
}
return removeEmpty(stringArray), nil
}
func removeEmpty(l []string) []string {
var stringArray []string
for _, s := range l {
if s == "" {
continue
}
stringArray = append(stringArray, s)
}
return stringArray
}
func parseQueryBoolArray(r *http.Request, key string) ([]bool, error) {
stringArray, ok := r.URL.Query()[key]
if !ok {
return nil, nil
}
var boolArray []bool
for _, s := range stringArray {
if s == "" {
continue
}
b, err := strconv.ParseBool(s)
if err != nil {
return nil, fmt.Errorf("%w", &HTTPError{http.StatusUnprocessableEntity, err})
}
boolArray = append(boolArray, b)
}
return boolArray, nil
}
func parseQueryOptionalInt(r *http.Request, key string) (*int, error) {
s := r.URL.Query().Get(key)
if s == "" {
return nil, nil
}
i, err := strconv.Atoi(s)
if err != nil {
return nil, fmt.Errorf("%w", &HTTPError{http.StatusUnprocessableEntity, err})
}
return &i, nil
}
func parseQueryOptionalStringArray(r *http.Request, key string) ([]string, error) {
return parseQueryStringArray(r, key)
}
func parseQueryOptionalBoolArray(r *http.Request, key string) ([]bool, error) {
return parseQueryBoolArray(r, key)
}
func parseBody(b []byte, i any) error {
dec := json.NewDecoder(bytes.NewBuffer(b))
err := dec.Decode(i)
if err != nil {
return fmt.Errorf("%w", &HTTPError{http.StatusUnprocessableEntity, err})
}
return nil
}
func JSONError(w http.ResponseWriter, err error) {
JSONErrorStatus(w, http.StatusInternalServerError, err)
}
func JSONErrorStatus(w http.ResponseWriter, status int, err error) {
w.WriteHeader(status)
b, _ := json.Marshal(map[string]string{"error": err.Error()})
w.Write(b)
}
func response(w http.ResponseWriter, v any, err error) {
if err != nil {
var httpError *HTTPError
if errors.As(err, &httpError) {
JSONErrorStatus(w, httpError.Status, httpError.Internal)
return
}
JSONError(w, err)
return
}
if v == nil {
w.WriteHeader(http.StatusNoContent)
return
}
w.WriteHeader(http.StatusOK)
b, _ := json.Marshal(v)
w.Write(b)
}
func validateSchema(body []byte, schema *gojsonschema.Schema, w http.ResponseWriter) bool {
jl := gojsonschema.NewBytesLoader(body)
validationResult, err := schema.Validate(jl)
if err != nil {
JSONError(w, err)
return true
}
if !validationResult.Valid() {
w.WriteHeader(http.StatusUnprocessableEntity)
var validationErrors []string
for _, valdiationError := range validationResult.Errors() {
validationErrors = append(validationErrors, valdiationError.String())
}
b, _ := json.Marshal(map[string]any{"error": "wrong input", "errors": validationErrors})
w.Write(b)
return true
}
return false
}
func NilMiddleware() func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, r)
})
}
}
func IgnoreRoles(_ []string) func(next http.Handler) http.Handler {
return NilMiddleware()
}