Decoding Void with Swift 4’s Decodable

Viewed 4721

I have a generic REST request:

struct Request<T> {…}

The T is the return type of the request, for example:

struct Animal {…}
let animalRequest = Request<Animal>
let animal: Animal = sendRequest(animalRequest)

Now I would like to express that the generic type has to conform to Decodable so that I can decode the JSON response from the server:

struct Request<T> where T: Decodable {…}
struct Animal: Decodable {…}

This makes sense and works – until I arrive at a request that has no response, a Request<Void>. The compiler is not happy about that one:

Type 'Void' does not conform to protocol 'Decodable'

My mischevious attempt to solve this by adding the Decodable conformance to Void was quickly found out by the compiler:

extension Void: Decodable {…} // Error: Non-nominal type 'Void' cannot be extended

It feels right to have the request generic over the return type. Is there a way to make it work with Void return types? (For example the requests that just create something on the server and don’t return anything.)

2 Answers

I found that sometimes other encoded objects of another types can be decoded to NoReply.self. For example custom Error type (enum) can be.

Playground example of this case:

enum MyError: String, Codable {
    case general
}

let voidInstance = VoidResult()
let errorInstance = MyError.general
let data1 = try! JSONEncoder().encode(voidInstance)
let data2 = try! JSONEncoder().encode(errorInstance)

let voidInstanceDecoded = try! JSONDecoder().decode(VoidResult.self, from: data1)
//VoidResult as expected

let errorInstanceDecoded = try! JSONDecoder().decode(MyError.self, from: data2)
//MyError.general as expected

let voidInstanceDecodedFromError = try! JSONDecoder().decode(VoidResult.self, from: data2)
//VoidResult - NOT EXPECTED

let errorInstanceDecodedFromVoid = try! JSONDecoder().decode(ScreenError.self, from: data1)
//DecodingError.typeMismatch - Expected

So my suggestion is to add "uniqueness to NoReply (zoul's answer)):

struct VoidResult: Codable {
    var id = UUID()
}

let voidInstanceDecodedFromError = try! JSONDecoder().decode(VoidResult.self, from: data2)
//DecodingError.typeMismatch - Now its fine - as expected
Related