Skip to main content
  1. Refs/

Golang Packages

··3 mins

Overview #

  • Cobra, Viper, GoDotEnv, Lumberjack, ZeroLog, LogRUs, Alice, Gorilla (Handlers / Mux), GDDO, Slug
  • Jwt, Unleash, Pulsar, Mongo
  • Go Text Gen

Extremely useful #

  • github.com/spf13/cobra v1.2.1
    • framework to make command line tools
  • github.com/spf13/viper v1.8.1
    • framework for config management
    • flexible and easy when dealing with files or command line params
    • not very easy to extend to deal with central config server (Java SCCS or Consul)
  • github.com/joho/godotenv v1.3.0
    • easy loading of environment variables and various files
  • github.com/natefinch/lumberjack v2.0.0+incompatible
    • makes it easy to pipe logs to various streams simultaneously (e.g. console + file)
    // log.go
    package util
    import (
      "os"
      "strings"
      "time"
    
      "github.com/natefinch/lumberjack"
      "github.com/rs/zerolog"
      "github.com/spf13/viper"
    )
    
    func NewLogger() *zerolog.Logger {
      var cw *zerolog.ConsoleWriter
      var fw *lumberjack.Logger
      if viper.GetBool("log.console.enabled") {
        cw = &zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC1123}
      }
    
      if viper.GetBool("log.file.enabled") {
        if strings.Compare(viper.GetString("log.file.name"), "") == 0 {
          viper.Set("log.file.name", "out.log")
          viper.WriteConfig()
        }
        fw = &lumberjack.Logger{
          Filename:   viper.GetString("log.file.name"),
          MaxBackups: viper.GetInt("log.file.backups"),
          MaxSize:    viper.GetInt("log.file.size"),
          MaxAge:     viper.GetInt("log.file.days"),
        }
      }
    
      if viper.GetBool("debug.enabled") {
        zerolog.SetGlobalLevel(zerolog.DebugLevel)
      } else {
        zerolog.SetGlobalLevel(zerolog.InfoLevel)
      }
    
      multi := zerolog.MultiLevelWriter(cw, fw)
    
      log := zerolog.New(multi).With().Timestamp().Logger()
    
      return &log
    }
    
  • github.com/rs/zerolog v1.23.0
    • like this because it was easy to wrap requests and trace them from the router down through the various layers
    • hlog assigns a request ID for each request (see alice example below)
  • github.com/sirupsen/logrus v1.7.0
  • github.com/justinas/alice v1.2.0
    • alice makes chaining midware together simpler and cleaner
    chain := alice.New()
    chain = chain.Append(hlog.NewHandler(*log))
    chain = chain.Append(hlog.RemoteAddrHandler("ip"))
      chain = chain.Append(hlog.UserAgentHandler("user_agent"))
      chain = chain.Append(hlog.RefererHandler("referer"))
      chain = chain.Append(hlog.RequestIDHandler("req_id", "Request-Id"))
    handler := chain.Then(sm)
    
  • github.com/gorilla/handlers v1.5.1
    • midware to handle CORS
    import gohandlers "github.com/gorilla/handlers"
      corsWrapper := gohandlers.CORS(
      	gohandlers.AllowedOrigins([]string{"*"}),
      	gohandlers.AllowedHeaders([]string{"Content-Type"}),
      	gohandlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"}),
      )
      srv := http.Server{
      	Addr:         bindAddress + port,
      	Handler:      corsWrapper(handler),
      }
    
  • github.com/gorilla/mux v1.8.0
    • mux allowed me to create open router + secure / password protected routes
    // InitRouters sets up both secure and open routers
    func InitRouters(log *zerolog.Logger, sh *Handler) *mux.Router {
      sm := mux.NewRouter()
      log.Debug().Msg("Setting route / method handling")
      newRouterSetUp(sm, sh)
      newSecureRouterSetUp(sm, sh, log)
    
      // swagger:route GET /error default notFound
      // Return custom not found message
      // responses:
      //	404: errorResponse
      sm.NotFoundHandler = sm.NewRoute().HandlerFunc(sh.NotFound).GetHandler()
    
      return sm
    }
    // newRouterSetUp creates a new Router with all of the unsecured subRouters required for the API
    func newRouterSetUp(sm *mux.Router, sh *Handler) {
    
      // swagger:route GET / default getRoot
      // Return default success message
      // responses:
      //	200: successResponse
      getRootRouter := sm.Methods(http.MethodGet, http.MethodOptions).Subrouter()
      getRootRouter.HandleFunc("", sh.GetRoot)
      getRootRouter.HandleFunc("/", sh.GetRoot)
    }
    // newSecureRouterSetUp creates a new Router with all of the secured subRouters required for the API
    func newSecureRouterSetUp(sm *mux.Router, sh *Handler, log *zerolog.Logger) {
    
      r := sm.PathPrefix("/api").Subrouter()
    
      // GET /api/cars
      listCarsRouter := r.PathPrefix("/cars").Methods(http.MethodGet, http.MethodOptions).Subrouter()
      listCarsRouter.HandleFunc("", util.ValidateApiKey(sh.GetCars))
      listCarsRouter.HandleFunc("/", util.ValidateApiKey(sh.GetCars))
    
      // swagger:route POST /cars cars importCars
      // Create multiple new hashCars
      // Requires emails array in body
      // responses:
      //	200: successResponse
      addCarsRouter := r.PathPrefix("/cars").Methods(http.MethodPost, http.MethodOptions).Subrouter()
      addCarsRouter.Path("").HandlerFunc(util.ValidateApiKey(sh.AddCars))
      addCarsRouter.Path("/").HandlerFunc(util.ValidateApiKey(sh.AddCars))
      }
    
  • github.com/golang/gddo v0.0.0-20200831202555-721e228c7686
    • contains httputil/header package which is useful in setting header values in REST response
  • github.com/gosimple/slug v1.9.0
    • slugifies strings (e.g. This is Rishi's Blog -> this-is-rishis-blog)

Project / Technology specific #

Mine 🎉 #