Search code examples
arraysjsonswiftvapor

Swift Vapor wrong decoding of array of objects


I'm trying to pass an array of objects inside another object

struct CreationData: Encodable {
  enum CodingKeys: String, CodingKey {
    case property1
    case amount
    case participants
    case code
  }

  var property1: String?
  var amount: Double?
  var tipAmount: Double?
  var participants: [Participant]
  var currency: Currency

  init() {
    name = nil
    property1 = nil
    participants = []
    tipAmount = nil
    currency = .hryvna
  }

  func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    if let name = name {
      try container.encode(name, forKey: .name)
    }
    if let property1 = property1 {
      try container.encode(property1, forKey: .property1)
    }
    if let tipAmount = tipAmount {
      try container.encode(tipAmount, forKey: .tipAmount)
    }
    if !participants.isEmpty {
      try container.encode(participants, forKey: .participants)
    }
    try container.encode(currency, forKey: .currencyCode)
  }
}

where object in array is

struct Participant: Hashable, Encodable {
  enum CodingKeys: String, CodingKey {
    case amount
    case id
  }

  var image: Data?
  var displayName: String
  var amount: Double? = 100
  var id: Int?

  var name: String?

  var isSelected: Bool = false

  func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(amount, forKey: .amount)
    try container.encode(id, forKey: .id)
  }

}

so my JSON looks something like this

{
  "property1" : 123,
  "code" : "zen",
  "name" : "No name",
  "participants" : [
    {
      "amount" : 100,
      "id" : 1
    }
  ]
}

On the backend I use this handler

func createHandler(_ req: Request, splitCreate: Create) throws -> Future<SplitResponse> {
    let logger = try req.make(Logger.self)
    let user = try req.requireAuthenticated(User.self)
    guard let id = user.id else {
      throw Abort(.badRequest, reason: "Couldn't get an id for current user")
    }

    ...

with this request content object

struct Create: Content {
    struct Participant: Content {
      var id: Int?
      var amount: Double?
    }

    var amount: Double?
    var tipAmount: Double?
    var name: String?
    var participants: [Participant]
    var currencyCode: String
  }

I create pivots by the participants array, and the problem is that instead of getting a single participant from an array like so

[App.Create.Participant(id: Optional(1), amount: Optional(100.0))]

on the backend from the specified JSON I get these participants

[App.Create.Participant(id: Optional(1), amount: nil), App.Create.Participant(id: Optional(1), amount: Optional(100.0))]

Seems like my array json is being decoded incorrectly, but I'm unable to find a way to fix it


Solution

  • For some reason adding Content-Type header to URLSessionConfiguration.additionalHeaders didn't change the encoding to JSON. So I had to set Alamofire's request encoding to JSONEncoding.default explicitly.