11import Foundation
22import GraphQL
33
4- /// A general response. This object's type is used to triage to other, more specific response objects.
5- struct Response : Equatable , JsonEncodable {
6- let type : ResponseMessageType
7- }
8-
94/// A websocket `connection_ack` response from the server to the client
105public struct ConnectionAckResponse : Equatable , JsonEncodable {
11- let type : ResponseMessageType
6+ public let type : ResponseMessageType = . connectionAck
127 public let payload : [ String : Map ] ?
138
14- init ( _ payload: [ String : Map ] ? = nil ) {
15- type = . connectionAck
9+ public init ( payload: [ String : Map ] ? = nil ) {
1610 self . payload = payload
1711 }
12+
13+ public init ( from decoder: any Decoder ) throws {
14+ let container = try decoder. container ( keyedBy: Self . CodingKeys. self)
15+ if try container. decode ( ResponseMessageType . self, forKey: . type) != . connectionAck {
16+ throw DecodingError . dataCorrupted ( . init( codingPath: decoder. codingPath, debugDescription: " type must be `connection_ack` " ) )
17+ }
18+ payload = try container. decodeIfPresent ( [ String : Map ] . self, forKey: . payload)
19+ }
1820}
1921
2022/// A websocket `next` response from the server to the client
2123public struct NextResponse : Equatable , JsonEncodable {
22- let type : ResponseMessageType
24+ public let type : ResponseMessageType = . next
2325 public let payload : GraphQLResult ?
2426 public let id : String
2527
26- init ( _ payload: GraphQLResult ? = nil , id: String ) {
27- type = . next
28+ public init ( payload: GraphQLResult ? , id: String ) {
2829 self . payload = payload
2930 self . id = id
3031 }
32+
33+ public init ( from decoder: any Decoder ) throws {
34+ let container = try decoder. container ( keyedBy: Self . CodingKeys. self)
35+ if try container. decode ( ResponseMessageType . self, forKey: . type) != . next {
36+ throw DecodingError . dataCorrupted ( . init( codingPath: decoder. codingPath, debugDescription: " type must be `next` " ) )
37+ }
38+ payload = try container. decodeIfPresent ( GraphQLResult . self, forKey: . payload)
39+ id = try container. decode ( String . self, forKey: . id)
40+ }
3141}
3242
3343/// A websocket `complete` response from the server to the client
3444public struct CompleteResponse : Equatable , JsonEncodable {
35- let type : ResponseMessageType
45+ public let type : ResponseMessageType = . complete
3646 public let id : String
3747
38- init ( id: String ) {
39- type = . complete
48+ public init ( id: String ) {
4049 self . id = id
4150 }
51+
52+ public init ( from decoder: any Decoder ) throws {
53+ let container = try decoder. container ( keyedBy: Self . CodingKeys. self)
54+ if try container. decode ( ResponseMessageType . self, forKey: . type) != . complete {
55+ throw DecodingError . dataCorrupted ( . init( codingPath: decoder. codingPath, debugDescription: " type must be `complete` " ) )
56+ }
57+ id = try container. decode ( String . self, forKey: . id)
58+ }
4259}
4360
4461/// A websocket `error` response from the server to the client
4562public struct ErrorResponse : Equatable , JsonEncodable {
46- let type : ResponseMessageType
63+ public let type : ResponseMessageType
4764 public let payload : [ GraphQLError ]
4865 public let id : String
4966
@@ -63,19 +80,36 @@ public struct ErrorResponse: Equatable, JsonEncodable {
6380}
6481
6582/// The supported websocket response message types from the server to the client
66- enum ResponseMessageType : String , Codable {
67- case connectionAck = " connection_ack "
68- case next
69- case error
70- case complete
71- case unknown
72-
73- init ( from decoder: Decoder ) throws {
74- guard let value = try ? decoder. singleValueContainer ( ) . decode ( String . self) else {
75- self = . unknown
76- return
77- }
78- self = ResponseMessageType ( rawValue: value) ?? . unknown
83+ public struct ResponseMessageType : Equatable , Codable , Sendable {
84+ // This is implemented as a struct with only public static properties, backed by an internal enum
85+ // in order to grow the list of accepted response types in a non-breaking way.
86+
87+ let type : ResponseType
88+
89+ init ( type: ResponseType ) {
90+ self . type = type
91+ }
92+
93+ public init ( from decoder: any Decoder ) throws {
94+ let container = try decoder. singleValueContainer ( )
95+ type = try container. decode ( ResponseType . self)
96+ }
97+
98+ public func encode( to encoder: any Encoder ) throws {
99+ var container = encoder. singleValueContainer ( )
100+ try container. encode ( type)
101+ }
102+
103+ public static let connectionAck : Self = . init( type: . connectionAck)
104+ public static let next : Self = . init( type: . next)
105+ public static let complete : Self = . init( type: . complete)
106+ public static let error : Self = . init( type: . error)
107+
108+ enum ResponseType : String , Codable {
109+ case connectionAck = " connection_ack "
110+ case next
111+ case complete
112+ case error
79113 }
80114}
81115
0 commit comments