Criei uma API no Go que, ao ser chamada, executa uma consulta, cria uma instância de uma estrutura e, em seguida, codifica essa estrutura como JSON antes de enviar de volta ao chamador. Agora, eu gostaria de permitir que o chamador pudesse selecionar os campos específicos que eles gostariam de retornar, passando um parâmetro GET "fields".
Isso significa que, dependendo do (s) valor (es) dos campos, minha estrutura mudaria. Existe alguma maneira de remover campos de uma estrutura? Ou pelo menos oculte-os na resposta JSON dinamicamente? (Nota: Às vezes, tenho valores vazios para que a tag JSON omitEmpty não funcione aqui) Se nenhuma dessas opções for possível, há uma sugestão sobre uma maneira melhor de lidar com isso? Desde já, obrigado.
Uma versão menor das estruturas que estou usando está abaixo:
type SearchResult struct {
Date string `json:"date"`
IdCompany int `json:"idCompany"`
Company string `json:"company"`
IdIndustry interface{} `json:"idIndustry"`
Industry string `json:"industry"`
IdContinent interface{} `json:"idContinent"`
Continent string `json:"continent"`
IdCountry interface{} `json:"idCountry"`
Country string `json:"country"`
IdState interface{} `json:"idState"`
State string `json:"state"`
IdCity interface{} `json:"idCity"`
City string `json:"city"`
} //SearchResult
type SearchResults struct {
NumberResults int `json:"numberResults"`
Results []SearchResult `json:"results"`
} //type SearchResults
Em seguida, codifico e produzo a resposta da seguinte maneira:
err := json.NewEncoder(c.ResponseWriter).Encode(&msg)
Respostas:
EDIT: Eu notei alguns votos negativos e dei uma outra olhada neste Q&A. Parece que a maioria das pessoas sente falta de que o OP solicitou a seleção dinâmica de campos com base na lista de campos fornecida pelo chamador. Você não pode fazer isso com a tag json struct definida estaticamente.
Se o que você deseja é sempre pular um campo para json-encode, é claro que use
json:"-"
para ignorar o campo (observe também que isso não será necessário se o seu campo não for exportado - esses campos são sempre ignorados pelo codificador json). Mas essa não é a pergunta do OP.Para citar o comentário na
json:"-"
resposta:Eu usaria uma interface de [string] do mapa {} em vez de uma estrutura nesse caso. Você pode remover facilmente os campos chamando o
delete
built-in no mapa para remover os campos.Ou seja, se você não puder consultar apenas os campos solicitados em primeiro lugar.
fonte
map[string]interface{}
faz sentido, mas não requer que você jogue fora sua definição de tipo.Id
, mas não quero retornar toda a estrutura do json. Obrigado por isso!use `json:" - "`
doc: http://golang.org/pkg/encoding/json/#Marshal
fonte
Outra maneira de fazer isso é ter uma estrutura de ponteiros com a
,omitempty
tag. Se os ponteiros forem nulos , os campos não serão Marshalled.Este método não exigirá reflexão adicional ou uso ineficiente de mapas.
Mesmo exemplo que jorelli usando este método: http://play.golang.org/p/JJNa0m2_nw
fonte
Você pode usar o
reflect
pacote para selecionar os campos que deseja, refletindo nas tags de campo e selecionando osjson
valores da tag. Defina um método no seu tipo SearchResults que selecione os campos que você deseja e os retorne como amap[string]interface{}
, e marshal que, em vez de SearchResults, se estruture. Aqui está um exemplo de como você pode definir esse método:e aqui está uma solução executável que mostra como você chamaria esse método e organizaria sua seleção: http://play.golang.org/p/1K9xjQRnO8
fonte
Acabei de publicar o xerife , que transforma estruturas em um mapa com base em tags anotadas nos campos struct. Você pode empacotar (JSON ou outros) o mapa gerado. Provavelmente, não permite que você serialize apenas o conjunto de campos solicitados pelo chamador, mas imagino que o uso de um conjunto de grupos permita cobrir a maioria dos casos. O uso de grupos em vez dos campos diretamente provavelmente também aumentaria a capacidade do cache.
Exemplo:
fonte
Tome três ingredientes:
O
reflect
pacote para fazer um loop em todos os campos de uma estrutura.Uma
if
declaração para selecionar os campos que você desejaMarshal
eO
encoding/json
pacote paraMarshal
os campos de sua preferência.Preparação:
Misture-os em uma boa proporção. Use
reflect.TypeOf(your_struct).Field(i).Name()
para obter um nome doi
th th deyour_struct
.Use
reflect.ValueOf(your_struct).Field(i)
para obter umaValue
representação de tipo de umi
th th deyour_struct
.Use
fieldValue.Interface()
para recuperar o valor real (upcasted para digitar interface {})fieldValue
do tipoValue
(observe o uso de colchete - o método Interface () produzinterface{}
Se você conseguir, com sorte, não queimar transistores ou disjuntores no processo, deverá obter algo assim:
Servindo:
servir com uma estrutura arbitrária e um
map[string]bool
dos campos que você deseja incluir, por exemploBom apetite!
fonte
Você pode usar o atributo de marcação "omitifempty" ou fazer ponteiros de campos opcionais e deixar aqueles que deseja ignorar não inicializados.
fonte
Eu também enfrentei esse problema, no começo eu só queria especializar as respostas no meu manipulador de http. Minha primeira abordagem foi criar um pacote que copia as informações de uma estrutura para outra estrutura e, em seguida, empacota essa segunda estrutura. Eu fiz esse pacote usando reflexão, então, nunca gostei dessa abordagem e também não fui dinamicamente.
Então, decidi modificar o pacote encoding / json para fazer isso. As funções
Marshal
,MarshalIndent
e(Encoder) Encode
, adicionalmente, recebe umtype F map[string]F
Eu queria simular um JSON dos campos necessários para empacotar, portanto, ele empacota apenas os campos que estão no mapa.
https://github.com/JuanTorr/jsont
fonte
A questão agora é um pouco antiga, mas me deparei com a mesma questão há pouco tempo e, como não encontrei uma maneira fácil de fazer isso, construí uma biblioteca cumprindo esse objetivo. Permite gerar facilmente um
map[string]interface{}
partir de uma estrutura estática.https://github.com/tuvistavie/structomap
fonte
[]byte
é que ele não é muito reutilizável: não há maneira fácil de adicionar um campo posteriormente, por exemplo. Então, eu sugeriria criar ummap[string]interface{}
e deixar a serialização JSON fazer parte da biblioteca padrão.Eu não tive o mesmo problema, mas semelhante. O código abaixo também resolve seu problema, é claro, se você não se importa com problemas de desempenho. Antes de implementar esse tipo de solução em seu sistema, recomendo que você redesenhe sua estrutura, se puder. O envio da resposta da estrutura variável está com excesso de engenharia. Acredito que uma estrutura de resposta represente um contrato entre uma solicitação e um recurso e não deve ser dependente de solicitações (você pode tornar nulos os campos não desejados). Em alguns casos, temos que implementar esse design, se você acredita que está nesses casos, aqui está o link e o código de reprodução que eu uso.
fonte
Criei essa função para converter struct em JSON, ignorando alguns campos. Espero que ajude.
Exemplo: https://play.golang.org/p/nmq7MFF47Gp
fonte