timoth-y/kicksware-api

View on GitHub
services/users/api/rest/handler.go

Summary

Maintainability
A
35 mins
Test Coverage
package rest

import (
    "io/ioutil"
    "log"
    "net/http"
    "time"

    "github.com/go-chi/chi"
    "github.com/pkg/errors"
    "go.kicksware.com/api/shared/api/rest"
    "go.kicksware.com/api/shared/config"

    common "go.kicksware.com/api/shared/core/meta"

    "go.kicksware.com/api/services/users/core/meta"
    "go.kicksware.com/api/services/users/core/model"
    "go.kicksware.com/api/services/users/core/service"
    "go.kicksware.com/api/services/users/usecase/business"
    "go.kicksware.com/api/services/users/usecase/serializer/json"
    "go.kicksware.com/api/services/users/usecase/serializer/msg"
)

type Handler struct {
    service     service.UserService
    auth        service.AuthService
    mail        service.MailService
    interact    service.InteractService
    contentType string
}

func NewHandler(service service.UserService, auth service.AuthService, mail service.MailService,
    interact service.InteractService, config config.CommonConfig) *Handler {
    return &Handler{
        service,
        auth,
        mail,
        interact,
        config.ContentType,
    }
}

func (h *Handler) GetOne(w http.ResponseWriter, r *http.Request) {
    userID := chi.URLParam(r,"userID")
    user, err := h.service.FetchOne(userID)
    if err != nil {
        if errors.Cause(err) == business.ErrUserNotFound {
            http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
            return
        }
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    h.setupResponse(w, user, http.StatusOK)
}

func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
    var users []*model.User
    var err error
    params := rest.NewRequestParams(r)

    if r.Method == http.MethodPost {
        query, err := h.getRequestQuery(r)
        if err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }
        users, err = h.service.FetchQuery(query, params)
    } else if r.Method == http.MethodGet {
        if codes := r.URL.Query()["userID"]; codes != nil && len(codes) != 0 {
            users, err = h.service.Fetch(codes, params)
        } else {
            users, err = h.service.FetchAll(params)
        }
    }

    if err != nil {
        if errors.Cause(err) == business.ErrUserNotFound {
            http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
            return
        }
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    h.setupResponse(w, users, http.StatusOK)
}

func (h *Handler) Post(w http.ResponseWriter, r *http.Request) {
    user, err := h.getRequestBody(r); if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    err = h.service.Register(user)
    if err != nil {
        if errors.Cause(err) == business.ErrUserInvalid {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    h.setupResponse(w, user, http.StatusOK)
}

func (h *Handler) Patch(w http.ResponseWriter, r *http.Request) {
    user, err := h.getRequestBody(r); if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    err = h.service.Modify(user)
    if err != nil {
        if errors.Cause(err) == business.ErrUserInvalid {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    h.setupResponse(w, nil, http.StatusOK)
}

func (h *Handler) Put(w http.ResponseWriter, r *http.Request) {
    user, err := h.getRequestBody(r); if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    err = h.service.Replace(user)
    if err != nil {
        if errors.Cause(err) == business.ErrUserInvalid {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    h.setupResponse(w, nil, http.StatusOK)
}

func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
    code := chi.URLParam(r,"userID")
    err := h.service.Remove(code)
    if err != nil {
        if errors.Cause(err) == business.ErrUserNotFound {
            http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
            return
        }
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    h.setupResponse(w, nil, http.StatusOK)
}

func (h *Handler) GetTheme(w http.ResponseWriter, r *http.Request) {
    code := chi.URLParam(r,"userID")
    user, err := h.service.FetchOne(code)
    if err != nil {
        if errors.Cause(err) == business.ErrUserNotFound {
            http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
            return
        }
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    h.setupResponse(w, user.Settings.Theme, http.StatusOK)
}

func (h *Handler) setupResponse(w http.ResponseWriter, body interface{}, statusCode int) {
    w.Header().Set("Content-Type", h.contentType)
    w.WriteHeader(statusCode)
    if body != nil {
        raw, err := h.serializer(h.contentType).Encode(body)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        if _, err := w.Write(raw); err != nil {
            log.Println(err)
        }
    }
}

func (h *Handler) setupAuthCookie(w http.ResponseWriter, token *meta.AuthToken) {
    cookie := &http.Cookie{
        Name: "AuthToken",
        Value: token.Token,
        Expires: token.Expires,
    }
    http.SetCookie(w, cookie)
}

func (h *Handler) recallAuthCookie(w http.ResponseWriter) {
    cookie := &http.Cookie{
        Name: "AuthToken",
        Expires: time.Now(),
        MaxAge: -1,
    }
    http.SetCookie(w, cookie)
}

func (h *Handler) getRequestBody(r *http.Request) (*model.User, error) {
    contentType := r.Header.Get("Content-Type")
    requestBody, err := ioutil.ReadAll(r.Body)
    if err != nil {
        return nil, err
    }
    body, err := h.serializer(contentType).Decode(requestBody)
    if err != nil {
        return nil, err
    }
    return body, nil
}

func (h *Handler) getRequestQuery(r *http.Request) (common.RequestQuery, error) {
    contentType := r.Header.Get("Content-Type")
    requestBody, err := ioutil.ReadAll(r.Body)
    if err != nil {
        return nil, err
    }
    body, err := h.serializer(contentType).DecodeMap(requestBody)
    if err != nil {
        return nil, err
    }
    return body, nil
}

func (h *Handler) serializer(contentType string) service.UserSerializer {
    if contentType == "application/x-msgpack" {
        return msg.NewSerializer()
    }
    return json.NewSerializer()
}