# 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

```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

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

* Ubah file main.go agar membaca env port saat membuat parameter server

```go
    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

```go
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

```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 :

```go
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
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://golang-microservices.rijalasepnugroho.com/build-rest-api-framework/configuration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
