Skip to content

AEP-0004 Linter Rules

Resource annotation presence

Resource annotation presence

This rule enforces that the same resource type doesn’t appear in more than one google.api.resource annotation, as described in AEP-004.

Details

This rule complains about messages that have the same type for the google.api.resource annotation, which frequently occur due to copy-paste errors and messages spread across multiple files and/or packages. Duplicate resource definitions can cause compilation problems in generated client code.

Examples

Incorrect code for this rule:

message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
string path = 1;
}
message Author {
option (google.api.resource) = {
// Incorrect: should be "library.googleapis.com/Author".
type: "library.googleapis.com/Book"
pattern: "authors/{author}"
};
string path = 1;
}

Correct code for this rule:

// Correct.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
string path = 1;
}
message Author {
option (google.api.resource) = {
type: "library.googleapis.com/Author"
pattern: "authors/{author}"
};
string path = 1;
}

Disabling

If you need to violate this rule, use a comment at the top of the file. Remember to also include an aep.dev/not-precedent comment explaining why.

// (-- api-linter: core::0004::duplicate-resource=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
syntax = "proto3";
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
string path = 1;
}
message Author {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "authors/{author}"
};
string path = 1;
}
Resource path field never optional

Resource path field never optional

This rule enforces that the path field of a resource message is not labeled with proto3_optional.

Details

This rule scans for messages with a google.api.resource annotation and ensures that the configured path field (either path or whichever field specified via path_field) is not labeled as optional.

Examples

Incorrect code for this rule:

// Incorrect.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
// The path field should not be labeled as optional.
optional string path = 1;
}

Correct code for this rule:

// Correct.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
string path = 1;
}

Disabling

If you need to violate this rule, use a leading comment above the message.

// (-- api-linter: core::04::path-never-optional=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
optional string path = 1;
}

If you need to violate this rule for an entire file, place the comment at the top of the file.

Resource annotation presence

Resource annotation presence

This rule enforces that top-level messages that appear to represent resources have a google.api.resource annotation, as described in AEP-4.

Details

This rule scans all top-level messages, and assumes that messages with a string path field are resources unless the message name ends with Request. For messages that are resources, it complains if the google.api.resource annotation is missing.

Examples

Incorrect code for this rule:

// Incorrect.
message Book {
// A `google.api.resource` annotation should be here.
string path = 1;
}

Correct code for this rule:

// Correct.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
string path = 1;
}

Disabling

If you need to violate this rule, use a leading comment above the message.

// (-- api-linter: core::4::resource-annotation=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
message Book {
string path = 1;
}

If you need to violate this rule for an entire file, place the comment at the top of the file.

Resource patterns

Resource patterns

This rule enforces that files that define a resource with the google.api.resource_definition annotation have a pattern defined, as described in AEP-123.

Details

This rule scans all google.api.resource_definition annotations in all files, and complains if pattern is not provided at least once. It also complains if the segments outside of variable names contain underscores.

Examples

Incorrect code for this rule:

import "google/api/resources.proto";
// Incorrect.
option (google.api.resource_definition) = {
type: "library.googleapis.com/Book"
// pattern should be here
};
import "google/api/resources.proto";
// Incorrect.
option (google.api.resource_definition) = {
type: "library.googleapis.com/ElectronicBook"
// Should be: publishers/{publisher}/electronicBooks/{electronic_book}
pattern: "publishers/{publisher}/electronic_books/{electronic_book}"
};

Correct code for this rule:

import "google/api/resources.proto";
// Correct.
option (google.api.resource_definition) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
import "google/api/resource.proto";
// Correct.
option (google.api.resource_definition) = {
type: "library.googleapis.com/ElectronicBook"
pattern: "publishers/{publisher}/electronicBooks/{electronic_book}"
};

Disabling

If you need to violate this rule, use a comment on the annotation.

import "google/api/resource.proto";
// (-- api-linter: core::0123::resource-definition-pattern=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
option (google.api.resource_definition) = {
type: "library.googleapis.com/Book"
};

If you need to violate this rule for an entire file, place the comment at the top of the file.

Resource type name

Resource type name

This rule enforces that files that define a resource with the google.api.resource_definition annotation have a properly formatted type, as described in AEP-123.

Details

This rule scans files with google.api.resource_definition annotations, and validates the format of the type field conforms to {Service Name}/{Type}.

Examples

Incorrect code for this rule:

import "google/api/resource.proto";
// Incorrect.
option (google.api.resource_definition) = {
// Should not have more than one separating '/'.
type: "library.googleapis.com/Genre/Mystery/Book"
pattern: "publishers/{publisher}/books/{book}"
};

Correct code for this rule:

import "google/api/resource.proto";
// Correct.
option (google.api.resource_definition) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};

Disabling

If you need to violate this rule, use a leading comment above the annotation.

import "google/api/resource.proto";
// (-- api-linter: core::0123::resource-definition-type-name=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
option (google.api.resource_definition) = {
type: "library.googleapis.com/Genre/Mystery/Book"
pattern: "publishers/{publisher}/books/{book}"
};

If you need to violate this rule for an entire file, place the comment at the top of the file.

Resource pattern variables

Resource pattern variables

This rule enforces that resource patterns use consistent variable naming conventions, as described in AEP-4.

Details

This rule scans all files with google.api.resource_definition annotations, and complains if variables in a pattern use camel case, or end in _id.

Examples

Incorrect code for this rule:

import "google/api/resource.proto";
// Incorrect.
option (google.api.resource_definition) = {
type: "library.googleapis.com/Book"
// Should be: publishers/{publisher}/books/{book}
pattern: "publishers/{publisher_id}/books/{book_id}"
};
import "google/api/resource.proto";
// Incorrect.
option (google.api.resource_definition) = {
type: "library.googleapis.com/ElectronicBook"
// Should be: publishers/{publisher}/electronicBooks/{electronic_book}
pattern: "publishers/{publisher}/electronicBooks/{electronicBook}"
};

Correct code for this rule:

import "google/api/resource.proto";
// Correct.
option (google.api.resource_definition) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
import "google/api/resource.proto";
// Correct.
option (google.api.resource_definition) = {
type: "library.googleapis.com/ElectronicBook"
pattern: "publishers/{publisher}/electronicBooks/{electronic_book}"
};

Disabling

If you need to violate this rule, use a leading comment above the annotation.

import "google/api/resource.proto";
// (-- api-linter: core::4::resource-definition-variables=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
option (google.api.resource_definition) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher_id}/books/{book_id}"
};

If you need to violate this rule for an entire file, place the comment at the top of the file.

Resource name components alternate

Resource name components alternate

This rule enforces that messages that have a google.api.resource annotation have pattern annotations that alternate between collection and identifier, as described in AEP-4.

Details

This rule scans messages with a google.api.resource annotation, and validates that each pattern alternated between collection and identifiers.

Examples

Incorrect code for this rule:

// Incorrect.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
// two collections next to each other.
pattern: "publishers/books/{book}"
};
string path = 1;
}

Correct code for this rule:

// Correct.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
string path = 1;
}

Disabling

If you need to violate this rule, use a leading comment above the message.

// (-- api-linter: core::4::resource-name-components-alternate=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/books/{book}"
};
string path = 1;
}

If you need to violate this rule for an entire file, place the comment at the top of the file.

Resource path field

Resource path field

This rule enforces that messages that appear to represent resources have a string path field, as described in AEP-4.

Details

This rule scans all messages that have a google.api.resource annotation, and complains if the path field is missing or if it is any type other than singular string.

Examples

Incorrect code for this rule:

// Incorrect: missing `string path` field.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
}
// Incorrect.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
// Should be `string`, not `bytes`.
bytes path = 1;
}

Correct code for this rule:

// Correct.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
string path = 1;
}

Disabling

If you need to violate this rule, use a leading comment above the message, or above the field if it is the wrong type.

// (-- api-linter: core::4::resource-path-field=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
}

If you need to violate this rule for an entire file, place the comment at the top of the file.

Resource patterns

Resource patterns

This rule enforces that messages that appear to represent resources have a pattern defined on their google.api.resource annotation, as described in AEP-4.

Details

This rule scans all messages with google.api.resource annotations, and complains if pattern is not provided at least once. It also complains if the segments outside of variable names contain underscores.

Examples

Incorrect code for this rule:

// Incorrect.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
// pattern should be here
};
string path = 1;
}
// Incorrect.
message ElectronicBook {
option (google.api.resource) = {
type: "library.googleapis.com/ElectronicBook"
// Should be: publishers/{publisher}/electronicBooks/{electronic_book}
pattern: "publishers/{publisher}/electronic_books/{electronic_book}"
};
string path = 1;
}

Correct code for this rule:

// Correct.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
string path = 1;
}
// Correct.
message ElectronicBook {
option (google.api.resource) = {
type: "library.googleapis.com/ElectronicBook"
pattern: "publishers/{publisher}/electronicBooks/{electronic_book}"
};
string path = 1;
}

Disabling

If you need to violate this rule, use a leading comment above the message.

// (-- api-linter: core::4::resource-pattern=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
};
string path = 1;
}

If you need to violate this rule for an entire file, place the comment at the top of the file.

Resource type name

Resource type name

This rule enforces that messages that have a google.api.resource annotation, have a properly formatted plural, as described in AEP-4.

Details

This rule scans messages with a google.api.resource annotation, and verifies the plural field exists.

Examples

Incorrect code for this rule:

// Incorrect.
message Book {
// no plural annotation
option (google.api.resource) = {
type: "library.googleapis.com/BookShelf"
pattern: "publishers/{publisher}/bookShelves/{book_shelf}"
};
string path = 1;
}

Correct code for this rule:

// Correct.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/BookShelf"
pattern: "publishers/{publisher}/bookShelves/{book_shelf}"
plural: "bookShelves",
};
string path = 1;
}

Disabling

If you need to violate this rule, use a leading comment above the message.

// (-- api-linter: core::4::resource-plural=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Genre/Mystery/Book"
pattern: "publishers/{publisher}/books/{book}"
};
string path = 1;
}

If you need to violate this rule for an entire file, place the comment at the top of the file.

Resource annotation presence

Resource annotation presence

This rule enforces that any field with a google.api.resource_reference annotation has a string type, as described in AEP-4.

Details

This rule scans all fields with a google.api.resource_reference annotation. If one is found, the type is checked, and the rule complains if the type is anything other than string.

It suggests the removal of the annotation rather than fixing the type, because what we have observed in real life is that the annotation is usually what is in error rather than the selected type.

Examples

Incorrect code for this rule:

// Incorrect.
message Book {
string path = 1;
// This is not a resource reference; the annotation does not belong.
Author author = 2 [(google.api.resource_reference) = {
type: "library.googleapis.com/Author"
}];
}

Correct code for this rule:

// Correct.
message Book {
string path = 1;
Author author = 2;
}
// Correct.
message Book {
string path = 1;
string author = 2 [(google.api.resource_reference) = {
type: "library.googleapis.com/Author"
}];
}

Disabling

Do not violate this rule; it will break several tools.

Resource type name

Resource type name

This rule enforces that messages that have a google.api.resource annotation, have a properly formatted singular, as described in AEP-4.

Details

This rule scans messages with a google.api.resource annotation, and validates the format of the singular field is the lower camel case of type.

Examples

Incorrect code for this rule:

// Incorrect.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/BookShelf"
pattern: "publishers/{publisher}/bookShelves/{book_shelf}"
// does not match type.
singular: "shelf",
};
string path = 1;
}

Correct code for this rule:

// Correct.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/BookShelf"
pattern: "publishers/{publisher}/bookShelves/{book_shelf}"
singular: "bookShelf",
};
string path = 1;
}

Disabling

If you need to violate this rule, use a leading comment above the message.

// (-- api-linter: core::4::resource-singular=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Genre/Mystery/Book"
pattern: "publishers/{publisher}/books/{book}"
singular: "shelf",
};
string path = 1;
}

If you need to violate this rule for an entire file, place the comment at the top of the file.

Resource type name

Resource type name

This rule enforces that messages that have a google.api.resource annotation, have a properly formatted type, as described in AEP-4.

Details

This rule scans messages with a google.api.resource annotation, and validates the format of the type field conforms to {Service Name}/{Type}.

Examples

Incorrect code for this rule:

// Incorrect.
message Book {
option (google.api.resource) = {
// Should not have more than one separating '/'.
type: "library.googleapis.com/Genre/Mystery/Book"
pattern: "publishers/{publisher}/books/{book}"
};
string path = 1;
}

Correct code for this rule:

// Correct.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
string path = 1;
}

Disabling

If you need to violate this rule, use a leading comment above the message.

// (-- api-linter: core::4::resource-type-name=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Genre/Mystery/Book"
pattern: "publishers/{publisher}/books/{book}"
};
string path = 1;
}

If you need to violate this rule for an entire file, place the comment at the top of the file.

Resource pattern variables

Resource pattern variables

This rule enforces that resource patterns use consistent variable naming conventions, as described in AEP-4.

Details

This rule scans all messages with google.api.resource annotations, and complains if variables in a pattern use camel case, or end in _id.

Examples

Incorrect code for this rule:

// Incorrect.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
// Should be: publishers/{publisher}/books/{book}
pattern: "publishers/{publisher_id}/books/{book_id}"
};
string path = 1;
}
// Incorrect.
message ElectronicBook {
option (google.api.resource) = {
type: "library.googleapis.com/ElectronicBook"
// Should be: publishers/{publisher}/electronicBooks/{electronic_book}
pattern: "publishers/{publisher}/electronicBooks/{electronicBook}"
};
string path = 1;
}

Correct code for this rule:

// Correct.
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
string path = 1;
}
// Correct.
message ElectronicBook {
option (google.api.resource) = {
type: "library.googleapis.com/ElectronicBook"
pattern: "publishers/{publisher}/electronicBooks/{electronic_book}"
};
string path = 1;
}

Disabling

If you need to violate this rule, use a leading comment above the message.

// (-- api-linter: core::4::resource-variables=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher_id}/books/{book_id}"
};
string path = 1;
}

If you need to violate this rule for an entire file, place the comment at the top of the file.