Skip to content

AEP-0135 Linter Rules

Delete methods- force field

This rule enforces that the standard Delete method for a resource that parents other resources in the service have a bool force field in the request message, as mandated in AEP-135.

This rule looks at any message matching Delete*Request for a resource with child resources in the same service and complains if the force field is missing.

Incorrect code for this rule:

// Incorrect.
message DeletePublisherRequest {
// Where Publisher parents the Book resource.
string path = 1 [
(google.api.resource_reference).type = "library.googleapis.com/Publisher"];
// Missing `bool force` field.
}

Correct code for this rule:

// Correct.
message DeletePublisherRequest {
// Where Publisher parents the Book resource.
string path = 1 [
(google.api.resource_reference).type = "library.googleapis.com/Publisher"];
// If set to true, any books from this publisher will also be deleted.
// (Otherwise, the request will only work if the publisher has no books.)
bool force = 2;
}

If you need to violate this rule, use a leading comment above the message (if the path field is missing) or above the field (if it is the wrong type). Remember to also include an aep.dev/not-precedent comment explaining why.

// (-- api-linter: core::0135::force-field=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
message DeletePublisherRequest {
// Where Publisher parents the Book resource.
string path = 1 [
(google.api.resource_reference).type = "library.googleapis.com/Publisher"];
}

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

Delete methods- No HTTP body

This rule enforces that all Delete RPCs omit the HTTP body, as mandated in AEP-135.

This rule looks at any message matching beginning with Delete, and complains if the HTTP body field is set.

Incorrect code for this rule:

// Incorrect.
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
body: "*" // This should be absent.
};
}

Correct code for this rule:

// Correct.
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
}

If you need to violate this rule, use a leading comment above the method. Remember to also include an aep.dev/not-precedent comment explaining why.

// (-- api-linter: core::0135::http-body=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
body: "*"
};
}

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

Delete methods- DELETE HTTP verb

This rule enforces that all Delete RPCs use the DELETE HTTP verb, as mandated in AEP-135.

This rule looks at any message matching beginning with Delete, and complains if the HTTP verb is anything other than DELETE. It does check additional bindings if they are present.

Incorrect code for this rule:

// Incorrect.
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
post: "/v1/{path=publishers/*/books/*}" // Should be `delete:`.
};
}

Correct code for this rule:

// Correct.
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
}

If you need to violate this rule, use a leading comment above the method. Remember to also include an aep.dev/not-precedent comment explaining why.

// (-- api-linter: core::0135::http-method=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
post: "/v1/{path=publishers/*/books/*}"
};
}

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

Delete methods- HTTP URI path field

This rule enforces that all Delete RPCs map the path field to the HTTP URI, as mandated in AEP-135.

This rule looks at any message matching beginning with Delete, and complains if the path variable is not included in the URI. It does check additional bindings if they are present.

Incorrect code for this rule:

// Incorrect.
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/publishers/*/books/*" // The `path` field should be extracted.
};
}

Correct code for this rule:

// Correct.
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
}

If you need to violate this rule, use a leading comment above the method. Remember to also include an aep.dev/not-precedent comment explaining why.

// (-- api-linter: core::0135::http-uri-path=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/publishers/*/books/*"
};
}

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

Delete methods- Method signature

This rule enforces that all Delete standard methods have a google.api.method_signature annotation with a value of "path", as mandated in AEP-135.

This rule looks at any method beginning with Delete, and complains if the google.api.method_signature annotation is missing, or if it is set to any value other than "path". Additional method signatures, if present, are ignored.

Incorrect code for this rule:

// Incorrect.
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
// A google.api.method_signature annotation should be present.
}
// Incorrect.
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.method_signature) = "book"; // Should be "path".
}

Correct code for this rule:

// Correct.
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.method_signature) = "path";
}

If you need to violate this rule, use a leading comment above the method. Remember to also include an aep.dev/not-precedent comment explaining why.

// (-- api-linter: core::0135::method-signature=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.method_signature) = "book";
}

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

Delete requests- force field

This rule enforces that all Delete request force fields have type bool, as mandated in AEP-135.

This rule looks at any message matching Delete*Request that contains a force field and complains if the field is not a singular bool.

Incorrect code for this rule:

message DeletePublisherRequest {
string path = 1 [
(google.api.resource_reference).type = "library.googleapis.com/Publisher",
(google.api.field_behavior) = REQUIRED
];
int32 force = 2; // Field type should be `bool`.
}

Correct code for this rule:

message DeletePublisherRequest {
string path = 1 [
(google.api.resource_reference).type = "library.googleapis.com/Publisher",
(google.api.field_behavior) = REQUIRED
];
bool force = 2;
}

If you need to violate this rule, use a leading comment above the field. Remember to also include an aep.dev/not-precedent comment explaining why.

message DeletePublisherRequest {
string path = 1 [
(google.api.resource_reference).type = "library.googleapis.com/Publisher",
(google.api.field_behavior) = REQUIRED
];
// (-- api-linter: core::0135::request-force-field=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
int32 force = 2;
}

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

Delete methods- Request message

This rule enforces that all Delete RPCs have a request message name of Delete*Request, as mandated in AEP-135.

This rule looks at any message matching beginning with Delete, and complains if the name of the corresponding input message does not match the name of the RPC with the suffix Request appended.

Incorrect code for this rule:

// Incorrect.
// Should be `DeleteBookRequest`.
rpc DeleteBook(Book) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
}

Correct code for this rule:

// Correct.
rpc DeleteBook(DeleteBookRequest) returns (Book) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
}

If you need to violate this rule, use a leading comment above the method. Remember to also include an aep.dev/not-precedent comment explaining why.

// (-- api-linter: core::0135::request-message-name=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
rpc DeleteBook(Book) returns (google.protobuf.Empty) {
option (google.api.http) = {
get: "/v1/{path=publishers/*/books/*}"
};
}

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

Delete methods- Field behavior

This rule enforces that all Delete standard methods have google.api.field_behavior set to REQUIRED on their string path field, as mandated in AEP-135.

This rule looks at any message matching Delete*Request and complains if the path field does not have a google.api.field_behavior annotation with a value of REQUIRED.

Incorrect code for this rule:

// Incorrect.
message DeleteBookRequest {
// The `google.api.field_behavior` annotation should also be included.
string path = 1 [(google.api.resource_reference) = {
type: "library.googleapis.com/Book"
}];
}

Correct code for this rule:

// Correct.
message DeleteBookRequest {
string path = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference).type = "library.googleapis.com/Book"
];
}

If you need to violate this rule, use a leading comment above the field. Remember to also include an aep.dev/not-precedent comment explaining why.

message DeleteBookRequest {
// (-- api-linter: core::0135::request-path-behavior=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
string path = 1 [(google.api.resource_reference) = {
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.

Delete methods- path field

This rule enforces that all Delete standard methods have a string path field in the request message, as mandated in AEP-135.

This rule looks at any message matching Delete*Request and complains if either the path field is missing, or if it has any type other than string.

Incorrect code for this rule:

// Incorrect.
message DeleteBookRequest {
string book = 1; // Field path should be `path`.
}
// Incorrect.
message DeleteBookRequest {
bytes path = 1; // Field type should be `string`.
}

Correct code for this rule:

// Correct.
message DeleteBookRequest {
string path = 1;
}

If you need to violate this rule, use a leading comment above the message (if the path field is missing) or above the field (if it is the wrong type). Remember to also include an aep.dev/not-precedent comment explaining why.

// (-- api-linter: core::0135::request-path-field=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
message DeleteBookRequest {
string book = 1;
}

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

Delete methods- Resource reference

This rule enforces that all Delete standard methods have google.api.resource_reference on their string path field, as mandated in AEP-135.

This rule looks at the path field of any message matching Delete*Request and complains if it does not have a google.api.resource_reference annotation.

Incorrect code for this rule:

// Incorrect.
message DeleteBookRequest {
// The `google.api.resource_reference` annotation should also be included.
string path = 1 [(google.api.field_behavior) = REQUIRED];
}

Correct code for this rule:

// Correct.
message DeleteBookRequest {
string path = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference).type = "library.googleapis.com/Book"
];
}

If you need to violate this rule, use a leading comment above the field. Remember to also include an aep.dev/not-precedent comment explaining why.

message DeleteBookRequest {
// (-- api-linter: core::0135::request-path-reference=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
string path = 1 [(google.api.field_behavior) = REQUIRED];
}

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

Delete methods- Name field

This rule enforces that all Delete standard methods have a string path field in the request message, as mandated in AEP-135.

This rule looks at any message matching Delete*Request and complains if the path field is missing.

Incorrect code for this rule:

// Incorrect.
message DeleteBookRequest {
// Field path should be `path`.
string book = 1;
}

Correct code for this rule:

// Correct.
message DeleteBookRequest {
string path = 1;
}

If you need to violate this rule, use a leading comment above the message. Remember to also include an aep.dev/not-precedent comment explaining why.

// (-- api-linter: core::0135::request-path-required=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
message DeleteBookRequest {
string book = 1;
}

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

Delete methods- Required fields

This rule enforces that all Delete standard methods do not have unexpected required fields, as mandated in AEP-135.

This rule looks at any message matching Delete*Request and complains if it comes across any required fields other than:

Incorrect code for this rule:

// Incorrect.
message DeleteBookRequest {
string path = 1 [(google.api.field_behavior) = REQUIRED];
// Non-standard required field.
bool allow_missing = 4 [(google.api.field_behavior) = REQUIRED];
}

Correct code for this rule:

// Correct.
message DeleteBookRequest {
string path = 1 [(google.api.field_behavior) = REQUIRED];
bool allow_missing = 4 [(google.api.field_behavior) = OPTIONAL];
}

If you need to violate this rule, use a leading comment above the field. Remember to also include an aep.dev/not-precedent comment explaining why.

message DeleteBookRequest {
string path = 1 [(google.api.field_behavior) = REQUIRED];
// (-- api-linter: core::0135::request-required-fields=disabled
// aep.dev/not-precedent: We really need this field to be required because
// reasons. --)
bool allow_missing = 4 [(google.api.field_behavior) = REQUIRED];
}

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

Delete methods- Unknown fields

This rule enforces that all Delete standard methods do not have unexpected fields, as mandated in AEP-135.

This rule looks at any message matching Delete*Request and complains if it comes across any fields other than:

Incorrect code for this rule:

// Incorrect.
message DeleteBookRequest {
string path = 1;
string library_id = 2; // Non-standard field.
}

Correct code for this rule:

// Correct.
message DeleteBookRequest {
string path = 1;
}

If you need to violate this rule, use a leading comment above the field. Remember to also include an aep.dev/not-precedent comment explaining why.

message DeleteBookRequest {
string path = 1;
// (-- api-linter: core::0135::request-unknown-fields=disabled
// aep.dev/not-precedent: We really need this field because reasons. --)
string library_id = 2;
}

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

Long-running Delete

This rule enforces that declarative-friendly delete methods use long-running operations, as mandated in AEP-135.

This rule looks at any Delete method connected to a resource with a google.api.resource annotation that includes style: DECLARATIVE_FRIENDLY, and complains if it does not use long-running operations.

Incorrect code for this rule:

// Incorrect.
// Assuming that Book is styled declarative-friendly, DeleteBook should
// return a long-running operation.
rpc DeleteBook(DeleteBookRequest) returns (Book) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
}

Correct code for this rule:

// Correct.
// Assuming that Book is styled declarative-friendly...
rpc DeleteBook(DeleteBookRequest) returns (google.longrunning.Operation) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
option (google.longrunning.operation_info) = {
response_type: "Book"
metadata_type: "OperationMetadata"
};
}

If you need to violate this rule, use a leading comment above the message. Remember to also include an aep.dev/not-precedent comment explaining why.

// (-- api-linter: core::0135::response-lro=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
rpc DeleteBook(DeleteBookRequest) returns (Book) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
}

Note: Violations of declarative-friendly rules should be rare, as tools are likely to expect strong consistency.

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

Delete methods- Response message

This rule enforces that all Delete RPCs have a response message of google.protobuf.Empty or the resource, as mandated in AEP-135.

This rule looks at any message matching beginning with Delete, and complains if the name of the corresponding output message is not one of:

  • google.protobuf.Empty
  • The name of the RPC with the prefix Delete removed.

It also permits a response of google.longrunning.Operation; in this case, it checks the response_type in the google.longrunning.operation_info annotation and ensures that it corresponds to either google.protobuf.Empty or the name of the RPC with the prefix Delete removed.

Incorrect code for this rule:

// Incorrect.
// Should be `google.protobuf.Empty` or the resource.
rpc DeleteBook(DeleteBookRequest) returns (DeleteBookResponse) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
}

Correct code for this rule:

// Correct.
rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
}
// Correct.
rpc DeleteBook(DeleteBookRequest) returns (Book) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
}

Important: For declarative-friendly resources, only the resource is permitted as a return type (and therefore only the second example is valid).

Incorrect code for this rule:

// Incorrect.
rpc DeleteBook(DeleteBookRequest) returns (google.longrunning.Operation) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
option (google.longrunning.operation_info) = {
// Should be "google.protobuf.Empty" or "Book".
response_type: "DeleteBookResponse"
metadata_type: "DeleteBookMetadata"
};
}

Correct code for this rule:

// Correct.
rpc DeleteBook(DeleteBookRequest) returns (google.longrunning.Operation) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
option (google.longrunning.operation_info) = {
response_type: "google.protobuf.Empty"
metadata_type: "DeleteBookMetadata"
};
}
// Correct.
rpc DeleteBook(DeleteBookRequest) returns (google.longrunning.Operation) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
option (google.longrunning.operation_info) = {
response_type: "Book"
metadata_type: "DeleteBookMetadata"
};
}

If you need to violate this rule, use a leading comment above the method. Remember to also include an aep.dev/not-precedent comment explaining why.

// (-- api-linter: core::0135::response-message-name=disabled
// aep.dev/not-precedent: We need to do this because reasons. --)
rpc DeleteBook(DeleteBookRequest) returns (DeleteBookResponse) {
option (google.api.http) = {
delete: "/v1/{path=publishers/*/books/*}"
};
}

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