Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to serialize JSON objects across WAMP #11

Open
eliburke opened this issue Nov 16, 2016 · 0 comments
Open

how to serialize JSON objects across WAMP #11

eliburke opened this issue Nov 16, 2016 · 0 comments

Comments

@eliburke
Copy link

It took me a while to figure out how to get this working nicely, so I thought I'd share some tips. If you want to easily serialize or ingest JSON objects through the WAMP connection the serializer can make it hard to accomplish. Many of the available frameworks want to operate directly on JSON data, or spit it out as JSON, but swamp only exposes Arrays/Dictionaries.

Fortunately I found Wrap and Unbox. Wrap is an object mapper that translates class properties into a Dictionary that can be passed to SwiftyJSON. Unbox is used with JSON, but can also accept a Dictionary to rehydrate your classes. Both handle optionals and dates and custom behaviors.

Step 1: Wrap your objects. You can do this when you are building arguments for your RPC calls, or you can do it within swamp using the following technique:

// declare a protocol or class your objects will conform to
class WampMessage: Unboxable {
}

// override _JSONSwampSerializer_ to look for your custom class/protocol
class WampMessageSwampSerializer: JSONSwampSerializer {

    open func packArray(_ arrayData:[Any]) -> [JSON] {        
        var jsonArray = [JSON]()
          for item in arrayData {
            
            if let arrayItem = item as? Array<Any> {
                let newArray = packArray(arrayItem)
                jsonArray.append(JSON(newArray))
            } else {
                do {
                    if let wampItem = item as? WampMessage {
                        let dict: [String:Any] = try wrap(wampItem)
                        jsonArray.append(JSON(dict))
                    } else {
                        jsonArray.append(JSON(item))
                    }
                } catch {
                    print("Fatal exception while packing `\(item)` into JSON")
                }
            }
        }
        return jsonArray
    }

    override func pack(_ data: [Any]) -> Data? {        
        let json = JSON(packArray(data))
        do {
            return try json.rawData()
        }
        catch let err as NSError {
            print("error = \(err.localizedDescription)")
            return nil
        }
    }
}

Step 2: Unbox the results. This example shows a WampMessage being passed in (see Step 1), but you could just as easily use bare JSON or Swift types, or convert the object inline by doing something like: let arg3: [String:Any] = try wrap(MyWampMessageObject() )

In the results block it shows a new object being initialized from the results using Unbox. If you didn't know the object type from the route being used, you might have to look at a value in the results first in order to determine what kind of object to Unbox

        let wampArgs: [Any] = [ arg1, arg2, MyWampMessageObject() ]
        swampSession.call("my.route", options: [:], args: wampArgs, kwargs: nil, onSuccess: { details, results, kwResults in
            if let results = results, let dict = results[0] as? [String:Any] {
                do {
                    let userInfo: MyWampMessageResult = try unbox(dictionary: dict)
                } catch {
                    print("failed to decode userInfo")
                }
            }
        }, onError: { details, error, args, kwargs in
            print ("ERROR: details: \(details), error: \(error), kwargs: \(kwargs)")
        })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant