Dan Donaldson
Dan Donaldson

Reputation: 1293

Receiving Websocket data in Swift

I'm carrying this on from this question, since the focus has changed.

I am trying to send string data from a vapor server over a websocket. The client side is where the main question is. This code successfully receives the string, which is expected to be JSON (but not absolutely guaranteed -- out of scope).

switch message {
case .data(let data):
  print("data: \(data)")

case .string(let str):
  //                    let data = str.message(using: .utf8)

  let jsonData = Data(str.utf8)
  print("string: \(jsonData)")
  do {
    struct Person : Codable {
      var name: String
    }

    let decoder = JSONDecoder()
    let people = try decoder.decode([Person].self, from: jsonData)
    print("result: \(people)")
  } catch {
    print(error.localizedDescription)
  }
}

After some very helpful guidance, sending a string such as "{\"name\": \"Bobberoo\"}" will print out

string: 20 bytes
The data couldn’t be read because it isn’t in the correct format.

If I wrap it in braces "[{\"name\": \"Bobberoo\"}]" produces the more helpful but still mystifing (to me) output:

result: [wb2_socket_client.WebSocketController.(unknown context at $101a35028).(unknown context at $101a350c0).(unknown context at $101a35158).Person(name: "Bobberoo")]

Clearly, the decoding is happening, but it's wrapped in these contexts. What are they? I can see that the first is the instance of the WebSocketController. How do I access this data.

And as a non-inflammatory aside: managing JSON is a trivial operation in any number of contexts. Python/Flask, Node, Ruby/Rails and on and on; I've used all these and implementing this kind of interaction is trivial. In Swift, it's a horrible, underdocumented nightmare. At least, that's my experience. Why? I know the language is type safe, but this is ridiculous.

Upvotes: 2

Views: 1456

Answers (1)

Sweeper
Sweeper

Reputation: 272370

error.localizedDescription won't give you an error message that is useful message for debugging. On the other hand, if you print error directly:

print(error)

You'd get something along the lines of "expected to decode array but found dictionary instead", which is exactly what is happening in the case of

{
    "name": "Bobberoo"
}

You are decoding a [Person].self, i.e. an array of Person, but your JSON root is not a JSON array. The above JSON can be decoded if you did:

let people = try decoder.decode(Person.self, from: jsonData)

Clearly, the decoding is happening, but it's wrapped in these contexts. What are they?

This is the default string representation of a type. Your Person struct does not conform to CustomStringConvertible or CustomDebugStringConvertible or TextOutputStreamable, so "an unspecified result is supplied automatically by the Swift standard library" (the link points to String.init(reflecting:), which presumably gets called somewhere along the way when you print the array of Person) and used as the string representation.

From what I can see, its current implementation is the fully qualified name of the struct - starting with the module, then the top-level class, then each enclosing scope, ending with the struct name, followed by the struct's members in brackets. It turns out that the enclosing scopes has no "names", and so are just called (unknown context at xxxxx). This is all very much implementation details, and things that you shouldn't care about.

What you should do, is provide an implementation of CustomStringConvertible:

struct Person: CustomStringConvertible {
    ...

    var description: String { "name: \(name)" }
}

Now printing people gives:

[name: Bobberoo]

I can see that the first is the instance of the WebSocketController.

No. The WebSocketController is part of the fully qualified name of your Person struct. There is exactly one instance in your decoded array, and it's an instance of Person, as you would expect!

How do I access this data?

To access its name:

if let firstPerson = people.first {
    let firstPersonsName = firstPerson.name
}

Upvotes: 6

Related Questions