Wrap responses in helper methods

Distinguish between client and server errors and respond properly.
master
Onion Ltd 4 years ago
parent e9406b88e9
commit 8bafb83c3a
Signed by: onionltd
GPG Key ID: E4B6CAC49B242A44

@ -45,6 +45,45 @@ func (s *server) defaultErrorHandler(err error, c echo.Context) {
}
}
func (s *server) response(c echo.Context, status int, data interface{}) error {
return c.JSON(status, data)
}
func (s *server) responseOK(c echo.Context, data interface{}) error {
return s.response(c, http.StatusOK, data)
}
func (s *server) responseCreated(c echo.Context, data interface{}) error {
return s.response(c, http.StatusCreated, data)
}
func (s *server) responseNoContent(c echo.Context) error {
return c.NoContent(http.StatusNoContent)
}
func (s *server) error(c echo.Context, status int, err error) error {
type genericError struct {
Error string `json:"error"`
}
return c.JSON(status, genericError{Error: err.Error()})
}
func (s *server) errorBadRequest(c echo.Context, err error) error {
return s.error(c, http.StatusBadRequest, err)
}
func (s *server) errorNotFound(c echo.Context, err error) error {
s.logger.Warn("client error", zap.Error(err))
return s.error(c, http.StatusNotFound, err)
}
func (s *server) errorInternal(c echo.Context, err error) error {
s.logger.Error("server error", zap.Error(err))
// Overwrite error so not to leak internal errors to clients
err = fmt.Errorf("internal server error")
return s.error(c, http.StatusInternalServerError, err)
}
func (s *server) handleInitMultisig() echo.HandlerFunc {
type member struct{}
@ -74,9 +113,7 @@ func (s *server) handleInitMultisig() echo.HandlerFunc {
in := &input{}
if err := c.Bind(in); err != nil {
return c.JSON(http.StatusBadRequest, map[string]interface{}{
"error": err.Error(),
})
return s.errorBadRequest(c, err)
}
// TODO: validate input!
@ -84,17 +121,13 @@ func (s *server) handleInitMultisig() echo.HandlerFunc {
// Check if input contains manager's username
managerNickname := s.config.ManagementCredentials.Username()
if _, ok := in.Members[managerNickname]; ok {
return c.JSON(http.StatusBadRequest, map[string]interface{}{
"error": fmt.Sprintf("username %s already taken", managerNickname),
})
return s.errorBadRequest(c, fmt.Errorf("username `%s` already taken", managerNickname))
}
in.Members[managerNickname] = member{}
topic, err := uuid.GenerateUUID()
if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]interface{}{
"error": "failed to generate UUID",
})
return s.errorInternal(c, err)
}
memberSecrets := map[string]string{}
@ -102,9 +135,7 @@ func (s *server) handleInitMultisig() echo.HandlerFunc {
// TODO: put password length in config.
token, err := password.Generate(18, 6, 0, false, false)
if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]interface{}{
"error": "failed to generate a token",
})
return s.errorInternal(c, err)
}
member := members.Member{
@ -121,9 +152,7 @@ func (s *server) handleInitMultisig() echo.HandlerFunc {
}
encoded, err := encodeSecret(secret)
if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]interface{}{
"error": "failed to encode secret data",
})
return s.errorInternal(c, err)
}
memberSecrets[nickname] = encoded
}
@ -136,7 +165,7 @@ func (s *server) handleInitMultisig() echo.HandlerFunc {
Secrets: memberSecrets,
}
return c.JSON(http.StatusCreated, out)
return s.responseCreated(c, out)
}
}
@ -152,19 +181,21 @@ func (s *server) handleListMessages() echo.HandlerFunc {
topic := c.Param("topic")
offset, err := offsetToNumber(c.QueryParam("offset"))
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]interface{}{
"error": "offset is not a number",
})
return s.errorBadRequest(c, fmt.Errorf("offset is not a number"))
}
messages, err := s.messageLog.List(topic, int(offset))
if err != nil {
return c.JSON(http.StatusNotFound, map[string]interface{}{
"error": err.Error(),
})
switch err.(type) {
case *messagelog.ErrInvalidMessage:
return s.errorBadRequest(c, err)
case *messagelog.ErrTopicNotFound:
return s.errorNotFound(c, err)
}
return s.errorInternal(c, err)
}
return c.JSON(http.StatusOK, messages)
return s.responseOK(c, messages)
}
}
@ -173,27 +204,27 @@ func (s *server) handlePushMessage() echo.HandlerFunc {
message := messagelog.Message{}
if err := c.Bind(&message); err != nil {
return c.JSON(http.StatusBadRequest, map[string]interface{}{
"error": "invalid message format",
})
return s.errorBadRequest(c, fmt.Errorf("invalid message format"))
}
member, ok := c.Get("member").(members.Member)
if !ok {
return c.JSON(http.StatusInternalServerError, map[string]interface{}{
"error": "internal server error",
})
return s.errorInternal(c, fmt.Errorf("missing member information from the middleware"))
}
message.Sender = member.Nickname
topic := c.Param("topic")
if err := s.messageLog.Push(topic, message); err != nil {
return c.JSON(http.StatusNotFound, map[string]interface{}{
"error": err.Error(),
})
switch err.(type) {
case *messagelog.ErrInvalidMessage:
return s.errorBadRequest(c, err)
case *messagelog.ErrTopicNotFound:
return s.errorNotFound(c, err)
}
return s.errorInternal(c, err)
}
return c.String(http.StatusNoContent, "")
return s.responseNoContent(c)
}
}

Loading…
Cancel
Save