@@ -2,48 +2,79 @@ import Foundation
22import GraphQL
33
44/// 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
5+ public struct Response : Equatable , JsonEncodable {
6+ public let type : ResponseMessageType
77}
88
99/// A websocket `connection_ack` response from the server to the client
1010public struct ConnectionAckResponse : Equatable , JsonEncodable {
11- let type : ResponseMessageType
11+ public let type : ResponseMessageType = . connectionAck
1212 public let payload : [ String : Map ] ?
1313
14- init ( _ payload: [ String : Map ] ? = nil ) {
15- type = . connectionAck
14+ public init ( payload: [ String : Map ] ? = nil ) {
1615 self . payload = payload
1716 }
17+
18+ public init ( from decoder: any Decoder ) throws {
19+ let container = try decoder. container ( keyedBy: Self . CodingKeys. self)
20+ if try container. decode ( ResponseMessageType . self, forKey: . type) != . connectionAck {
21+ throw DecodingError . dataCorrupted ( . init(
22+ codingPath: decoder. codingPath,
23+ debugDescription: " type must be ` \( ResponseMessageType . connectionAck. type) ` "
24+ ) )
25+ }
26+ payload = try container. decodeIfPresent ( [ String : Map ] . self, forKey: . payload)
27+ }
1828}
1929
2030/// A websocket `next` response from the server to the client
2131public struct NextResponse : Equatable , JsonEncodable {
22- let type : ResponseMessageType
32+ public let type : ResponseMessageType = . next
2333 public let payload : GraphQLResult ?
2434 public let id : String
2535
26- init ( _ payload: GraphQLResult ? = nil , id: String ) {
27- type = . next
36+ public init ( payload: GraphQLResult ? , id: String ) {
2837 self . payload = payload
2938 self . id = id
3039 }
40+
41+ public init ( from decoder: any Decoder ) throws {
42+ let container = try decoder. container ( keyedBy: Self . CodingKeys. self)
43+ if try container. decode ( ResponseMessageType . self, forKey: . type) != . next {
44+ throw DecodingError . dataCorrupted ( . init(
45+ codingPath: decoder. codingPath,
46+ debugDescription: " type must be ` \( ResponseMessageType . next. type) ` "
47+ ) )
48+ }
49+ payload = try container. decodeIfPresent ( GraphQLResult . self, forKey: . payload)
50+ id = try container. decode ( String . self, forKey: . id)
51+ }
3152}
3253
3354/// A websocket `complete` response from the server to the client
3455public struct CompleteResponse : Equatable , JsonEncodable {
35- let type : ResponseMessageType
56+ public let type : ResponseMessageType = . complete
3657 public let id : String
3758
38- init ( id: String ) {
39- type = . complete
59+ public init ( id: String ) {
4060 self . id = id
4161 }
62+
63+ public init ( from decoder: any Decoder ) throws {
64+ let container = try decoder. container ( keyedBy: Self . CodingKeys. self)
65+ if try container. decode ( ResponseMessageType . self, forKey: . type) != . complete {
66+ throw DecodingError . dataCorrupted ( . init(
67+ codingPath: decoder. codingPath,
68+ debugDescription: " type must be ` \( ResponseMessageType . complete. type) ` "
69+ ) )
70+ }
71+ id = try container. decode ( String . self, forKey: . id)
72+ }
4273}
4374
4475/// A websocket `error` response from the server to the client
4576public struct ErrorResponse : Equatable , JsonEncodable {
46- let type : ResponseMessageType
77+ public let type : ResponseMessageType = . error
4778 public let payload : [ GraphQLError ]
4879 public let id : String
4980
@@ -56,26 +87,54 @@ public struct ErrorResponse: Equatable, JsonEncodable {
5687 return GraphQLError ( error)
5788 }
5889 }
59- type = . error
6090 payload = graphQLErrors
6191 self . id = id
6292 }
93+
94+ public init ( from decoder: any Decoder ) throws {
95+ let container = try decoder. container ( keyedBy: Self . CodingKeys. self)
96+ if try container. decode ( ResponseMessageType . self, forKey: . type) != . error {
97+ throw DecodingError . dataCorrupted ( . init(
98+ codingPath: decoder. codingPath,
99+ debugDescription: " type must be ` \( ResponseMessageType . error. type) ` "
100+ ) )
101+ }
102+ payload = try container. decode ( [ GraphQLError ] . self, forKey: . payload)
103+ id = try container. decode ( String . self, forKey: . id)
104+ }
63105}
64106
65107/// 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
108+ public struct ResponseMessageType : Equatable , Codable , Sendable {
109+ // This is implemented as a struct with only public static properties, backed by an internal enum
110+ // in order to grow the list of accepted response types in a non-breaking way.
111+
112+ let type : ResponseType
113+
114+ init ( type: ResponseType ) {
115+ self . type = type
116+ }
117+
118+ public init ( from decoder: any Decoder ) throws {
119+ let container = try decoder. singleValueContainer ( )
120+ type = try container. decode ( ResponseType . self)
121+ }
122+
123+ public func encode( to encoder: any Encoder ) throws {
124+ var container = encoder. singleValueContainer ( )
125+ try container. encode ( type)
126+ }
127+
128+ public static let connectionAck : Self = . init( type: . connectionAck)
129+ public static let next : Self = . init( type: . next)
130+ public static let complete : Self = . init( type: . complete)
131+ public static let error : Self = . init( type: . error)
132+
133+ enum ResponseType : String , Codable {
134+ case connectionAck = " connection_ack "
135+ case next
136+ case complete
137+ case error
79138 }
80139}
81140
0 commit comments