Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions aip/cloud/25001.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
id: 25001
state: draft
created: TBD
placement:
category: gcp
---

# Empty Objects

Fields of type Message **must not** be empty. Empty messages do not have uniform
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this sentence is too broad in its guidance. Empty messages are very useful for future proofing APIs, whether it be a response message, Operation metadata, or just a nested message in a resource. I don't think the use of empty messages should be banned completely. It looks like you have a couple of specific scenarios, I think the guidance should focus on those scenarios, and potentially outline when it is OK to use empty messages (i.e. in the scenarios i've mentioned above).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, ok how about something like:

Messages within the body of resource requests or responses must not be empty.

No problems with empty responses as a concept, or empty operation information. Just empty objects within resources are the target


## Alternatives

The presence of empty Messages are sometimes used to indicate that a flag is enabled. Alternatives to empty Messages could include a single boolean field within the Message to signify enablement or an Enum rather than an empty Message.

### Add Field to Message
For example:
```proto
message EnableMyFeature {
}
```
Could be modeled instead as:

```proto
message MyFeature {
bool enabled = 1;
}
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember seeing this as purely enablement, outside a oneof. Often it's "here's a message which might contain more information later" and its presence is indicative of the choice for that feature.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, it's usually an object that could contain more information later. I think that's where adding the enabled flag within the object works well, as new fields can be added alongside that field as they become available.

One of the problems I'm trying to solve here is that there are many ways to implement behavior off of an empty message, none of which are clear to the user. To a user that is new to an API seeing an empty object documented in the REST docs is confusing, and it is unclear how or why to use such a field.

Some of this confusion is contributed to by our generated documentation for empty objects like the following. DLP primitive transformations have a field replaceWithInfoTypeConfig that is an empty object. The generated documentation for this field seems broken to a viewer, but is technically correct.

I don't think that the documentation generation is to blame here though. This pattern is nonstandard and nonintuitive to users, which is why generated tools and docs end up with a sub-par experience.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But enabled won't always be suitable, for multiple reasons:

  • Depending on the context, it may be invalid to have a configuration which isn't enabled, because it's always got to be used to retrieve something. Basically you're asserting that there are always more valid scenarios than an empty message implies, and I don't believe that assertion is justified.
  • Adding enabled requires more work for anyone populating a configuration; it's easy to forget to explicitly enable it, at which point it may be hard to work out what's wrong
  • If it is valid for enabled to be false, then a user retrieving a configuration where it's false will still see an empty object - is that really any better than the current situation? (I'd argue it's actually worse, if they've only accidentally left off enabled.)

I agree that we can and should improve documentation - but I believe that's all that we should do here. I don't believe we should be artificially requiring an additional field.

As a side-note, I'm going to do some research on:

  • How many (and which) messages are currently empty across all Google APIs
  • How many (and which) messages have been empty but then become non-empty

That may provide some additional food for thought.

### Move Option to Top-Level Enum

For a situation where the presence of an empty Message indicates a certain option is being chosen, an alternative is to choose the option via an enum rather than the presence of a particular object.

For example:
```proto
oneof access_model {
AccessModelFree free = 1
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it make sense for this oneof to have unspecified? or some default value, as with any other enum value?

IIRC that works around backwards compatibility issues where the returned enum is not a value that is present in older versions of a client.

AccessModelQuota quota = 2
}

message AccessModelFree {
}

message AccessModelQuota {
int32 requests_per_day = 1;
}
```

Could be modeled instead as:
```proto
enum AccessModel {
UNSPECIFIED = 0;
FREE = 1;
QUOTA = 1;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: = 2, correct?

}

message AccessModelQuota {
int32 requests_per_day = 1;
}
```
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except you've then got far more potential for conflicting options having their details specified at the same time.

The oneof pattern is much more sensible IMO... if tools are unable to handle empty messages, I'd far prefer them to be improved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to agree that the proposal of sidelined enum configuration over the values in the enum itself has poor usability: it requires the user to look at two different values (the enum and the corresponding configuration message) to reason about which value is correct.

I can see the argument about an empty top-level message, but what's the issue with an empty enum value? it's clear what the type of the object is from the enum itself.



## Changelog

- **TBD**: Created