これは、リフレクション、安全でない、または構造体ごとの関数のないソリューションです。この例は少し複雑で、このようにする必要はないかもしれませんが、重要なのは、map [string]interface{}を使用してフィールドタグを持つ構造体から離れることです。同様のソリューションでアイデアを使用できる可能性があります。
package main
import (
    "encoding/json"
    "fmt"
    "log"
)
// example full database record
var dbj = `{ "bit_size": 8, "secret_key": false }`
// User type has only the fields going to the API
type User struct {
    // tag still specifies internal name, not API name
    NumBits int `json:"bit_size"`
}
// mapping from internal field names to API field names.
// (you could have more than one mapping, or even construct this
// at run time)
var ApiField = map[string]string{
    // internal: API
    "bit_size": "num_bits",
    // ...
}
func main() {
    fmt.Println(dbj)
    // select user fields from full db record by unmarshalling
    var u User
    if err := json.Unmarshal([]byte(dbj), &u); err != nil {
        log.Fatal(err)
    }
    // remarshal from User struct back to json
    exportable, err := json.Marshal(u)
    if err != nil {
        log.Fatal(err)
    }
    // unmarshal into a map this time, to shrug field tags.
    type jmap map[string]interface{}
    mInternal := jmap{}
    if err := json.Unmarshal(exportable, &mInternal); err != nil {
        log.Fatal(err)
    }
    // translate field names
    mExportable := jmap{}
    for internalField, v := range mInternal {
        mExportable[ApiField[internalField]] = v
    }
    // marshal final result with API field names
    if exportable, err = json.Marshal(mExportable); err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(exportable))
}
出力:
  {"bit_size":8、 "secret_key":false} 
  {"num_bits":8}
編集:より多くの説明。トムがコメントで指摘しているように、コードの背後で反省が起こっています。ここでの目標は、ライブラリの利用可能な機能を使用してコードを単純に保つことです。パッケージjsonは現在、データを操作する2つの方法、構造体タグと[string]interface{}のマップを提供しています。structタグを使用するとフィールドを選択できますが、静的に1つのjsonフィールド名を選択する必要があります。マップでは、実行時にフィールド名を選択できますが、マーシャルするフィールドは選択できません。jsonパッケージで両方を同時に実行できると便利ですが、そうではありません。ここでの答えは、2つの手法と、OPの問題例のソリューションでそれらをどのように構成できるかを示しています。