Reputation: 4326
This question is about how to write Encodable
definition for a custom nested struct I have. I have defined a JSON request struct as follows:
//Define type of request - get or set
enum ReqType: String, Codable {
case get,set
}
//For get request, define what request we can make
enum GetReq: String, Codable {
case getPage,getOther
}
//Request structure - reqBody for now is set to GetReq type
// to keep it simple, no sum type over GetReq and SetReq for now
struct Req {
var reqType: ReqType
var reqBody: GetReq
enum CodingKeys: String, CodingKey{
case reqType
}
}
//An incomplete attempt at encoding logic
extension Req: Encodable {
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(reqBody, forKey: .reqType)
}
}
Now, given a request say Req(reqType: ReqType.get,reqBody: GetReq.getPage)
, we want to encode it as {"get":"getPage"}
. That is, key is the string value of ReqType
enum, and value is the string value of GetReq
enum. My code above can't encode string value of ReqType
enum as key. So, it ends up encoding as {"reqType":"getPage"}
.
Will appreciate help with fixing the code to achieve the encoding where the key is string value of the enum.
Upvotes: 0
Views: 298
Reputation: 271135
Since you want ReqType
to be the key of the JSON, conform that to CodingKey
, instead of Codable
:
enum ReqType: String, CodingKey {
case get,set
}
Now you can do
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: ReqType.self)
try container.encode(reqBody, forKey: reqType)
}
In case you also need a Decodable
implementation:
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: ReqType.self)
// picks the first valid ReqType, in case the JSON has multiple keys
if let key = container.allKeys.first {
reqBody = try container.decode(GetReq.self, forKey: key)
reqType = key
} else {
throw DecodingError.valueNotFound(GetReq.self, .init(codingPath: container.codingPath, debugDescription: "No request body found!"))
}
}
Upvotes: 1