AIP-200

Precedent

Many times, APIs are written in ways that do not match new guidance that is added to these standards after those APIs have already been released. Additionally, sometimes it can make sense to intentionally violate standards for particular reasons, such as maintaining consistency with established systems, meeting stringent performance requirements, or other practical concerns. Finally, as carefully as everyone reviews APIs before they are released, sometimes mistakes can slip through.

Since it often is not feasible to fix past mistakes or make the standards serve every use case, APIs may be stuck with these exceptions for quite some time. Further, since new APIs often base their designs (names, types, structures, etc) on existing APIs, it is possible that a standards violation in one API could spill over into other APIs, even if original reason for the exception is not applicable to the other APIs.

As a result of this problem, it is important to “stop the bleeding” of these standards exceptions into new APIs, and additionally document the reasons for each exception so that historical wisdom is not lost.

Guidance

If an API violates the AIP standards for any reason, there must be an internal comment linking to this document using its descriptive link (aip.dev/not-precedent) to ensure others do not copy the violations or cite the errors as precedent of a “previously approved API”.

The comment should also include an explanation of what violates standards and why it is necessary. For example:

message DailyMaintenanceWindow {
  // Time within the maintenance window to start the maintenance operations.
  // It must use the format "HH MM", where HH : [00-23] and MM : [00-59] GMT.
  // (-- aip.dev/not-precedent: This was designed for consistency with crontab,
  //     and preceded the AIP standards.
  //     Ordinarily, this type should be `google.type.TimeOfDay`. --)
  string start_time = 2;

  // Output only. Duration of the time window, automatically chosen to be
  // smallest possible in the given scenario.
  // (-- aip.dev/not-precedent: This preceded the AIP standards.
  //     Ordinarily, this type should be `google.protobuf.Duration`. --)
  string duration = 3;
}

Important: APIs should only be considered to be precedent-setting if they are in beta or GA.

Local consistency

If an API violates a standard throughout, it would be jarring and frustrating to users to break the existing pattern only for the sake of adhering to the global standard.

For example, if all of an API’s resources use creation_time (instead of the standard field create_time described in AIP-142), a new resource in that API should continue to follow the local pattern.

However, others who might otherwise copy that API should be made aware that this is contra-standard and not something to cite as precedent when launching new APIs.

// ...
message Book {
  // (-- aip.dev/not-precedent: This field was present before there was a
  //     standard field.
  //     Ordinarily, it should be spelled `create_time`. --)
  google.protobuf.Timestamp creation_time = 1;
}

// ...
message Author {
  // (-- aip.dev/not-precedent: `Book` had `creation_time` before there was
  //     a standard field, so we match that here for consistency. Ordinarily,
  //     this would be spelled `create_time`. --)
  google.protobuf.Timestamp creation_time = 1;
}

Grandfathered functionality

Standards violations are sometimes overlooked before launching, resulting in APIs that become stable and therefore can not easily be modified. Additionally, a stable API may pre-date a standards requirement.

In these scenarios, it is difficult to make the API fit the standard. However, the API should still cite that the functionality is contra-standard so that other APIs do not copy the mistake and cite the existing API as a reason why their design should be approved.

Adherence to external spec

Occasionally, APIs must violate standards because specific requests are implementations of an external specification (for example, OAuth), and their specification may be at odds with AIP guidelines. In this case, it is likely to be appropriate to follow the external specification.

Adherence to existing systems

Similar to the example of an external specification above, it may be proper for an API to violate AIP guidelines to fit in with an existing system in some way. This is a fundamentally similar case where it is wise to meet the customer where they are. A potential example of this might be integration with or similarity to a partner API.

Expediency

Sometimes there are users who need an API surface by a very hard deadline or money walks away. Since most APIs serve a business purpose, there will be times when an API could be better but cannot get it that way and into users’ hands before the deadline. In those cases, API review councils may grant exceptions to ship APIs that violate guidelines due to time and business constraints.

Technical concerns

Internal systems sometimes have very specific implementation needs (e.g., they rely on operation transforms that speak UTF-16, not UTF-8) and adhering to AIP guidelines would require extra work that does not add significant value to API consumers. Future systems which are likely to expose an API at some point should bear this in mind to avoid building underlying infrastructure which makes it difficult to follow AIP guidelines.

Changelog

  • 2020-03-27: Reworded much of this AIP to follow AIP-8, and remove first and second person. No semantic changes.
  • 2019-05-04: Changed to a public link (aip.dev/not-precedent), and changed references to “the style guide” to use the more generic term “standards” (to account for a general shift to AIPs).