220

I wish to use the "encoding/json" package to marshal a struct declared in one of the imported packages of my application.

Eg.:

type T struct {
    Foo int
}

Because it is imported, all available (exported) fields in the struct begins with an upper case letter. But I wish to have lower case key names:

out, err := json.Marshal(&T{Foo: 42})

will result in

{"Foo":42}

but I wish to get

{"foo":42}

Is it possible to get around the problem in some easy way?

pgpb.padilla
  • 2,318
  • 2
  • 20
  • 44
ANisus
  • 74,460
  • 29
  • 162
  • 158
  • 5
    @Zippoxer: I would say: a key in a client/server communication protocol strictly defined to lower case letters. Well, in my case it doesn't matter since I have defined the protocol myself.. but in theory at least? But, I know it is mainly just me spending too much time on a silly little detail. – ANisus Jul 28 '12 at 20:00
  • Don't apologize. You're not the silly one, the language that does not accept the full json spec is the silly one (although the issue is easily solved, as below). – Jehan Dec 02 '15 at 00:42
  • @ANisus: I misread your question as about struct key names, not JSON key names. Retracted the vote. – Jonathan Hall Jun 20 '17 at 12:50

4 Answers4

333

Have a look at the docs for encoding/json.Marshal. It discusses using struct field tags to determine how the generated json is formatted.

For example:

type T struct {
    FieldA int    `json:"field_a"`
    FieldB string `json:"field_b,omitempty"`
}

This will generate JSON as follows:

{
    "field_a": 1234,
    "field_b": "foobar"
}
jimt
  • 25,324
  • 8
  • 70
  • 60
  • 11
    Field tags? Oh my.. I missed this entire part when searching in the docs. I was looking for flags, functions or some other settings. Well, this is the exact answer I was looking for! And in addition, I have a new Go concept to learn about: field tags :) – ANisus Jul 27 '12 at 19:18
  • 1
    They are quite handy. You can access them at runtime through the `reflect` package. – jimt Jul 27 '12 at 19:19
  • Yeah, when working with reflection I see how having a way to add meta data to a field can be a wonderful thing! Btw, just tried the answer. Works like a charm. – ANisus Jul 27 '12 at 19:23
  • 8
    I've just started to curse the go language - how stupid is this, why would they make the fields with lowercase letters in the generated JSON etc, etc. Then I came across this thread and thought "OMG That's brilliant!!!". I even jumped and explained my girlfriend why I am so excited :D It's so cool :))) – nyxz Feb 10 '14 at 21:52
  • 14
    Make sure there is no space between the colon and the first quotation mark of the tag! Use `json:"some_tag"` instead of `json: "some_tag"`. I got bit by this for a while. – David Morales Sep 03 '16 at 20:27
  • This could be made even better with some inspiration from [Gson](https://github.com/google/gson), which allows setting any "field naming policy" like `LOWER_CASE_WITH_UNDERSCORES` (aka snake case). – Vicky Chijwani Jun 22 '17 at 14:50
  • why is golang so trival to write a json – Yin Nov 25 '19 at 13:19
  • i don't get why this is an accepted answer. The OP's question was to output lowercased json keys for a struct that does not contain 'json' tags. every other language's serializer supports configuration of the output. it's not reasonable to expect that the input's type will be adjusted to satisfy marshaller's needs just because it cannot do any better than taking the field's name as-is – grzegorz_p Jun 29 '22 at 15:32
10

You could make your own struct with the keys that you want to export, and give them the appropriate json tags for lowercase names. Then you can copy the desired struct into yours before encoding it as JSON. Or if you don't want to bother with making a local struct you could probably make a map[string]interface{} and encode that.

Lily Ballard
  • 182,031
  • 33
  • 381
  • 347
  • The silly thing is that the other package (containing the types) is actually mine as well. But, yes, I have probably stared to blindly at the fact that it must be a struct. Using a `map[string]interface{}` would work as long as I don't end up with nested objects/structs – ANisus Jul 27 '12 at 19:17
  • 1
    @ANisus: Oh, my answer was predicated on you not being in control of the definition of the struct. jimt's answer is definitely what you want. – Lily Ballard Jul 27 '12 at 19:24
  • Yeah, I wasn't clear whether or not it was an external package or not. But your answer is still relevant and useful in the cases when you don't control the definitions. – ANisus Jul 27 '12 at 19:26
5

I will only add that you can generate those tags automatically using gopls. It is a menial task to add the tags manually, especially with large json structs, so the feature is a live-saver.

Adding the gopls langserver differs based on one's preferred editor. After:

go install golang.org/x/tools/gopls@latest

For Neovim with CoC you can :CocInstall coc-go and then go.tags.add. For complete docs on the CoC extension for go please see here.

Piotr Ostrowski
  • 520
  • 5
  • 8
  • 3
    This could be a great answer if you simply tell how to do it. I know someone can google it. But showing how to achieve it would actually answer the question. – Dan Ortega Aug 02 '22 at 06:34
  • True. However, depending on the question author's preferred editor the implementation steps for generating the tags using gopls might differ. Hence, I skipped them. – Piotr Ostrowski Aug 02 '22 at 09:52
  • 1
    In VSCode, you can open the command panel (`Cmd + Shift + p`), and seach "Add tags" after this setup. – krsoni Nov 08 '22 at 11:34
0

You can generate the json:"camelCase" tags of struct fields with fatih/gomodifytags.

e.g.

$ gomodifytags -file main.go -struct T -add-tags json -transform camelcase -quiet -w

NB: You can also use -override to override existing tags.

Letik
  • 520
  • 5
  • 11