pubnub / swift

PubNub native Swift SDK for iOS, MacOS, WatchOS, TvOS
Other
31 stars 28 forks source link

Payload issue after upgrading from `3.1.0` #190

Open kacperd opened 1 month ago

kacperd commented 1 month ago

Hello!

In our project, I noticed the issue with messages payload after upgrading to the SDK version 7.0.0 (previously, we were using version 3.1.0). The problem is that the payload no longer represents the correct JSON and our parsing started to fail.

Here's the debugged value of the payload that we received in SDK 7.0.0:

                  ▿ concretePayload : action","data":{"type":"chat_updated"}}
                  ▿ value : AnyJSONType
                       - string : "action\",\"data\":{\"type\":\"chat_updated\"}}"

It looks like the beginning of the json response was removed and it's no longer interpreted as a valid JSON.

In version 3.1.0, the payload was a correct JSON.

jguz-pubnub commented 1 month ago

Hi @kacperd, could you show an example how do you publish a message with your custom payload?

kacperd commented 1 month ago

Unfortunately, I don't have access to the project that publishes messages 😞

jguz-pubnub commented 1 month ago

Here's how you could do it. Let's assume you have your custom struct (or any other type) conforming to our JSONCodable protocol:

struct YourCustomStruct: JSONCodable {
  var action: String
  var data: [String: String]
}

Then, here's how you could use publish and subscribe methods:

// Your configured PubNub instance
var pubNub: PubNub = ...
// Assumes you store a strong reference to the listener object
var listener = SubscriptionListener()

// Publish
pubNub.publish(
  channel: "your-channel",
  message: YourCustomStruct(action: "action", data: ["type": "chat_updated"])
) {
  switch $0 {
  case let .success(tt):
    debugPrint("Message successfully published at \(tt) timetoken")
  case let .failure(error):
    debugPrint("Failed to publish a message due to error \(error)")
  }
}

listener.didReceiveMessage = {
  if let decodedPayload = try? $0.payload.decode(YourCustomStruct.self) {
    debugPrint("Payload successfuly decoded to YourCustomStruct")
    // Proceed with a decodedPayload object
  } else {
    debugPrint("Failed to decode a payload")
  }
}
kacperd commented 1 month ago

Thanks for your help @jguz-pubnub. I think I was not precise enough when I first described the issue. The problem we have is that the .payload is not correct. Compare the difference in payload while using two different versions of SDK.

Here's the payload we get from PubNub SDK in version 3.1.0

 ▿ concretePayload : ["data": ["type": "chat_updated"], "event": "trade-action"]
    ▿ value : AnyJSONType
      ▿ dictionary : 2 elements
        ▿ 0 : 2 elements
          - key : "data"
          ▿ value : AnyJSONType
            ▿ dictionary : 1 element
              ▿ 0 : 2 elements
                - key : "type"
                ▿ value : AnyJSONType
                  - string : "chat_updated"
        ▿ 1 : 2 elements
          - key : "event"
          ▿ value : AnyJSONType
            - string : "trade-action"

Here's the debugged value of the payload that we received in SDK 7.0.0:


 ▿ concretePayload : action","data":{"type":"chat_updated"}}
     ▿ value : AnyJSONType
        - string : "action\",\"data\":{\"type\":\"chat_updated\"}}"

And decoding of the latter fails with:

typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found a string instead.", underlyingError: nil))

The payload in 7.0.0 is missing the "event": "trade-action".

What could be the reason for this difference?

jguz-pubnub commented 1 month ago

I did a quick test on the newest 8.0.0 version, but it should also work for 7.0.0. We haven't changed anything with regards serialization:

let messageToPublish = ["data": ["type": "chat_updated"], "event": "trade-action"] as [String : JSONCodable]

pubNub.publish(
  channel: "your-channel-name",
  message: AnyJSON(messageToPublish),
  completion: { result in
      debugPrint(result)
  }
)

Then, I was able to receive expected payload and decode it into raw dictionary:

listener.didReceiveMessage = { message in
   let decodedPayload = try? message.payload.decode([String: AnyJSON].self)
   let event = decodedPayload?["event"]?.stringOptional
   let data = decodedPayload?["data"]?.dictionaryOptional

   debugPrint("event: \(String(describing: event)), data: \(String(describing: data))")
}

Another question is, do you publish a Dictionary you mentioned from another endpoint that uses PubNub Swift SDK? Or is it a message from developer console or any other SDK like Java, Kotlin, JavaScript, etc?

kacperd commented 1 month ago

This dictionary is not published by PubNub Swift SDK. It's published by some backend service. I don't have implementation details, but I know that nothing has changed in the way the messages are published.

jguz-pubnub commented 1 month ago

Do you use another PubNub SDK on the server side or do you encode a message yourself and manually invoke our rest API and its publish method? I will test the example dictionary payload (similar to yours) for both 3.1.0 and the newest version and let you know. But it would be great to test the real message (without any confidential data) you trigger from the server side

kacperd commented 1 month ago

From the information I got, we use PubNub PHP SDK version 4.1.7 on the server.

jguz-pubnub commented 1 month ago

Could you update PHP SDK used on the server side to the newer value? The one you use is quite obsolete. I pasted your payload into our PubNub Developer Console and Debugger (you can try it out by filling up the left panel with your keys, channel and user id), published a message and I had no problems with parsing for both 3.1.0 and 7.0.0 Swift SDK versions. Here's the example payload I mentioned:

{ "data": { "type": "chat_updated" }, "event": "trade-action" }