feat: authsession service
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
package publichttp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"galaxy/authsession/internal/service/shared"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const publicErrorCodeContextKey = "public_error_code"
|
||||
|
||||
type malformedJSONRequestError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func (e *malformedJSONRequestError) Error() string {
|
||||
if e == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return e.message
|
||||
}
|
||||
|
||||
func decodeJSONRequest(request *http.Request, target any) error {
|
||||
if request == nil || request.Body == nil {
|
||||
return &malformedJSONRequestError{message: "request body must not be empty"}
|
||||
}
|
||||
|
||||
return decodeJSONReader(request.Body, target)
|
||||
}
|
||||
|
||||
func decodeJSONReader(reader io.Reader, target any) error {
|
||||
decoder := json.NewDecoder(reader)
|
||||
decoder.DisallowUnknownFields()
|
||||
|
||||
if err := decoder.Decode(target); err != nil {
|
||||
return describeJSONDecodeError(err)
|
||||
}
|
||||
|
||||
if err := decoder.Decode(&struct{}{}); err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &malformedJSONRequestError{message: "request body must contain a single JSON object"}
|
||||
}
|
||||
|
||||
return &malformedJSONRequestError{message: "request body must contain a single JSON object"}
|
||||
}
|
||||
|
||||
func describeJSONDecodeError(err error) error {
|
||||
var syntaxErr *json.SyntaxError
|
||||
var typeErr *json.UnmarshalTypeError
|
||||
|
||||
switch {
|
||||
case errors.Is(err, io.EOF):
|
||||
return &malformedJSONRequestError{message: "request body must not be empty"}
|
||||
case errors.As(err, &syntaxErr):
|
||||
return &malformedJSONRequestError{message: "request body contains malformed JSON"}
|
||||
case errors.Is(err, io.ErrUnexpectedEOF):
|
||||
return &malformedJSONRequestError{message: "request body contains malformed JSON"}
|
||||
case errors.As(err, &typeErr):
|
||||
if strings.TrimSpace(typeErr.Field) != "" {
|
||||
return &malformedJSONRequestError{
|
||||
message: fmt.Sprintf("request body contains an invalid value for %q", typeErr.Field),
|
||||
}
|
||||
}
|
||||
|
||||
return &malformedJSONRequestError{message: "request body contains an invalid JSON value"}
|
||||
case strings.HasPrefix(err.Error(), "json: unknown field "):
|
||||
return &malformedJSONRequestError{
|
||||
message: fmt.Sprintf("request body contains unknown field %s", strings.TrimPrefix(err.Error(), "json: unknown field ")),
|
||||
}
|
||||
default:
|
||||
return &malformedJSONRequestError{message: "request body contains invalid JSON"}
|
||||
}
|
||||
}
|
||||
|
||||
func abortWithProjection(c *gin.Context, projection shared.PublicErrorProjection) {
|
||||
c.Set(publicErrorCodeContextKey, projection.Code)
|
||||
c.AbortWithStatusJSON(projection.StatusCode, errorResponse{
|
||||
Error: errorBody{
|
||||
Code: projection.Code,
|
||||
Message: projection.Message,
|
||||
},
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user