2017-09-27 2 views
1

Ich entwickle gerade eine JSON-API für einen Blog in Golang, und ich bin in einen Roadblock geraten, der versucht, die Serialisierung und Deserialisierung von Blogposts zu behandeln. Ich möchte, dass meine Posts eine Reihe von Post Sections enthalten, die eine Reihe von Dingen beinhalten können (wie normale Absätze, Bilder, Zitate usw.). Ich verwende Mongo für die Lagerung (mit den erstaunlichen mgo library) und ich möchte die Beiträge so speichern:Benutzerdefinierte JSON-Serialisierung und Deserialisierung für Schnittstellen in Go

{ 
    "title": "Blog post", 
    "sections": [ 
    { 
     "type": "text", 
     "content": { "en": "English content", "de": "Deutscher Inhalt" } 
    }, 
    { 
     "type": "image", 
     "content": "https://dummyimage.com/100x100" 
    }, 
    ...more sections 
    ], 
    ...other fields 
} 

ich mehrere Lösungen ausprobiert habe dies in gehen zu implementieren und keiner hat wirklich schien, wie das „Recht Weg“, es zu tun:

  1. Pflege nicht über den Inhalt

Diese wie die offensichtliche Lösung schien, nur eine einfache Struktur mit:

type PostSection struct{ 
    Type string 
    Content interface{} 
} 

Auf diese Weise kann ich durch was auch immer die Frontend-POSTS passieren und speichern Sie es. Es ist jedoch unmöglich, die Daten zu manipulieren oder zu validieren, also ist es keine gute Lösung.

  1. Verwenden von benutzerdefinierten Schnittstelle Serialisierung

fand ich this article über Schnittstellen in golang Serialisierung. Dies schien zunächst groß, weil ich eine Schnittstelle wie diese haben könnte:

type PostSection interface{ 
    Type() string 
    Content() interface{} 
} 

und dann jede Art wie folgt implementieren:

type PostImage string 

func (p *PostImage) Type() string { 
    return "image" 
} 

func (p *PostImage) Content() interface{} { 
    return p 
} 

Optimal, dass es gewesen wäre, und nach der Implementierung MarshalJSON und UnmarshalJSON für alle meine Typen, es war in Ordnung, wenn Sie json.Marshal direkt auf einem PostSection-Objekt verwenden.

Wenn jedoch eine Reihe von PostSection s Serialisierung oder ein ganzen Beitrag Objekt Deserialisierung enthält, wurde mein eigener Code einfach ignoriert werden und die PostSections ebenso wie die zugrunde liegenden Objekte (string oder map[string]string in den Beispielen) behandelt werden würden, wenn die Serialisierung, oder führen beim Deserialisieren zu leeren Objekten.

  1. Schreiben benutzerdefinierte Serialisierung für die

So struct gesamte Post, ich die Lösung zur Zeit bin mit aber möchte, ist benutzerdefinierte Serialisierung für das gesamte Beitrag Objekt ändern. Dies führt Super hässlich Code zu, da ich nur wirklich individuellen Code für ein einzelnes Feld benötigen und so durch den Rest ich vorbei, so dass die Deserialisierung so aussehen:

p.ID = decoded.ID 
p.Author = decoded.Author 
p.Title = decoded.Title 
p.Intro = decoded.Intro 
p.Slug = decoded.Slug 
p.TitleImage = decoded.TitleImage 
p.Images = decoded.Images 
...more fields... 

und dann die Decodierung der Abschnitte wie dies:

sections := make([]PostSection, len(decoded.Sections)) 
for i, s := range decoded.Sections { 
    if s["type"] == "text" { 
     content := s["content"].(map[string]interface{}) 
     langs := make(PostText, len(content)) 
     for lang, langContent := range content { 
      langString := langContent.(string) 
      langs[lang] = langString 
     } 
     sections[i] = &langs 
    } else if s["type"] == "image" { 
     content := s["content"].(string) 
     contentString := PostImage(content) 
     sections[i] = &contentString 
    } 
} 

p.Sections = sections 

Dies ist eine ganze Menge Code ich werde jedes Mal, wenn ich will, gehören PostSections in einer anderen Form woanders verwenden müssen (zum Beispiel in einem Newsletter) und es fühlt sich nicht wie idiomatische go Code mit einem langen Schuss. Außerdem gibt es keine Fehlerbehandlung für fehlerhafte Abschnitte - Sie verursachen nur eine solche Panik.

Gibt es eine saubere Lösung für dieses Problem?

+1

# 2, 'beim Serialisieren oder Deserialisieren eines gesamten Post-Objekts, das ein Array von PostSections enthält, wurde mein benutzerdefinierter Code nicht verwendet und ich würde Fehler erhalten. Welche Fehler? Und haben Sie "MarshalJSON" und "UnmarshalJSON" für das Post-Objekt selbst implementiert? – RayfenWindspear

+0

Sorry, aber es scheint, als hätte ich mich daran erinnert. Ich habe es gerade noch einmal ausprobiert und die Fehler traten nur auf, wenn ich versuchte, von mgo zu deserialisieren, weil es keine 'SetBSON'-Methode für die PostSection-Schnittstelle finden konnte. Was deine zweite Frage angeht, darüber spreche ich in # 3. – happens

Antwort

1

Um das Schreiben UnmarshalJSON für das ganze Post zu vermeiden, können Sie Ihre PostSection in einem konkreten Typ umhüllen und es die Unmarshaler-Schnittstelle implementieren lassen.

+0

Das funktioniert super, vielen Dank! Fühlt sich so offensichtlich, duh ... – happens

Verwandte Themen