Skip to content

how to serialize JSON objects across WAMP #11

@eliburke

Description

@eliburke

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)")
        })

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions