Code Review For Go Beginner

Hi, I recently got started with go. I’m writing a little web application managing contacts. I’d appreciate if you could have a look at the following code and give me some tipps on how to improve the code. This is a mux router which provides some basic CRUD operations. One thing for example that annoys me is the repeated authentication checks.

package server

import (
	"log"
	"encoding/json"
	"errors"
	"net/http"
	"github.com/gorilla/mux"
	"github.com/cretzel/dopi-contacts/pkg"
)

type contactRouter struct {
	contactService root.ContactService
}

func NewContactRouter(contactService root.ContactService, router *mux.Router) *mux.Router {
	contactRouter := contactRouter{contactService}
	router.HandleFunc("/contacts", contactRouter.getContacts).Methods("GET")
	router.HandleFunc("/contacts", contactRouter.createContact).Methods("POST")
	router.HandleFunc("/contacts/{id}", contactRouter.updateContact).Methods("PUT")
	router.HandleFunc("/contacts/{id}", contactRouter.deleteContact).Methods("DELETE")
	return router
}

func (router *contactRouter) getContacts(response http.ResponseWriter, request *http.Request) {
	username, err := getCurrentUser(request)
	if err != nil {
		Error(response, http.StatusForbidden, err.Error())
		return
	}

	contacts, err := router.contactService.GetContacts(username)
	if err != nil {
		Error(response, http.StatusInternalServerError, err.Error())
		return
	}

	Json(response, http.StatusOK, contacts)
}

func (router *contactRouter) createContact(response http.ResponseWriter, request *http.Request) {
	username, err := getCurrentUser(request)
	if err != nil {
		Error(response, http.StatusForbidden, err.Error())
		return
	}

	contact, err := decodeContact(request)
	if err != nil {
		Error(response, http.StatusBadRequest, "Invalid request payload")
		return
	}

	responseContact, err := router.contactService.CreateContact(username, &contact)
	if err != nil {
		Error(response, http.StatusInternalServerError, err.Error())
		return
	}

	Json(response, http.StatusCreated, responseContact)
}

func (router *contactRouter) updateContact(response http.ResponseWriter, request *http.Request) {
	username, err := getCurrentUser(request)
	if err != nil {
		Error(response, http.StatusForbidden, err.Error())
		return
	}

	vars := mux.Vars(request)
	id := vars["id"]

	contact, err := decodeContact(request)
	if err != nil {
		Error(response, http.StatusBadRequest, "Invalid request payload")
		return
	}

	err = router.contactService.UpdateContact(username, id, &contact)
	if err != nil {
		Error(response, http.StatusInternalServerError, err.Error())
		return
	}

	Json(response, http.StatusOK, nil)
}

func (router *contactRouter) deleteContact(response http.ResponseWriter, request *http.Request) {
	username, err := getCurrentUser(request)
	if err != nil {
		Error(response, http.StatusForbidden, err.Error())
		return
	}

	vars := mux.Vars(request)
	id := vars["id"]

	err = router.contactService.DeleteContact(username, id)
	if err != nil {
		Error(response, http.StatusInternalServerError, err.Error())
		return
	}

	Json(response, http.StatusOK, "")
}

func decodeContact(request *http.Request) (root.Contact, error) {
	var contact root.Contact
	if request.Body == nil {
		return contact, errors.New("no request body")
	}
	decoder := json.NewDecoder(request.Body)
	err := decoder.Decode(&contact)
	return contact, err
}

func getCurrentUser(request *http.Request) (string, error) {
	username := request.Header.Get("X-User")
	log.Println("Username", username)
	if (username == "") {
		return username, errors.New("no username found")
	}
	return username, nil
}

Hi Cretzel,
You can use a middleware to deal with authentication. For example, you can use a middleware to verify that the user was correctly authenticated and then save it into a “context”:

Later, you can retrieve that user from your handlers:


I made the previous project to learn GO as well :slight_smile:

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.