title: How to implement a fragmented config file validation in go
body: <p>I try to configure a CLI app via config file (yaml). The app has several "components" (lets say a persistence layer, an integrated web server etc.). Those components are managed in subpackages to keep the code tidy. The configuration of those components is defined inside their packages
  and "merged" in a config package to a struct that represents the config file. See this code as a demo implementation:</p>
  
  <pre><code>package main
  
  import (
      "errors"
      "fmt"
  
      yaml "gopkg.in/yaml.v2"
  )
  
  //
  // This would be in package 'webserver'
  // Only the Config part is shown, there would be a constructor and the implementation of
  // the webserver as well...
  //
  
  // WebserverConfig holds all required configuration params
  type WebserverConfig struct {
      Listen    string `yaml:"listen"`
      Autostart bool   `yaml:"autostart"`
  }
  
  // Validate checks if all fields make sense and returns a list of error string if problems
  // are found
  func (wsc WebserverConfig) Validate() (error, []string) {
      errs := []string{}
      if wsc.Listen == "" {
          errs = append(errs, "Field 'listen' must not be empty.")
      }
      if len(errs) &gt; 0 {
          err := errors.New("Config of 'webserver' has errors")
          return err, errs
      }
      return nil, errs
  }
  
  // UnmarshalYAML implements a custom unmarshaller to make sure defaults are set
  // to meaningful values
  func (wsc *WebserverConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
      type WebserverConfigDefaulted WebserverConfig
      var defaults = WebserverConfigDefaulted{
          Listen:    ":8080",
          Autostart: true,
      }
  
      out := defaults
      err := unmarshal(&amp;out)
      *wsc = WebserverConfig(out)
      return err
  }
  
  //
  // This would be in package conf
  //
  //
  
  // Config is the global configuration composed of all component configuration sections
  type Config struct {
      Webserver WebserverConfig `yaml:"webserver"`
  }
  
  // Load reads the bytes into the global config
  func Load(data string) (Config, error) {
      c := Config{}
      err := yaml.Unmarshal([]byte(data), &amp;c)
      if err != nil {
          return c, fmt.Errorf("Error while unmarshalling configuration from yaml: %s", err.Error())
      }
      return c, nil
  }
  
  // Validate should call each individual component configurations validate function (if it exists)
  func (c Config) Validate() error {
      // TODO: IMPLEMPNT...
      return nil
  }
  
  //
  // This is finally in main
  //
  //
  
  var yamlFile = `---
  webserver:
    listen: ":9999" 
  `
  
  func main() {
      c, err := Load(yamlFile)
      if err != nil {
          fmt.Println(err)
      }
      err = c.Validate()
      if err != nil {
          fmt.Println(err)
      }
  }
  </code></pre>
  
  <p>Find it on the playground here (does not run because of the dep to yaml): <a href="https://play.golang.org/p/i3EAZJP7aYz" rel="nofollow noreferrer">https://play.golang.org/p/i3EAZJP7aYz</a></p>
  
  <p>QUESTION: At this point I have no idea how the global validation function <code>func (c Config) Validate() error</code> could be implemented to call all Validate funcs of the 'component configurations' (such as <code>func (wsc WebserverConfig) Validate() (error, []string)</code>). Any idea or hints?</p>