N
N
Nikita2020-12-18 13:05:51
go
Nikita, 2020-12-18 13:05:51

How to make one structure for different json sources?

Hello!

Faced such a task
. json with a different structure comes to the input:

{"title": "Title", "text": "Text"}
{"name": "Title", "description": "Text"}

Of these, you need to create one object with a structure
type Post struct {
  Title string
  Text  string
}


since for Unmarshal you cannot set a json tag with several different names for the field, I did this: https://play.golang.org/p/HCyzIrboFYT

Two structures for each json, then checking and creating a Post object.
In this implementation, I have Post described three times, I don’t really like it :)

Is there a more elegant solution?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
E
Evgeny Mamonov, 2020-12-18
@somebug

It is possible to make unmarshal in map[string]string and already extract data from there.
And then, for example, you can make a function like this

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
}

Here is a working example https://play.golang.org/p/gizeAA8uWKt
The text of the working example

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)
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question