title: Swift Codable: Decode different array of items with same root objects
body: <p>I'm currently trying to decode JSON which looks like this:</p>
  
  <pre class="lang-json prettyprint-override"><code>{
    "result": {
      "success": true,
      "items": [
        {
          "timeEntryID": "1",
          "start": "1519558200",
          "end": "1519563600",
          "customerName": "Test-Customer",
          "projectName": "Test-Project",
          "description": "Entry 1",
        },
        {
          "timeEntryID": "2",
          "start": "1519558200",
          "end": "1519563600",
          "customerName": "Test-Customer",
          "projectName": "Test-Project",
          "description": "Entry 2",
        }
      ],
      "total": "2"
    },
    "id": "1"
  }
  </code></pre>
  
  <p>The decoding process for this specific type of JSON is pretty simple. I just need something like this:</p>
  
  <pre class="lang-swift prettyprint-override"><code>struct ResponseKeys: Decodable {
      let result: ResultKeys
  
      struct ResultKeys: Decodable {
          let success: Bool
          let items: [Item]
      }
  }
  </code></pre>
  
  <p>Now the problem I'm facing is that every response of the server has the same structure as the above JSON but with different item types. So sometimes it is <code>let items: [Item]</code> but it could also be <code>let items: [User]</code> if I make a call to the User endpoint. </p>
  
  <p>Because it would be an unnecessary duplication of code if I would write the above swift code for every endpoint with just the modification of the items array, I created a custom decoder:</p>
  
  <pre class="lang-swift prettyprint-override"><code>enum KimaiAPIResponseKeys: String, CodingKey {
      case result
  
      enum KimaiResultKeys: String, CodingKey {
          case success
          case items
      }
  }
  
  struct Activity: Codable {
      let id: Int
      let description: String?
      let customerName: String
      let projectName: String
      let startDateTime: Date
      let endDateTime: Date
  
      enum CodingKeys: String, CodingKey {
          case id = "timeEntryID"
          case description
          case customerName
          case projectName
          case startDateTime = "start"
          case endDateTime = "end"
      }
  }
  
  extension Activity {
  
      init(from decoder: Decoder) throws {
          let resultContainer = try decoder.container(keyedBy: KimaiAPIResponseKeys.self)
          let itemsContainer = try resultContainer.nestedContainer(keyedBy: KimaiAPIResponseKeys.KimaiResultKeys.self, forKey: .result)
          let activityContainer = try itemsContainer.nestedContainer(keyedBy: Activity.CodingKeys.self, forKey: .items)
  
          id = Int(try activityContainer.decode(String.self, forKey: .id))!
          description = try activityContainer.decodeIfPresent(String.self, forKey: .description)
          customerName = try activityContainer.decode(String.self, forKey: .customerName)
          projectName = try activityContainer.decode(String.self, forKey: .projectName)
          startDateTime = Date(timeIntervalSince1970: Double(try activityContainer.decode(String.self, forKey: .startDateTime))!)
          endDateTime = Date(timeIntervalSince1970: Double(try activityContainer.decode(String.self, forKey: .endDateTime))!)
      }
  
  }
  </code></pre>
  
  <p>The decoder works perfectly if <code>"items"</code> does only contain a single object and not an array:</p>
  
  <pre class="lang-json prettyprint-override"><code>{
    "result": {
      "success": true,
      "items":
        {
          "timeEntryID": "2",
          "start": "1519558200",
          "end": "1519563600",
          "customerName": "Test-Customer",
          "projectName": "Test-Project",
          "description": "Entry 2",
        },
      "total": "2"
    },
    "id": "1"
  }
  </code></pre>
  
  <p>If <code>items</code> is an array I get the following error:</p>
  
  <blockquote>
    <p>typeMismatch(Swift.Dictionary, Swift.DecodingError.Context(codingPath: [__lldb_expr_151.KimaiAPIResponseKeys.result], debugDescription: "Expected to decode Dictionary but found an array instead.", underlyingError: nil))</p>
  </blockquote>
  
  <p><strong>I just cannot figure out how to modify my decoder to work with an array of items.</strong> I created a Playground file with the working and not working version of the JSON. Please take a look and try it out: <a href="https://drive.google.com/open?id=1sxY02bBmxB34DBynp9vkAbcA6-WVnSdi" rel="nofollow noreferrer">Decodable.playground</a></p>
  
  <p>Thank you for your help!</p>