somebug
@somebug

Как сделать одну структуру для разных источников json?

Всем привет!

Столкнулся с такой задачей
На вход приходят json с разной структурой:
{"title": "Title", "text": "Text"}
{"name": "Title", "description": "Text"}

Из них нужно создавать один объект со структурой
type Post struct {
	Title string
	Text  string
}


так как для Unmarshal нельзя задать тег json с несколькими разными именами для поля, сделал так: https://play.golang.org/p/HCyzIrboFYT

Две структуры для каждого json, потом проверка и создание объекта Post.
В такой реализации у меня Post описан три раза, мне это не очень нравится :)

Есть ли более изящное решение?
  • Вопрос задан
  • 77 просмотров
Решения вопроса 1
EvgenyMamonov
@EvgenyMamonov
Senior software developer, system architect
Можно сделать unmarshal в map[string]string и уже извлечь данные от туда.
А дальше, например, можно сделать такую функцию
func NewPostFromIncomingPost(incomingPost map[string]string) (*Post, error) {
	post := &Post{}

	if title, exists := incomingPost[`name`]; exists {
		post.Title = title
	} else if title, exists := incomingPost[`title`]; exists {
		post.Title = title
	} else {
		return nil, errors.New(`title not found`)
	}

	if text, exists := incomingPost[`text`]; exists {
		post.Text = text
	} else if text, exists := incomingPost[`description`]; exists {
		post.Text = text
	} else {
		return nil, errors.New(`text not found`)
	}
	
	return post, nil
}

Вот тут работающий пример https://play.golang.org/p/gizeAA8uWKt
Текст работающего примера

package main

import (
	"encoding/json"
	"fmt"
	"errors"
)

type Post struct {
	Title string
	Text  string
}

func NewPostFromIncomingPost(incomingPost map[string]string) (*Post, error) {
	post := &Post{}

	if title, exists := incomingPost[`name`]; exists {
		post.Title = title
	} else if title, exists := incomingPost[`title`]; exists {
		post.Title = title
	} else {
		return nil, errors.New(`title not found`)
	}

	if text, exists := incomingPost[`text`]; exists {
		post.Text = text
	} else if text, exists := incomingPost[`description`]; exists {
		post.Text = text
	} else {
		return nil, errors.New(`text not found`)
	}
	
	return post, nil
}

func main() {
	jsonSource1 := []byte(`{"title": "Title", "text": "Text"}`)
	jsonSource2 := []byte(`{"name": "Title", "description": "Text"}`)

	var incomingPost1 map[string]string
	if err := json.Unmarshal(jsonSource1, &incomingPost1); err != nil {
		panic(err)
	}

	post1, err := NewPostFromIncomingPost(incomingPost1)
	fmt.Printf("post1: %+v\nerr: %+v\n\n", post1, err)

	var incomingPost2 map[string]string
	if err := json.Unmarshal(jsonSource2, &incomingPost2); err != nil {
		panic(err)
	}

	post2, err := NewPostFromIncomingPost(incomingPost2)
	fmt.Printf("post2: %+v\nerr: %+v\n\n", post2, err)
}

Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы