/ / Go JSONのインターフェースのカスタムJSONシリアル化とデシリアライズ、go、シリアライズ

Go JSONのインターフェースのカスタムJSONシリアル化と非直列化、移動、シリアライズ

私は現在JSON APIを開発しています。golang、そして私はブログ記事のシリアライゼーションとデシリアライズを処理しようとするロードブロッキングに遭遇しました。私の投稿には、多くのもの(普通の段落、画像、引用符など)であるPost Sectionの配列が含まれています。私はMongoをストレージに使用しています(素晴らしい mgoライブラリ)私はこのような投稿を保存したい:

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

私はこれを実現するためにいくつかのソリューションを試してみましたが、本当に "正しい方法"のようには思えませんでした。

  1. 内容を気にしない

これは明白な解決策のように思えました。単純な構造体を使用しています:

type PostSection struct{
Type    string
Content interface{}
}

この方法で、私はフロントエンドのPOSTSを何でも通過させて保存することができます。しかし、データの操作や検証は不可能なので、良い解決策ではありません。

  1. カスタムインターフェイスのシリアル化を使用する

私は見つけた この記事 golangのインターフェースのシリアライズについて私はこのようなインターフェースを持つことができたので、これは最初は素晴らしいようでした。

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

次のようにすべての型を実装します。

type PostImage string

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

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

最適には、それはそれを実行していました。 MarshalJSON そして UnmarshalJSON PostSectionオブジェクトでjson.Marshalを直接使用すると、すべてのタイプに対して正常に動作していました。

しかし、配列を含むPostオブジェクト全体をシリアライズまたはデシリアライズするときは、 PostSection私のカスタムコードはちょうど無視され、PostSectionsは基本的なオブジェクトとして扱われますstring または map[string]string デシリアライズ時に空のオブジェクトになることがあります。

  1. POST構造体全体のカスタムシリアル化の記述

だから、私が現在使っている解決策変更するのは、Postオブジェクト全体のカスタムシリアル化です。私は実際には単一のフィールド用のカスタムコードが必要なので、残りの部分を渡して、逆シリアル化を次のようにします。

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...

次に、このようなセクションをデコードします。

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

これは私が使用しなければならないたくさんのコードですPostSectionsを別の場所(例えばニュースレター)に入れたいと思うたびに、長いセクションで慣用的なgoコードのように感じることはありません。また、不正なセクションのエラー処理もありません。この。

この問題の解決策はありますか?

回答:

回答№1は2

書くことを避けるために UnmarshalJSON 全体 Post あなたはあなたを包むことができます PostSection Unmarshalerインタフェースを実装するようにしてください。

type Post struct {
ID         int
Author     string
Title      string
Intro      string
Slug       string
TitleImage string
Images     []string

Sections []*PostSection
}

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

type PostSection struct {
Content SectionContent
}

func (s *PostSection) UnmarshalJSON(data []byte) error {
// ...
return nil
}