title: Cast interface to concrete type - type switch
body: <p>I am looking for a way to cast an interface into the concrete type to save a lot of source code.</p>
  <p>The initial situation are two functions of a webserver handler. They differ only in that one function decodes an array of structs and the other decodes a single struct and stores it in the database. The functions which have to be called for saving are identical depending on the type.</p>
  <p>To decide whether an array or a struct is passed, it is tried to cast the interface into the type and then to pass this appropriately as a parameter of the function. Similar as it is described in the <a href="https://golang.org/ref/spec#Type_switches" rel="nofollow noreferrer">documentation</a> and in the stackoverflow <a href="https://stackoverflow.com/a/38186057/7652996">post</a>.</p>
  <p>However, I do not get the concrete type as expected and the program always runs into the default section. What am I doing wrong or have I not taken into account?</p>
  <p>These are the outputs of the default section:</p>
  <pre><code># interface is a struct
  ... or a single repository struct: map[string]interface{}
  
  # interface is an array of structs
  ... or a single repository struct: []interface{}
  </code></pre>
  <p>Below is the source code with the functions</p>
  <pre class="lang-golang prettyprint-override"><code>func (rh *RouteHandler) AddOrUpdateRepository(rw http.ResponseWriter, req *http.Request) {
      repository := new(types.Repository)
      rh.addOrUpdateRepositories(rw, req, repository)
  }
  
  func (rh *RouteHandler) AddOrUpdateRepositories(rw http.ResponseWriter, req *http.Request) {
      repositories := make([]*types.Repository, 0)
      rh.addOrUpdateRepositories(rw, req, repositories)
  }
  
  func (rh *RouteHandler) addOrUpdateRepositories(rw http.ResponseWriter, req *http.Request, v interface{}) {
      defer req.Body.Close()
  
      switch req.Header.Get(&quot;Content-Type&quot;) {
      case &quot;application/xml&quot;:
          xmlDecoder := xml.NewDecoder(req.Body)
          err := xmlDecoder.Decode(&amp;v)
          if err != nil {
              rw.WriteHeader(http.StatusInternalServerError)
              fmt.Fprintf(rw, &quot;Failed to decode repositories or repository&quot;)
              rh.ulogger.Error(&quot;Failed to decode repositories or repository: %v&quot;, err)
              return
          }
      case &quot;application/json&quot;:
          fallthrough
      default:
          jsonDecoder := json.NewDecoder(req.Body)
          err := jsonDecoder.Decode(&amp;v)
          if err != nil {
              rw.WriteHeader(http.StatusInternalServerError)
              fmt.Fprintf(rw, &quot;Failed to decode repositories or repository&quot;)
              rh.ulogger.Error(&quot;Failed to decode repositories or repository: %v&quot;, err)
              return
          }
      }
  
      var err error
      switch x := v.(type) {
      case map[string]*types.Repository:
          for _, repository := range x {
              err = rh.manager.AddOrUpdateRepository(context.Background(), repository)
          }
      case *types.Repository:
          err = rh.manager.AddOrUpdateRepository(context.Background(), x)
      case map[string][]*types.Repository:
          for i := range x {
              for j := range x[i] {
                  err = rh.manager.AddOrUpdateRepository(context.Background(), x[i][j])
              }
          }
      case []*types.Repository:
          err = rh.manager.AddOrUpdateRepository(context.Background(), x...)
      case nil:
          rw.WriteHeader(http.StatusInternalServerError)
          fmt.Fprintf(rw, &quot;Failed to cast interface&quot;)
          rh.ulogger.Error(&quot;Failed to cast interface. Interface is a type of nil&quot;)
          return
      default:
          rw.WriteHeader(http.StatusInternalServerError)
          fmt.Fprintf(rw, &quot;Failed to cast interface&quot;)
          rh.ulogger.Error(&quot;Failed to cast interface. Interface does not match onto an array of repositories or a single repository struct: %T&quot;, x)
          return
      }
  
      if err != nil {
          rw.WriteHeader(http.StatusInternalServerError)
          fmt.Fprintf(rw, &quot;Failed to add repositories or repository&quot;)
          rh.ulogger.Error(&quot;Failed to add repositories or repository: %v&quot;, err)
          return
      }
      rw.WriteHeader(http.StatusCreated)
  
  }
  </code></pre>
  <p><a href="https://i.stack.imgur.com/jbfiv.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/jbfiv.png" alt="enter image description here" /></a></p>