2013-10-09 34 views
8

Ipotetico, corro un'API e quando un utente effettua una richiesta GET sulla risorsa utente, tornerò settori pertinenti come JSONGolang + MongoDB incassato (incorporando una struttura in un'altra struct)

type User struct { 
    Id  bson.ObjectId `json:"id,omitempty" bson:"_id,omitempty"` 
    Name string  `json:"name,omitempty" bson:"name,omitempty"` 
    Secret string  `json:"-,omitempty" bson:"secret,omitempty"` 
} 

Come puoi vedere, il campo segreto nell'utente è json:"-". Ciò implica che nella maggior parte delle operazioni non vorrei tornare. In questo caso, una risposta sarebbe

{ 
    "id":1, 
    "Name": "John" 
} 

Il segreto campo non verrà restituito come json:"-" omette il campo.

Ora, sto aprendo un percorso solo amministrativo dove vorrei restituire il campo segreto. Tuttavia, ciò significherebbe duplicare la struttura dell'utente.

mia soluzione attuale assomiglia a questo:

type adminUser struct {  
    Id  bson.ObjectId `json:"id,omitempty" bson:"_id,omitempty"` 
    Name string  `json:"name,omitempty" bson:"name,omitempty"` 
    Secret string  `json:"secret,omitempty" bson:"secret,omitempty"` 
} 

Esiste un modo per incorporare l'utente in AdminUser? Tipo di eredità come:

type adminUser struct {  
    User 
    Secret string  `json:"secret,omitempty" bson:"secret,omitempty"` 
} 

È possibile che questo momento non funziona, in quanto solo il segreto campo verrà restituito in questo caso.

Nota: nell'attuale base di codice ci sono alcuni campi di dozzine. In quanto tale, il costo della duplicazione del codice è elevato.

la query effettiva mongo è qui sotto:

func getUser(w http.ResponseWriter, r *http.Request) { 
    ....omitted code... 

    var user adminUser 
    err := common.GetDB(r).C("users").Find(
     bson.M{"_id": userId}, 
).One(&user) 
    if err != nil { 
     return 
    } 
    common.ServeJSON(w, &user) 
} 

risposta

22

si dovrebbe dare un'occhiata alla bandiera in linea del pacchetto BSON (che è documentato in bson.Marshal). Esso dovrebbe permettere di fare qualcosa di simile:

type adminUser struct { 
    User `bson:",inline"` 
    Secret string `json:"secret,omitempty" bson:"secret,omitempty"` 
} 

Tuttavia, ora si noterà che si ottiene errori di chiave duplicati quando si tenta di leggere dal database con questa struttura, dal momento che entrambi adminUser e User contenere la chiave secret.

Nel tuo caso vorrei rimuovere il campo da SecretUser e hanno solo quella in adminUser. Quindi, ogni volta che è necessario scrivere nel campo secret, assicurarsi di utilizzare uno adminUser.

+0

In questo caso, si verifica un errore di runtime: Errore interno del server Chiave duplicata "secret" in struct main.adminUser! – samol

+0

Aggiornato la mia risposta. Non avevo capito che c'erano due chiavi duplicate. –

+1

Proprio come una nota a margine per il record, l'uso del tag _ ", inline" _ funziona anche per i campi normali (non incorporati/non anonimi). –

1

Un'altra alternativa sarebbe dichiarare un'interfaccia.

type SecureModel interface { 
    SecureMe() 
} 

Assicurarsi che il modello implementa:

type User struct { 
    Id  bson.ObjectId `json:"id,omitempty" bson:"_id,omitempty"` 
    Username string  `json:"username" bson:"username"` 
    Secret string  `json:"secret,omitempty" bson:"secret"` 
} 

func (u *User) SecureMe() { 
    u.Secret = "" 
} 

E solo lo chiamano a seconda di quale percorso si chiama.

// I am being sent to a non-admin, secure me. 
if _, ok := user.(SecureModel); ok { 
    user.(SecureModel).SecureMe() 
} 
// Marshall to JSON, etc. 
... 

Edit: La ragione per usare un'interfaccia qui è per i casi in cui si potrebbe inviare modelli arbitrari sul filo utilizzando un metodo comune.

Problemi correlati