Hot questions for Using Vapor in arrays

Question:

using swift vapor and elasticsearch, got a response like:

{ "_shards": { "failed": 0, "successful": 5, "total": 5 }, "hits": { "hits": [ { "_id": "3", "_index": "items_v1", "_score": 1.2029922, "_source": { "property1": "test", "property2": "another test", ... }, "_type": "item" }, ...

inside "hits" -> "hits" -> "_source" I got all the properties of my model "Item". How can I create an array of Items "[Item]" from this json response?


Answer:

Small enhancement, use a guard statement to avoid the nested ifs...

guard
  let dict = response as? [String : Any],
  let hits = dict["hits"] as? [String : Any],
  let hitArray = hits["hits"] as? [[String : Any]]
else
{ throw Abort}

for hit in hitArray {
   if let source = hit["_source"] {
        arrayOfItems.append(Item(with: source))
   }
}

Question:

I am sending a request to my vapor 1.5 server via Alamofire with body of type [String:Any] where Any type is a dictionary of String:String

When the request is received on the server I convert it to JSON type

 guard let reqJson = request.json else {return}

How can I loop through this JSON object and convert it to an array of [String:Any]

The body of the request I send from the client app looks like this:

 ["DHSKL3920JFLSKXFgs": 
   ["title": “some title”, 
    "body": “some body”, 
    "DHSKL3920JFLSKXFgs": "DHSKL3920JFLSKXFgs", 
    "unreadMessagesCount": 3], 

 "PKF993AVG59gkCM": 
   ["title": “some title”, 
    "body": “some body”,  
    "DHSKL39": "DHSKL39", 
     "unreadMessagesCount": 3]] 

Answer:

You can use swift4 Codable and shrink your code to 4-5 lines. Documentation

Question:

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


Answer:

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.

Question:

I make REST calls from my own server running Vapor to a Firebase server and the response is a JSON object. How can I get the the elements under "1508321173" without knowing the actual value. This represents a timestamp, so this value is always dynamic in the database.

let jsonObject:JSON = [
"EmailAddress": "damiena@gmail.com",
"PhoneNumber": 07672395038,
"RescheduledByCustomer": 
     [1508321173:
       ["BookingStatusClient": "true",
      "DateAndTime": "Fri, 20 Oct 2017 18:30"]
  ],
 "BookingNumber":"726070304"
   .
   .
   .
] 



let jsonObject:JSON?

if let arrayOfDict:Any = jsonObject?.object?["RescheduledByCustomer"]{
                print("arrayOfDict is \(arrayOfDict)") 

prints: arrayOfDict is JSON(node: Node.Node.object(["1508321173": Node.Node.object(["BookingStatusClient": Node.Node.string("true"), "DateAndTime": Node.Node.string("Fri, 20 Oct 2017 18:30")])]))

    if let underTimeStamp = arrayOfDict as? [[String: Any]]{
       print("underTstamp is \(underTstamp)")
            //it does not print anything
   //how can I get the elements under "1508321173" ?
                }          
    }

Answer:

//get the object under timeStamp 1508321173


let arrayOfTimeStamps = jsonObject?["RescheduledByCustomer"]?.object?.keys
  for timeStampKey in arrayOfTimeStamps?.array ?? [] {
   let dictUnderTstamp = jsonObject?["RescheduledByCustomer"]?.object?[timeStampKey]


            for i in (dictUnderTstamp?.object)!{
                print("i key dictUnderTstamp is \(i.key)")
                print("i value dictUnderTstamp is \(i.value)")
            }
        }