I am working with the Firebase Database REST API and JSONDecoder / JSONEncoder. It's been working pretty well so far.
However for removing data the expected returned response is null
, and JSONDecoder doesn't seem to like that very much.
This is the type of query I am sending via Postman and what I am getting back (sensitive data excluded).
DELETE /somedata/-LC03I3oHcLhQ/members/ZnWsJtrZ5UfFS6agajbL2hFlIfG2.json
content-type: application/json
cache-control: no-cache
postman-token: ab722e0e-98ed-aaaa-bbbb-123f64696123
user-agent: PostmanRuntime/7.2.0
accept: */*
host: someapp.firebaseio.com
accept-encoding: gzip, deflate
content-length: 39
HTTP/1.1 200
status: 200
server: nginx
date: Thu, 02 Aug 2018 21:53:27 GMT
content-type: application/json; charset=utf-8
content-length: 4
connection: keep-alive
access-control-allow-origin: *
cache-control: no-cache
strict-transport-security: max-age=31556926; includeSubDomains; preload
null
As you can see the response code is 200
and the body is null
.
When I receive the response this is the error I get :
Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}))))
I tried creating a custom type (NoReply
) to handle this as per a previous post but to no-avail.
This is where the error happens :
resource: {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return try decoder.decode(Resource.self, from: $0)
},
error: {
let decoder = JSONDecoder()
return try decoder.decode(FirebaseError.self, from: $0)
}
So apparently even if I feed a custom NoReply type (as per the post mentioned above) JSONDecoder doesn't like null
.
Any suggestions ?
As a side note this is what their documentation says about the response for a DELETE operation :
A successful DELETE request is indicated by a 200 OK HTTP status code with a response containing JSON
null
.
After a few successful hacks, the most elegant solution I came up with was the combination of :
NoReply
(as described by Zoul)null
string to an empty JSON object structure ({}
)So first, the conversion :
if "null" == String(data: data, encoding: .utf8) { let json = Data("{}".utf8)
which is then fed back to the closure handling the request's response :
resource: { let decoder = JSONDecoder() return try decoder.decode(Resource.self, from: $0) },
where the Resource is none other than :
public struct NoReply: Decodable {}
This works great now and allows me to handle the DELETE cases and GET cases on a non-existent object where it returns null
.
Thanks for the help !
Unfortunately JSONDecoder
does not expose the underlying JSONSerialization
option (.allowFragments
) that would support JSON fragments like a solo null
value. You could try transforming the response or just using JSONSerialization
directly. Unfortunately there's nothing elegant to be done here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With