Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Siesta edit fetched entity

I'm building an API client using Siesta and Swift 3 on Xcode 8. I want to be able to fetch an entity using a Siesta resource, then update some of the data and do a patch to the API.

The issue is that having an entity, if I save the JSON arrays in my entity fields I can't send them back to the server, I get the following error:

▿ Siesta.RequestError
  - userMessage: "Cannot send request"
  - httpStatusCode: nil
  - entity: nil
  ▿ cause: Optional(Siesta.RequestError.Cause.InvalidJSONObject())
    - some: Siesta.RequestError.Cause.InvalidJSONObject
  - timestamp: 502652734.40489101

My entity is:

import SwiftyJSON
import Foundation
struct Order {
    let id: String?
    let sessionId: String?
    let userId: Int?
    let status: String?
    let comment: String?
    let price: Float?
    let products: Array<JSON>? 

    init(json: JSON) throws {
        id          = json["id"].string
        sessionId      = json["sessionId"].string
        userId      = json["userId"].int
        status        = json["status"].string
        comment        = json["comment"].string
        price       = json["price"].float
        products   = json["products"].arrayValue

    }

    /**
     * Helper method to return data as a Dictionary to be able to modify it and do a patch
     **/
    public func toDictionary() -> Dictionary<String, Any> {
        var dictionary: [String:Any] = [
            "id": id ?? "",
            "sessionId": sessionId ?? "",
            "userId": userId ?? 0,
            "status": status ?? "",
            "comment": comment ?? ""
        ]
        dictionary["products"] = products ?? []

        return dictionary
    }
}

What I'm doing is:

 MyAPI.sessionOrders(sessionId: sessionId).request(.post, json: ["products": [["product": productId, "amount": 2]], "comment": "get Swifty"]).onSuccess() { response in
    let createdObject : Order? =  response.typedContent()
    expect(createdObject?.sessionId).to(equal(sessionId))
    expect(createdObject?.comment).to(equal("get Swifty"))
    expect(createdObject?.products).to(haveCount(1))
    expect(createdObject?.price).to(equal(product.price! * 2))

    if let createdId = createdObject?.id {
        var data = createdObject?.toDictionary()
        data?["comment"] = "edited Swifty" // can set paid because the user is the business owner
        MyAPI.order(id: createdId).request(.patch, json: data!).onSuccess() { response in
            result = true

        }.onFailure() { response in
                dump(response) //error is here
        }
    }
}

Resources:

func sessionOrders( sessionId: String ) -> Resource {
    return self
        .resource("/sessions")
        .child(sessionId)
        .child("orders")
}
func order( id: String ) -> Resource {
    return self
        .resource("/orders")
        .child(id)
}

Transformers:

    self.configureTransformer("/sessions/*/orders", requestMethods: [.post, .put]) {
        try Order(json: ($0.content as JSON)["data"])
    }

    self.configureTransformer("/orders/*") {
        try Order(json: ($0.content as JSON)["data"])
    }

I've managed to circle this by creating dictionary structures like:

let products: Array<Dictionary<String, Any>>?

    products   = json["products"].arrayValue.map({
        ["product": $0.dictionaryValue["product"]!.stringValue, "amount": $0.dictionaryValue["amount"]!.intValue]
    })

But I live in a hell of downcasts if I need to modify anything:

var data = createdObject?.toDictionary()
data?["comment"] = "edited Swifty" 
//if I want to modify the products...
var products = data?["products"] as! Array<Dictionary<String, Any>>
products[0]["amount"] = 4
data?["products"] = products

How can I send those original JSON arrays with Siesta? They're really easy to modify and read! I've browsed the siesta docs and github issues with no success...

like image 402
SkarXa Avatar asked Jul 07 '26 17:07

SkarXa


1 Answers

Your problem is a mismatch between SwiftyJSON and Foundation’s JSONSerialization; Siesta just happens to be in the middle of it.

InvalidJSONObject is Siesta telling you that Foundation doesn’t understand the thing you gave it — which would be the value returned by your toDictionary() method. Most of the things in that dictionary look fine: strings, ints, a float. (Careful about using float for money, BTW.)

The culprit is that products array: it’s [JSON], where JSON is a SwiftyJSON type that Foundation doesn’t know what to do with. You should be in the clear if you turn the JSON values back into simple dictionaries:

dictionary["products"] = (products ?? []).map { $0.dictionaryObject }

If that doesn’t do it, or if you need to diagnose a similar error in the future, remove all the values from the offending dictionary and then add them back in one at a time to see which one is tripping up JSONSerialization.

like image 95
Paul Cantrell Avatar answered Jul 10 '26 12:07

Paul Cantrell



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!