googleapis / google-cloud-go

Google Cloud Client Libraries for Go.
https://cloud.google.com/go/docs/reference
Apache License 2.0
3.73k stars 1.28k forks source link

firestore: opt-in support for json struct tags when firestore struct tag is not available #10545

Open nathanperkins opened 3 months ago

nathanperkins commented 3 months ago

Is your feature request related to a problem? Please describe.

We would prefer that Firebase serializes our objects in a way that is consistent with the JSON or YAML representation and with the JSON style guide.

We use proto to define and generate some of our request structs. We store the request as a field on one of our objects which is then stored in Firebase. These fields use property keys which don't align with the other object fields because the proto generated structs have json tags but no firebase tags. The default golang representation does not match the JSON style guide.

There is no built-in mechanism for proto to generate arbitrary struct tags, and the feature is rejected by the go proto team. This comment from 2016 shows another engineer having the same exact problem as us.

Besides this issue, it is very, very common for structs to have json or yaml tags defined. When Firebase ignores those tags, it uses an object representation which doesn't align with the other way those structs are being serialized. We would like it to be consistent.

This issue is particularly problematic for services which involve multiple languages, since the default representation may differ.

Describe the solution you'd like

Allow users to configure the client library in a way that it uses the json or yaml tags when a firebase tag is not present. This is a breaking change so it must be opt-in.

Example:

type Foo struct {
  Bar string `json:"baz"`
}

func main() {
  // Note: this is just one way it could be done. I'm open to any API which allows us to enable the feature.
  cl, err := firestore.NewClientWithJSONTags(context.Context(), "my-project")
  if err != nil {
    log.Fatalf("Failed to create client: %s", err)
  }
  v := Foo{
    Bar: "my-value",
  }
  _, err := c.Collection("my-collection").Doc("my-doc").Create(ctx, v)
  if err != nil {
    log.Fatalf("Failed to create Foo in Firestore: %s", err)
  }
}

Results in a document which has baz as a key, instead of the go language default Bar.

{
  "baz": "my-value"
}

Describe alternatives you've considered

Setting the firebase tag on our protos.

Caveats:

nathanperkins commented 3 months ago

Moved from https://github.com/googleapis/google-api-go-client/issues/2686

cc: @codyoss

codyoss commented 2 months ago

I think a small code example could be helpful here.

nathanperkins commented 2 months ago

I think a small code example could be helpful here.

Thanks, added a small example.