跳转至正文

Config Usage Guide ​

github.com/prismgo/framework/config provides a Laravel-style runtime configuration repository. Configuration files are registered as namespaces with Add, .env and system environment variables are read with Env, and application code reads values through dot paths.

Application code usually imports github.com/prismgo/framework/config directly and registers its own configuration namespaces from config/*.go.

Quick Start ​

Define a configuration namespace:

go
package config

func init() {
    Add("mail", func() map[string]interface{} {
        return map[string]interface{}{
            "host": Env("MAIL_HOST", "127.0.0.1"),
            "port": Env("MAIL_PORT", 1025),
            "from": map[string]interface{}{
                "address": Env("MAIL_FROM_ADDRESS", "noreply@example.com"),
                "name":    Env("MAIL_FROM_NAME", "prismgo"),
            },
        }
    })
}

Read configuration:

go
package service

import (
    "strconv"

    "github.com/prismgo/framework/config"
)

func mailEndpoint() string {
    host := config.GetString("mail.host", "127.0.0.1")
    port := config.GetInt("mail.port", 1025)
    return host + ":" + strconv.Itoa(port)
}

Example local .env:

dotenv
MAIL_HOST=smtp.example.com
MAIL_PORT=587
MAIL_FROM_ADDRESS=notice@example.com

What It Is For ​

github.com/prismgo/framework/config mainly solves four problems:

CapabilityPurpose
Configuration registrationRegister namespaces such as app, database, and cache with Add(name, fn)
Environment variable accessRead .env or system environment variables with Env inside registration functions
Runtime readsRead nested configuration with dot paths such as GetString("app.name")
Facade managementUse Resolve for lazy loading through the application container; tests can explicitly bind configuration instances

The configuration repository is only responsible for loading static runtime configuration. Mutable tenant settings, system parameter tables, and other business data should not be stored in this package.

Loading Flow ​

During application startup, github.com/prismgo/framework/foundation registers the configuration factory:

text
main.go
  -> bootstrap.NewApplication()
  -> foundation.NewApplication()
  -> registerConfigResource()
  -> first config.Resolve / config.GetString
  -> read .env, execute all Add registration functions, build the runtime repository

Configuration functions are executed when the repository is built, not when the package is initialized. Therefore config/*.go should preferably contain declarative structures only:

go
Add("app", func() map[string]interface{} {
    return map[string]interface{}{
        "name":  Env("APP_NAME", "prismgo"),
        "debug": Env("APP_DEBUG", false),
    }
})

If the .env file does not exist, no error is raised. The repository continues with system environment variables and default values. When .env and system environment variables are both present, explicitly provided values override defaults.

Environment Variable Function ​

Env ​

Reads one environment variable and returns the default value when the variable is missing or blank:

go
debug := config.Env("APP_DEBUG", false)
name := config.Env("APP_NAME", "prismgo")

The return value is converted according to the default value where possible. Defaults of type bool, int, int64, uint, float64, and string return the corresponding type.

Registering Configuration ​

Add(name, fn) registers a namespace in the global configuration registry. The namespace becomes the first segment of dot paths:

go
config.Add("audit", func() map[string]interface{} {
    return map[string]interface{}{
        "enabled": config.Env("AUDIT_ENABLED", true),
        "rules": map[string]interface{}{
            "prismgo": config.Env("AUDIT_PRISMGO", true),
        },
    }
})

Read it with:

go
enabled := config.GetBool("audit.enabled", true)
prismgo := config.GetBool("audit.rules.prismgo", true)

Nested maps returned by registration functions are normalized to map[string]any, so both map[string]interface{} and map[string]any are supported.

Reading Configuration ​

Common read functions:

FunctionReturn typePurpose
Get / GetStringstringString configuration
GetIntintPorts, counts, seconds, and similar values
GetInt64int6464-bit integer configuration
GetUintuintUnsigned integer configuration
GetFloat64float64Floating-point configuration
GetBoolboolFeature flags and switches
GetStringMapmap[string]anyNested configuration blocks
GetStringMapStringmap[string]stringString maps

Missing values can receive defaults:

go
appName := config.GetString("app.name", "prismgo")
debug := config.GetBool("app.debug", false)
timeout := config.GetInt("app.server.timeout", 15)

Read nested configuration:

go
server := config.GetStringMap("app.server")
channels := config.GetStringMap("logging.channels")
labels := config.GetStringMapString("map.labels")

If the path does not exist, map read functions return an empty map instead of nil.

Application Configuration Reference ​

New applications register application-level configuration in config/app.go with config.Add("app", ...). APP_* and SERVER_* values from .env override the defaults.

Base Application Configuration ​

Config PathEnvironment VariableDefaultDescription
app.nameAPP_NAMEPrismgoApplication name used when the framework displays or references the app
app.envAPP_ENVproductionCurrent environment; high-risk commands use this to decide whether --force is required
app.keyAPP_KEY""Application encryption key; see Encryption
app.debugAPP_DEBUGfalseDebug mode; must be false in production
app.urlAPP_URLhttp://localhost:8080Base URL used from CLI and other non-HTTP contexts
app.timezoneAPP_TIMEZONEUTCApplication timezone
app.localeAPP_LOCALEenDefault locale for translations
app.fallback_localeAPP_FALLBACK_LOCALEenFallback locale when a translation is missing
app.cipherAPP_CIPHERAES-256-GCMEncryption cipher; currently AES-256-GCM
app.previous_keysAPP_PREVIOUS_KEYS""Comma-separated old application keys for key rotation

HTTP Server Configuration ​

Config PathEnvironment VariableDefaultDescription
app.server.hostSERVER_HOST""Listen host
app.server.portSERVER_PORT8080Listen port
app.server.timeoutSERVER_TIMEOUT15Legacy request timeout fallback
app.server.read_timeoutSERVER_READ_TIMEOUT15sTimeout for reading full requests
app.server.read_header_timeoutSERVER_READ_HEADER_TIMEOUT5sTimeout for reading request headers
app.server.write_timeoutSERVER_WRITE_TIMEOUT30sResponse write timeout
app.server.idle_timeoutSERVER_IDLE_TIMEOUT60sKeep-alive idle timeout
app.server.shutdown_timeoutSERVER_SHUTDOWN_TIMEOUT15sGraceful shutdown timeout
app.server.max_header_bytesSERVER_MAX_HEADER_BYTES1048576Maximum request header bytes
app.server.max_multipart_memorySERVER_MAX_MULTIPART_MEMORY33554432Multipart form memory limit
app.server.trusted_proxiesSERVER_TRUSTED_PROXIES""Comma-separated trusted proxies
app.server.client_ip_headersSERVER_CLIENT_IP_HEADERSX-Forwarded-For,X-Real-IPHeaders used to resolve client IP
app.server.access_logSERVER_ACCESS_LOGtrueEnable access logging
app.server.exception_handlerSERVER_EXCEPTION_HANDLERtrueMount the unified exception handler middleware

For more HTTP server details, see HTTP Server.

Standalone Instances ​

Besides the global facade, you can create standalone Config instances. Tests, scripts, and temporary tools should prefer standalone instances to avoid polluting global configuration:

go
cfg, err := config.NewFromFile("testdata/.env")
if err != nil {
    return err
}

name := cfg.GetString("app.name", "prismgo")
debug := cfg.GetBool("app.debug", false)

Clone the current configuration:

go
clone := config.Clone()

Clone returns an isolated repository. Later Reload calls do not affect the clone and original repository together.

Facade Entry Points ​

The global default configuration of github.com/prismgo/framework/config is managed by github.com/prismgo/framework/facade.

FunctionPurpose
Resolve()Resolve the configuration repository from the current Application container
Clone()Copy the current configuration repository and return an isolated clone
Reload()Reload the current configuration object from the default .env
Empty()Check whether the current configuration repository is empty

Common test pattern:

go
func TestWithConfig(t *testing.T) {
    cfg, err := config.NewFromFile("testdata/.env")
    if err != nil {
        t.Fatal(err)
    }
    bindConfigForTest(t, cfg)

    got := config.GetString("app.name", "")
    if got == "" {
        t.Fatal("missing app name")
    }
}

Recommendations ​

  • Application code should import github.com/prismgo/framework/config first; do not repeatedly wrap environment variable reads in the business layer.
  • Use lowercase English names for configuration namespaces, such as app, database, and wechat.
  • New configuration items should be placed in config/*.go; avoid direct os.Getenv calls in services.
  • Environment variable names should settle on the current names. Do not add compatibility entries for old names from pre-release phases.
  • Provide reasonable defaults for missing values, especially ports, timeouts, and feature flags.
  • Put mutable business configuration in business tables or dedicated repositories, not in the runtime configuration repository.