Configuration

  • Di production, semua konfigurasi dimasukkan ke dalam environment server

  • Di development, semua konfigurasi akan dibaca dari file .env

  • Konfigurasi yang akan diatur meliputi : port server, database driver, database connection

  • Sebagai tambahan dibuat konfigurasi penanda apakah aplikasi berjalan di production atau lokal

  • Buat file .env yang isinya

APP_PORT=0.0.0.0:9000
APP_ENV=local

DB_DRIVER=mysql
DB_SOURCE=root:pass@tcp(localhost:3306)/essentials?parseTime=true
  • Kemudian buat library untuk membaca file .env dan menyalinnya ke environment OS. Buat file libraries/config/config.go

package config

import (
    "io/ioutil"
    "os"
    "strings"
)

//Setup environment from file .env
func Setup(file string) error {
    data, err := ioutil.ReadFile(file)
    if err != nil {
        return err
    }

    datas := strings.Split(string(data), "\n")
    for _, env := range datas {
        e := strings.Split(env, "=")
        if len(e) >= 2 {
            os.Setenv(strings.TrimSpace(e[0]), strings.TrimSpace(strings.Join(e[1:], "=")))
        }
    }

    return nil
}
  • Ubah file main.go agar meload file .env jika environment-nya developement atau lokal, dengan menyisipkan kode

if _, ok := os.LookupEnv("APP_ENV"); !ok {
    config.Setup(".env")
}
  • Ubah file main.go agar membaca env port saat membuat parameter server

    server := http.Server{
        Addr:         os.Getenv("APP_PORT"),
        Handler:      http.HandlerFunc(service.List),
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 5 * time.Second,
    }
  • File main.go akan menjadi seperti ini

package main

import (
    "context"
    "essentials/controllers"
    "essentials/libraries/config"
    "essentials/libraries/database"
    "log"
    "net/http"
    "os"
    "os/signal"
    "syscall"
    "time"

    _ "github.com/go-sql-driver/mysql"
)

func main() {
    if _, ok := os.LookupEnv("APP_ENV"); !ok {
        config.Setup(".env")
    }

    // =========================================================================
    // App Starting

    log.Printf("main : Started")
    defer log.Println("main : Completed")

    // =========================================================================

    // Start Database

    db, err := database.Open()
    if err != nil {
        log.Fatalf("error: connecting to db: %s", err)
    }
    defer db.Close()

    // Create variable service with pattern dependency injection.
    // Inject koneksion db to type of Users
    service := controllers.Users{Db: db}

    // parameter server
    server := http.Server{
        Addr:         os.Getenv("APP_PORT"),
        Handler:      http.HandlerFunc(service.List),
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 5 * time.Second,
    }

    serverErrors := make(chan error, 1)
    // mulai listening server
    go func() {
        log.Println("server listening on", server.Addr)
        serverErrors <- server.ListenAndServe()
    }()

    // Membuat channel untuk mendengarkan sinyal interupsi/terminate dari OS.
    // Menggunakan channel buffered karena paket signal membutuhkannya.
    shutdown := make(chan os.Signal, 1)
    signal.Notify(shutdown, os.Interrupt, syscall.SIGTERM)

    // Mengontrol penerimaan data dari channel,
    // jika ada error saat listenAndServe server maupun ada sinyal shutdown yang diterima
    select {
    case err := <-serverErrors:
        log.Fatalf("error: listening and serving: %s", err)

    case <-shutdown:
        log.Println("caught signal, shutting down")

        // Jika ada shutdown, meminta tambahan waktu 5 detik untuk menyelesaikan proses yang sedang berjalan.
        const timeout = 5 * time.Second
        ctx, cancel := context.WithTimeout(context.Background(), timeout)
        defer cancel()

        if err := server.Shutdown(ctx); err != nil {
            log.Printf("error: gracefully shutting down server: %s", err)
            if err := server.Close(); err != nil {
                log.Printf("error: closing server: %s", err)
            }
        }
    }

    log.Println("done")
}
  • Ubah file libraries/database/database.go

package database

import (
    "database/sql"
    "os"
)

//Open : open database
func Open() (*sql.DB, error) {
    return sql.Open(os.Getenv("DB_DRIVER"), os.Getenv("DB_SOURCE"))
}
  • Ubah file cmd/main.go menjadi seperti berikut :

package main

import (
    "essentials/libraries/config"
    "essentials/libraries/database"
    "essentials/schema"
    "flag"
    "log"
    "os"

    _ "github.com/go-sql-driver/mysql"
)

func main() {

    if _, ok := os.LookupEnv("APP_ENV"); !ok {
        config.Setup(".env")
    }

    // Start Database
    db, err := database.Open()
    if err != nil {
        log.Fatalf("error: connecting to db: %s", err)
    }
    defer db.Close()

    // Handle cli command
    flag.Parse()

    switch flag.Arg(0) {
    case "migrate":
        if err := schema.Migrate(db); err != nil {
            log.Println("error applying migrations", err)
            os.Exit(1)
        }
        log.Println("Migrations complete")
        return

    case "seed":
        if err := schema.Seed(db); err != nil {
            log.Println("error seeding database", err)
            os.Exit(1)
        }
        log.Println("Seed data complete")
        return
    }
}

Last updated