从API解析结构

I am trying to access some information stored in a json file via Go. I have two related issues. One is that I'm not sure how to organize my structs and secondly how do I access them via a variable. I'll notate my code to make a little more sense

// To be clear, this is dummy info and I'm linting my actual json
// data. It loads fine, I just don't want to get hung up on this side
{
 "A": {
        "lob": "A",
        "url": [
                 "example.com",
                 "test.com"]
}
 "B": {
        "lob": "B",
        "url": [
                 "example2.com",
                 "test2.com"]

}
}

So the concern is that the structure of the options is identical. I am building this as part of a REST AP. The hope is that users can use http://testapi.com/getdata/A and it will return the urls and name info under A and likewise for B. As is, it loads both of them as separate components of the same struct:

type SiteList struct {
    A struct {
        Lob string   `json:"lob"`
        URL []string `json:"url"`
    } `json:"test"`
    B struct {
        Lob string   `json:"lob"`
        URL []string `json:"url"`
    } `json:"test2"`
}

I can do .A or .B by hand but I'm wondering how to handle it when the requests come in so that my API will only return the data under A or B.

If you're going to consume the API via accessing the API via http://testapi.com/getdata/A or http://testapi.com/getdata/B then A and B can be considered the parameters that drive the behavior of your API.

If you're passing A, you basically want to access the site data associated with A and if you're passing B, the site data for B should be returned.

An easy way to organize this data internally is to use a dedicated Go type site which holds Lob and URL and arrange everything in a map via map[string]site, which is initialized on startup of your server.

You can then dynamically access the parameter given to your API (A or B, but can be easily extended), lookup the site information from the map and, in case it's a valid site, return the corresponding data encoded as JSON.

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
)

type site struct {
    Lob string   `json:"lob"`
    URL []string `json:"url"`
}

var sites = map[string]site{
    "A": site{
        Lob: "A",
        URL: []string{
            "example.com",
            "test.com",
        },
    },
    "B": site{
        Lob: "B",
        URL: []string{
            "example2.com",
            "test2.com",
        },
    },
}

const endpoint = "/getdata/"

func handler(w http.ResponseWriter, r *http.Request) {
    lob := r.URL.Path[len(endpoint):]
    s, ok := sites[lob]
    if !ok {
        w.WriteHeader(http.StatusNotFound)
        return
    }

    resp, err := json.Marshal(s)
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    w.Write(resp)
}

func main() {
    http.HandleFunc(endpoint, handler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Missing values in the json will be unmarshalled with their zero values. An int will be 0, a string will be "", a map and any pointer will be nil. Structs will be initialized, but their fields will have the zero value.

In your case, when comcast is missing in the json, B will be initialized as a struct, where Lob is "" and URL is an empty slice of string.

If I understand correctly you have a struct SiteList and depending on if they user navigates to /getData/A or /getData/B you want to serve SiteList.A or SiteList.B.

From the json marshal docs here or this SO answer you can leave out some fields of a struct when they are empty. Basically if there's no data in that field then it will not appear in the marshalled json.

The "omitempty" option specifies that the field should be omitted from the encoding if the field has an empty value, defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string.

With that in mind, if you have the control in the handlers of the requests to be able to set the values in SiteList according to the path then you could make use of this feature.

If you extract the shared parts of A and B into a struct:

type Inner struct {
    Lob string `json:"lob"`
    URL []string `json:"url"`
}

// using pointers here for A and B means setting to nil is empty
type SiteList struct {
    A *Inner `json:"test,omitempty"`
    B *Inner `json:"test2,omitempty"`
}

And then set the one that you do not want to be in the response body to nil. (nil is empty for a pointer, so it will not get marshalled.)