Please review my configuration reader in terms of maintainability and correctness

Hi,

I’m a newbie and want to start with a web api project. For now I want to configure the log level and server port and thought about using Viper with environment variables.

I’m not sure if I should ( how ) validate the inputs and use good fallback values. I started with the following ( split into multiple files )

package configuration

import "github.com/spf13/viper"

type AppConfiguration struct { 
	LoggerConfiguration LoggerConfiguration 
	ServerConfiguration ServerConfiguration 
}

type ServerConfiguration struct { 
	Port uint16 mapstructure:"SERVER_PORT" 
}

type LoggerConfiguration struct { 
	Level string mapstructure:"LOGGER_LEVEL" 
}

func GetAppConfiguration() (AppConfiguration, error) { 
	viper.SetEnvPrefix("MYAPP") viper.AutomaticEnv()
	loggerConfiguration, err := getLoggerConfiguration()

	if err != nil {
		return AppConfiguration{}, err
	}

	serverConfiguration, err := getServerConfiguration()

	if err != nil {
		return AppConfiguration{}, err
	}

	return AppConfiguration{LoggerConfiguration: loggerConfiguration, ServerConfiguration: serverConfiguration}, nil
}

func getLoggerConfiguration() (LoggerConfiguration, error) { 
	var loggerConfiguration LoggerConfiguration
	err := viper.Unmarshal(&loggerConfiguration)

	return loggerConfiguration, err
}

func getServerConfiguration() (ServerConfiguration, error) { 
	var serverConfiguration ServerConfiguration
	err := viper.Unmarshal(&serverConfiguration)

	if err != nil {
		return ServerConfiguration{}, err
	}

	// Use a fallback value
	if serverConfiguration.Port == 0 {
		serverConfiguration.Port = 3000
	}

	return serverConfiguration, err
}

Maybe the log level doesn’t exist or the Port makes no sense. And 3000 as a fallback value is a magic number. And should I even wrap all the configs inside a AppConfiguration struct?

I’m looking for help to get a maintainable implementation that tries to achieve “correctness” by validating the fields.

Thanks in advance!