2016-08-20 5 views
1

Ich benutze eine Bibliothek (Go-kit), die erfordert, dass ich Funktionen zum Codieren/Decodieren meiner Anfrage und Antworttypen zu/von JSON angeben. Für die Codierung ist es einfach:Golang JSON-Decodierung kann Schnittstelle nicht decodieren {}

Ich übergeben diese Funktion, um den HTTP-Server zu erstellen, und es funktioniert gut. Doch für Anfragen ihr vorgeschlagenen Ansatz ist eine separate Funktion der Form zu machen:

func decodeUppercaseRequest(_ context.Context, r *http.Request) (interface{}, error) { 
    var req UppercaseRequest 
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil { 
     return nil, err 
    } 
    return req, nil 
} 

Für jede einzelne RPC in meiner Anwendung. Ich würde meinen Code DRY gerne behalten und Hunderte von fast identischen Methoden vermeiden. Als solche habe ich versucht, eine Funktion zu schreiben Schließungen zu erzeugen, die die gegebene Anforderungstyp dekodieren:

func DecodeRequest(req interface{}) httptransport.DecodeRequestFunc { 
    return func(_ context.Context, r *http.Request) (interface{}, error) { 
     if err := json.NewDecoder(r.Body).Decode(&req); err != nil { 
      return nil, err 
     } 
     return req, nil 
    } 
} 

Diese Funktion kann wie so aufgerufen werden:

DecodeRequest(UppercaseRequest{}} 

Leider, wenn ich so, die JSON Die Decodierung schlägt fehl, obwohl der Typ von req tatsächlich mypackage.UppercaseRequest ist. Ich bin mir nicht sicher, wohin ich von hier aus gehen soll. Kann ich es vermeiden, eine Methode pro Anfragetyp schreiben zu müssen? Gibt es eine Möglichkeit, wie ich der Decode-Funktion helfen kann zu verstehen, was dieser Typ zur Laufzeit ist? Danke im Voraus!

ist hier ein Spielplatz gehen das Problem demonstriert: https://play.golang.org/p/GgHsLffp1G

+0

Was ist der json dekodieren errror? Ein Typ-Switch kann helfen oder das reflect-Paket verfügt über viele Tools zur Identifizierung des Laufzeittyps. – Sridhar

+0

@Sridhar Wenn ich rufe DecodeRequest (CountRequest {}) bekomme ich "http: Panik dienen [:: 1]: 55992: Schnittstelle Umwandlung: Schnittstelle ist map [string] Schnittstelle {}, nicht user.CountRequest" und Wenn ich die zu verwendende Funktion ändere ... Decode (req) und DecodeRequest aufrufen (& CountRequest {}) bekomme ich "http: panic serving [:: 1]: 56375: schnittstellenumwandlung: interface is * user.CountRequest, not user.CountRequest " –

+0

Was ist CountRequest? Eine Map [string] -Schnittstelle {}? Sie sollten sich wirklich an diese [http://www.stackoverflow.com/help/mcve] halten. Vielleicht versuchen Sie Decode (Req) und rufen Sie DecodeRequest (CountRequest {})? – Sridhar

Antwort

2

Nach dem Stück Code, den Sie zeigen uns, glaube ich Ihnen eine Art Behauptung Problem konfrontiert sind. Ich habe eine playground to show you what I explain below erstellt.

Sie übergeben ein UpperCaseRequest an DecodeRequest func. In diesem func ist das Argument vom Typ interface {} und übergibt einen Zeiger dieses Arguments an den json Decoder. Der Decoder sieht also einen Zeiger auf die Schnittstelle und keinen Zeiger auf UpperCaseRequest.

Deshalb ist es nicht richtig decodiert. Und dann, eine Typprüfung auf es zu versuchen, schlägt fehl, weil zwei verschiedene Typen nicht möglich ist.

Also, in Ihrem Code, würde ich vorschlagen:

func DecodeRequest(req interface{}) httptransport.DecodeRequestFunc { 
    return func(_ context.Context, r *http.Request) (interface{}, error) { 
     // Note the '&' is removed here 
     if err := json.NewDecoder(r.Body).Decode(req); err != nil { 
      return nil, err 
     } 
     return req, nil 
    } 
} 

Und rufen Sie diese Funktion wie folgt aus:

// Note the & is placed here. 
DecodeRequest(&UppercaseRequest{}} 
+0

Leider funktioniert das nicht für mich. Wenn ich es versuche, ist der Fehler, den ich bekomme: http: panic serving [:: 1]: 58709: Schnittstellenumwandlung: Schnittstelle ist * user.UppercaseRequest, nicht user.UppercaseRequest –

+0

Oh! Ich denke, ich habe eine Idee - vielleicht ist das Problem nicht mit dem JSON-Decoder, aber eher, dass ich einen Zeiger anstelle der eigentlichen Struktur zurückgeben. Ich denke, ich muss zurückkehren * req, nil. Aber wie kann ich dann eine Schnittstelle auf einen Zeiger auf eine Schnittstelle anwenden? –

+0

Leider hat keiner funktioniert - überprüfen Sie den Go-Spielplatz, den ich hinzugefügt habe, der das Problem repliziert. –

Verwandte Themen