supa pati
supa pati

Reputation: 73

How to create a struct with different structs of one members of struct in go?

I am getting a json response from a server with three fix json object field and one field with different json objects.

Example - Response 1

{
   status : "success",
   error-code : "",
   message : "login successful",
   data : {
           token : "token value",
           refresh-token : "refresh token value"
          }
}

Example - Response 2

{
   status : "success",
   error-code : "",
   message : "user data fetched",
   data : {
           first-name: "josh",
           last-name : "walter",
           age : "30",
           phone: 1234567890,
           address : "x street, dc"
          }
}

for above json response created struct as follows

type loginData struct {
    Token string `json:"token"`
    RefreshToken string `json:"refresh-token"`

}

type userdata {
    FirstName string    `json:"first-name"`
    LastName string     `json:"refresh-token"`
    Age string          `json:"age"`
    Phone string        `json:"phone"`
    Address string      `json:"address"`

}


type response struct {
    Status string       `json:"status"`
    ErrorCode string    `json:"error-code"`
    RespMessage string  `json:"message"`
    RespData string     `json:"data"`
}



How to add logindata struct while unmarshaling during login response and userdata struct while unmarshaling userdata response in "RespData" field in response struct

Upvotes: 1

Views: 1379

Answers (3)

supa pati
supa pati

Reputation: 73

@mkopriva as you said tried this suggestion it worked.

package main

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

type loginData struct {
    Token        string `json:"token"`
    RefreshToken string `json:"refresh-token"`
}

type userdata struct {
    FirstName string `json:"first-name"`
    LastName  string `json:"last-name"`
    Age       string `json:"age"`
    Phone     string `json:"phone"`
    Address   string `json:"address"`
}

type response struct {
    Status      string      `json:"status"`
    ErrorCode   string      `json:"error-code"`
    RespMessage string      `json:"message"`
    RespData    interface{} `json:"data"`
}

func main() {
    jsonresp_1 := `{
        "status" : "success",
        "error-code" : "",
        "message" : "login successful",
        "data" : {
                "token" : "token value",
                "refresh-token" : "refresh token value"
               }
     }`

    jsonresp_2 := `{
        "status" : "success",
        "error-code" : "",
        "message" : "user data fetched",
        "data" : {
                "first-name": "josh",
                "last-name" : "walter",
                "age" : "30",
                "phone": "1234567890",
                "address" : "x street, dc"
               }
     }`
    resp1 := strings.NewReader(jsonresp_1)
    data1 := loginData{}
    respdata1 := response{RespData: &data1}

    if err := json.NewDecoder(resp1).Decode(&respdata1); err != nil {
        fmt.Println(err)
    }
    fmt.Printf("token : %s \nrefreshtoken : %s \n", data1.Token, data1.RefreshToken)

    fmt.Println("-------------------")

    resp2 := strings.NewReader(jsonresp_2)
    data2 := userdata{}
    respdata2 := response{RespData: &data2}

    if err := json.NewDecoder(resp2).Decode(&respdata2); err != nil {
        fmt.Println(err)
    }
    fmt.Printf("firstname : %s \nlastname : %s ", data2.FirstName, data2.LastName)
}

Output

⚡ ⇒  go run main.go 
token : token value 
refreshtoken : refresh token value 
-------------------
firstname : josh 
lastname : walter

Upvotes: 0

Aswin Thiyagarajan
Aswin Thiyagarajan

Reputation: 365

According to me, you should have two different structs to do this. One reason is separation of concern, as the structure of these responses may change in the future and these are responses from two different apis so its better to maintain different response objects.

type loginData struct {
    Token        string `json:"token"`
    RefreshToken string `json:"refresh-token"`
}

type userdata struct {
    FirstName string `json:"first-name"`
    LastName  string `json:"refresh-token"`
    Age       string `json:"age"`
    Phone     string `json:"phone"`
    Address   string `json:"address"`
}

type response struct {
    Status      string `json:"status"`
    ErrorCode   string `json:"error-code"`
    RespMessage string `json:"message"`
}

type userResponse struct {
    response
    RespData userdata `json:"data"`
}

type loginResponse struct {
    response
    RespData loginData `json:"data"`
}

Upvotes: 0

mkopriva
mkopriva

Reputation: 38343

First change the RespData field's type:

type response struct {
    Status      string      `json:"status"`
    ErrorCode   string      `json:"error-code"`
    RespMessage string      `json:"message"`
    RespData    interface{} `json:"data"`
}

Then, depending on what request you are making, set the RespData field to a pre-allocated instance of a pointer to the expected type:

r, err := http.Get("https://some_api.com/loginData")
if err != nil {
    return err
}
defer r.Body.Close()

// check r.StatusCode and make sure it's correct

data := loginData{}
resp := response{RespData: &data}
if err := json.NewDecoder(r.Body).Decode(&resp); err != nil {
    return err
}

fmt.Println(data)

Upvotes: 2

Related Questions