googleapis / api-linter

A linter for APIs defined in protocol buffers.
https://linter.aip.dev/
Apache License 2.0
593 stars 144 forks source link

For multi-word nouns, the word boundary is detected incorrectly #946

Open weixifan opened 2 years ago

weixifan commented 2 years ago

If the noun for a resource has multiple words and contains a word with only an initial uppercase letter and digits, for example ServiceV2Config, the word boundary will be detected as Service + V2config as two separate words rather than three separate words Service + V2 + Config. This causes the linter to flag methods such as

rpc UpdateServiceV2Config(UpdateServiceV2ConfigRequest) returns (ServiceV2Config) {
    option (google.api.http) = {
      patch: "/v1/{service_v2_config.name=accounts/*/serviceV2Configs/*}"
      body: "service_v2_config"
    };
    option (google.api.method_signature) = "service_v2_config,update_mask";
  }

Because the linter thinks that the correct name is service_v2config.

GregFurmanek commented 2 years ago

Would you mind pointing to an AIP or another guidance that would provide more detailed info. Should this change only be limited to a version (V)? Do we have other use cases we need to account for? Any exceptions to such rule we need to be aware of?

fsaintjacques commented 2 years ago

This is also something we've witnessed with an internal API where auth0 is a well known product.

// Request for the CreateAuth0MemberInvite  method.                                        
message CreateAuth0MemberInviteRequest {

...

  // (-- api-linter: core::0133::request-unknown-fields=disabled               
  //     api-linter: core::0133::request-resource-field=disabled               
  //     aip.dev/not-precedent: The linter expects `auth0member_invite_id`. --)
  string auth0_member_invite_id = 3;                                           
}

I don't think there will be a common way to break this uniformly. But it would be great to have an escape hatch, maybe an annotation that explicit the expected casing, e.g. in the google.api.resource annotation:

message Auth0MemberInvite {                                
  option (google.api.resource) = {                         
    type: "REDACTED",         
    pattern: "...",
    resource_name: "auth0_member_invite",
  };
  ...
 }                                                       
KoopaKing commented 2 years ago

So I think this is actually somewhat related to my analysis in #614

The real root of the problem is that mapping from camel case (for strings containing characters that cannot be capitalized) to snake case is not a function because there may be multiple valid mappings. Mapping from snake case to camel case is a function however.

The way this was fixed in #614 should be applicable here. Perform the equivalency check by converting the snake case field into camel case, not the other way around.