2017-10-05 14 views
-1

J'ai un cas où le serveur répondra avec objet d'erreur json lorsque la demande a échoué pour une raison quelconque, le serveur répond toujours avec HTTP 200. Donc, dans le cas où mon jeton a expiré et je demande des informations d'utilisateur par exemple .:JSON incorrect est structuré sans erreur

type Person struct { FirstName string LastName string }

Au lieu d'obtenir {"FirstName": "Bob", "LastName": "Smith"} Je suis fourni avec {"error":401, "msg":"Unauthorized"}

J'ai une fonction qui prend interface{} pour unmarshalling:

func (ah *APIHandler) getObjectFromJson(bodyResponse string, target interface{}) *ServerError { 
    parsingError := json.NewDecoder(strings.NewReader(bodyResponse)).Decode(target) 
    // when server responds with ServerError I expect to get persingError here and proceed to unmarshalling the error message 
    if parsingError != nil { 
     fmt.Println(parsingError.Error()) 
     var err *ServerError = &ServerError{} 
     parsingError = json.NewDecoder(strings.NewReader(bodyResponse)).Decode(err) 
     if parsingError != nil { 
      // this means unmarshalling ServerError failed 
      panic(parsingError.Error()) 
     } 
     return err 
    } 
    return nil 
} 

Mettre dans un exemple de travail, quand je fournis JSON incorrect passé interface{} j'attendre à obtenir erreur dans la console « JSON ne correspond pas à struct », pas struct vide. Est-ce possible? J'ai plus de 50 modèles, donc idéalement je voudrais éviter d'écrire unmarshaller pour chacun d'entre eux pour vérifier si les champs ont été correctement dégroupés, aussi je voudrais éviter d'écrire if strings.Contains(responseBody, "error") car certains des objets peuvent contenir des erreurs de chaîne dans leur.

https://play.golang.org/p/vecLomIXeB

+0

Si vous ne pouvez pas incorporer des modèles ou écrire déballeurs, vous pouvez toujours décoder dans une interface '{}' map: https://play.golang.org/p/ewks8sHz99. Pas la meilleure solution cependant. – abhink

+0

@abhink Oui, mais voir que j'ai +50 modèles, au total +600 champs, ne peut pas le faire manuellement. – agilob

+0

A part: Si '* ServerError' implémente' error', changez la signature de votre fonction pour retourner 'error'. Voir https://golang.org/doc/faq#nil_error – Peter

Répondre

4

La bibliothèque standard ignore toujours les champs non mappées lors du décodage. C'est ce que vous voulez, car sinon vous ne pourriez pas ajouter de nouveaux champs à vos modèles sans casser tous les consommateurs de ces modèles. Au lieu de vérifier les champs non reconnus, vérifiez si la réponse contient le champ d'erreur, soit en déchaînant deux fois, soit en analysant le champ d'erreur en plus des données attendues. Vous faites déjà cela, mais vous l'avez fait dans l'autre sens.

func (ah *APIHandler) getObjectFromJson(bodyResponse string, target interface{}) *ServerError { 
    b := []byte(bodyResponse) 

    se := &ServerError{} 
    if err := json.Unmarshal(b, &se); err != nil { 
      // ... 
    } 
    if se.Error != "" { 
      return se 
    } 

    if err := json.Unmarshal(b, target); err != nil { 
      // ... 
    } 

    return nil 
} 
+0

Merci, bonne idée, mieux que de faire la carte de la cible, puis de convertir la carte en structure, fonctionne également sur chaque structure puisque 'ServerError' est toujours le même, mais' target 'n'est pas. – agilob