2 votes

JSONDecoder ne peut pas gérer une réponse nulle

Contexte

Je travaille avec le Base de données Firebase REST API et JSONDecoder / JSONEncoder. Cela fonctionne plutôt bien jusqu'à présent. Cependant, pour suppression des données la réponse attendue est null et JSONDecoder ne semble pas l'apprécier beaucoup.

Voici le type de requête que j'envoie via Postman et ce que je reçois en retour (données sensibles exclues).

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

Comme vous pouvez le voir, le code de réponse est 200 et le corps est null .

Error

Lorsque je reçois la réponse, voici l'erreur que j'obtiens :

Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath : [], debugDescription : "Les données fournies n'étaient pas des JSON valides", underlyingError : Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Le texte JSON ne commençait pas par un tableau ou un objet et l'option pour autoriser le texte JSON ne commençait pas par un tableau ou un objet. fragments n'a pas été définie." UserInfo={NSDebugDescription=Le texte JSON n'a pas commencé par un tableau ou un objet et l'option pour autoriser les fragments n'a pas été définie. pas commencé par un tableau ou un objet et l'option d'autoriser les fragments n'a pas été définie.}))))

J'ai essayé de créer un type personnalisé ( NoReply ) pour gérer cette situation conformément à l'article un post précédent mais en vain.

Code

C'est là que l'erreur se produit :

        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)
        }

Donc apparemment, même si j'alimente un type NoReply personnalisé (selon l'article mentionné ci-dessus), JSONDecoder n'aime pas null .

Des suggestions ?


A titre d'information, voici ce que dit la documentation sur la réponse à une opération DELETE :

Une demande DELETE réussie est indiquée par un code d'état HTTP 200 OK. avec une réponse contenant du JSON null .

4voto

jshier Points 2454

Malheureusement JSONDecoder n'expose pas le système sous-jacent JSONSerialization option ( .allowFragments ) qui supporterait les fragments JSON comme un solo null valeur. Vous pouvez essayer de transformer la réponse ou simplement d'utiliser JSONSerialization directement. Malheureusement, il n'y a rien d'élégant à faire ici.

4voto

Nick Points 123

Suivi rapide

Après quelques bidouillages réussis, la solution la plus élégante que j'ai trouvée est la combinaison de :

  • en utilisant NoReply (tel que décrit par Zoul )
  • la conversion de la null à une structure d'objet JSON vide ( {} )

Tout d'abord, la conversion :

            if "null" == String(data: data, encoding: .utf8) {
                let json = Data("{}".utf8)

qui est ensuite renvoyée à la fermeture gérant la réponse à la demande :

        resource: {
            let decoder = JSONDecoder()
            return try decoder.decode(Resource.self, from: $0)
        },

où la Ressource n'est autre que :

public struct NoReply : Décodable {}

Cela fonctionne très bien maintenant et me permet de gérer les cas DELETE et GET sur un objet inexistant où il renvoie null .

Merci pour votre aide !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X