Creé una API en Go que, al ser llamada, realiza una consulta, crea una instancia de una estructura y luego codifica esa estructura como JSON antes de enviarla de nuevo a la persona que llama. Ahora me gustaría permitir que la persona que llama pueda seleccionar los campos específicos que le gustaría devolver al pasar un parámetro GET de "campos".
Esto significa que dependiendo de los valores de los campos, mi estructura cambiaría. ¿Hay alguna forma de eliminar campos de una estructura? ¿O al menos ocultarlos en la respuesta JSON dinámicamente? (Nota: a veces tengo valores vacíos, por lo que la etiqueta omitEmpty de JSON no funcionará aquí) Si ninguno de estos es posible, ¿hay alguna sugerencia sobre una mejor manera de manejar esto? Gracias por adelantado.
A continuación se muestra una versión más pequeña de las estructuras que estoy usando:
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
Luego codifico y envío la respuesta de esta manera:
err := json.NewEncoder(c.ResponseWriter).Encode(&msg)
Respuestas:
EDITAR: Noté algunos votos negativos y eché otro vistazo a estas preguntas y respuestas. La mayoría de las personas parecen perderse que el OP solicitó que los campos se seleccionen dinámicamente según la lista de campos proporcionada por la persona que llama. No puede hacer esto con la etiqueta json struct estáticamente definida.
Si lo que desea es omitir siempre un campo para codificar json, entonces, por supuesto, úselo
json:"-"
para ignorar el campo (también tenga en cuenta que esto no es necesario si su campo no se exporta; esos campos siempre son ignorados por el codificador json). Pero esa no es la pregunta del OP.Para citar el comentario sobre la
json:"-"
respuesta:En este caso, usaría una interfaz de mapa [cadena] {} en lugar de una estructura. Puede eliminar fácilmente los campos llamando a la función
delete
integrada en el mapa para que se eliminen los campos.Es decir, si no puede consultar solo los campos solicitados en primer lugar.
fuente
map[string]interface{}
tiene sentido, pero no requiere que deseche su definición de tipo.Id
pero no quiero devolver toda la estructura json. ¡Gracias por esto!use `json:" - "`
doc: http://golang.org/pkg/encoding/json/#Marshal
fuente
Otra forma de hacer esto es tener una estructura de punteros con la
,omitempty
etiqueta. Si los punteros son nulos , los campos no serán Marshalled.Este método no requerirá una reflexión adicional o un uso ineficiente de los mapas.
Mismo ejemplo que jorelli usando este método: http://play.golang.org/p/JJNa0m2_nw
fuente
Puede usar el
reflect
paquete para seleccionar los campos que desee reflejando en las etiquetas de campo y seleccionando losjson
valores de las etiquetas. Defina un método en su tipo SearchResults que seleccione los campos que desea y los devuelva como amap[string]interface{}
, y luego marque eso en lugar de la estructura SearchResults en sí. Aquí hay un ejemplo de cómo podría definir ese método:y aquí hay una solución ejecutable que muestra cómo llamaría a este método y calificaría su selección: http://play.golang.org/p/1K9xjQRnO8
fuente
Acabo de publicar Sheriff , que transforma las estructuras en un mapa basado en etiquetas anotadas en los campos de la estructura. Luego puede ordenar (JSON u otros) el mapa generado. Probablemente no le permita serializar solo el conjunto de campos que solicitó la persona que llama, pero imagino que usar un conjunto de grupos le permitiría cubrir la mayoría de los casos. El uso de grupos en lugar de los campos directamente probablemente también aumentaría la capacidad de caché.
Ejemplo:
fuente
Toma tres ingredientes:
El
reflect
paquete para recorrer todos los campos de una estructura.Una
if
declaración para recoger los campos que deseaMarshal
yEl
encoding/json
paquete aMarshal
los campos de tu agrado.Preparación:
Licuarlos en una buena proporción. Use
reflect.TypeOf(your_struct).Field(i).Name()
para obtener un nombre deli
campo th deyour_struct
.Use
reflect.ValueOf(your_struct).Field(i)
para obtener unaValue
representación de tipo de uni
campo th deyour_struct
.Utilícelo
fieldValue.Interface()
para recuperar el valor real (incluido en la interfaz de tipo {})fieldValue
del tipo deValue
(tenga en cuenta el uso de corchetes: el método Interface () produceinterface{}
Si afortunadamente logra no quemar ningún transistor o interruptor automático en el proceso, debería obtener algo como esto:
Servicio:
servir con una estructura arbitraria y una
map[string]bool
de los campos que desea incluir, por ejemplo¡Buen provecho!
fuente
Puede usar el atributo de etiquetado "omitifempty" o hacer punteros de campo opcionales y dejar los que desea omitir sin inicializar.
fuente
También enfrenté este problema, al principio solo quería especializar las respuestas en mi controlador http. Mi primer enfoque fue crear un paquete que copiara la información de una estructura a otra estructura y luego reunir esa segunda estructura. Hice ese paquete usando la reflexión, por lo que nunca me gustó ese enfoque y tampoco lo fui dinámicamente.
Así que decidí modificar el paquete de codificación / json para hacer esto. Las funciones
Marshal
,MarshalIndent
y(Encoder) Encode
además recibe untype F map[string]F
Quería simular un JSON de los campos que se necesitan para ordenar, por lo que solo ordena los campos que están en el mapa.
https://github.com/JuanTorr/jsont
fuente
La pregunta ahora es un poco vieja, pero me encontré con el mismo problema hace un tiempo, y como no encontré una manera fácil de hacerlo, construí una biblioteca que cumplía este propósito. Permite generar fácilmente a
map[string]interface{}
partir de una estructura estática.https://github.com/tuvistavie/structomap
fuente
[]byte
es que no es muy reutilizable: no es una manera fácil de agregar un campo después, por ejemplo. Por lo tanto, sugeriría crear unmap[string]interface{}
y dejar que la serialización JSON forme parte de la biblioteca estándar.No tuve el mismo problema pero similar. El siguiente código también resuelve su problema, por supuesto si no le importa el problema de rendimiento. Antes de implementar ese tipo de solución en su sistema, le recomiendo que rediseñe su estructura si puede. Enviar respuesta de estructura variable es sobre ingeniería. Creo que una estructura de respuesta representa un contrato entre una solicitud y un recurso y no deberían ser solicitudes dependientes (puede hacer que los campos no deseados sean nulos, lo hago). En algunos casos tenemos que implementar este diseño, si crees que estás en esos casos, aquí está el enlace de reproducción y el código que uso.
fuente
Creé esta función para convertir la estructura a una cadena JSON ignorando algunos campos. Espero que ayude.
Ejemplo: https://play.golang.org/p/nmq7MFF47Gp
fuente