Google's API design guidelines allow custom methods written as POST /v1/users/{id}:activate, with a colon before the verb. What problem does that colon-suffix syntax solve, and what are its drawbacks?
answer
- colon separates resource name from method
- AIP: custom methods are the fallback
- POST unless genuinely safe
- %3A encoding / router quirks
- alternative: /users/{id}/activation noun
basics
~20 sThe colon visibly marks the last part as a named operation rather than a sub-resource, so readers and routers cannot confuse /users/1:activate with a collection /users/1/activate. Drawbacks: unfamiliar outside Google-style APIs, and colons occasionally trip naive routers, proxies, and tooling.
solid answer
~60 sThe colon is a **disambiguation marker**. In `/users/{id}/activate` the last segment is syntactically indistinguishable from a sub-resource, so the reader cannot tell whether `activate` is a thing you can GET or an operation you invoke. Google's AIP convention writes it `POST /v1/users/{id}:activate`, where the colon says explicitly: everything to the left is the resource name, the token to the right is a custom method on it. That keeps the resource-name grammar uniform — every resource path is still `collection/id/collection/id` — which matters when tooling parses resource names generically, and it makes the escape from standard methods deliberate and greppable. Drawbacks are practical rather than theoretical. Colons in a path segment are legal per RFC 3986, but some routers, proxies, API gateways, and client SDKs handle them awkwardly or over-encode them to `%3A`. The convention is also unfamiliar outside gRPC-transcoded and Google-influenced APIs, so a public API may pay a documentation tax. And the syntax makes custom methods cheap to add, which invites overuse — AIP treats them as a fallback when standard methods genuinely do not fit.
code
http · 11 linesPOST /v1/users/12345:activate HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 2
{}
HTTP/1.1 409 Conflict
Content-Type: application/problem+json
{"type":"about:blank","title":"Conflict","detail":"User is already active"}go deeper
Recognise the syntax and know the verb goes after a colon, always with POST for state changes.
Explain that the colon separates the resource name from the operation so a sub-resource is never confused with an action.
Weigh it against noun sub-resources and status updates, and raise the real-world friction — encoding, gateways, unfamiliar consumers — plus the overuse hazard.
Decide the house convention by audience and tooling: AIP consistency for gRPC-adjacent platforms, plainest-possible syntax for broad public APIs, and enforce one choice API-wide.
## What the convention is Google's API Improvement Proposals describe a **resource-oriented** design where nearly everything is one of five standard methods on resources: List, Get, Create, Update, Delete. When an operation genuinely does not fit — activate a user, cancel an order, move a document, undelete a record, batch-translate text — AIP allows a **custom method**, written in the HTTP mapping with a colon: ``` POST /v1/users/12345:activate POST /v1/documents/9:move POST /v1/orders/abc:cancel ``` The rules that come with it matter as much as the syntax: custom methods use POST unless the operation is genuinely safe and side-effect-free (where GET is permitted), the verb is a lowerCamelCase word, and they are meant to be the exception rather than the default shape of the API. ## The problem the colon solves Without the marker you write `/users/12345/activate`. Structurally that is identical to `/users/12345/settings` — a nested resource. Two consequences follow. First, **human ambiguity**: a reader scanning the URL cannot tell an invocable operation from an addressable sub-resource, and neither can a generated client. Second, and more important in Google's ecosystem, **machine ambiguity**: AIP treats the resource path as a structured *resource name* with a strict alternating grammar of collection ids and resource ids (`users/12345/settings/default`). Slipping a verb into that grammar breaks generic parsers that split a name into its components, resolve parents, or check permissions by prefix. The colon puts the verb outside the name entirely: everything before it is a valid resource name, everything after it is the method. Tools can therefore parse `users/12345` from `users/12345:activate` with a single rule. A smaller benefit is auditability. Custom methods are visually obvious in a spec and in access logs, so it is easy to see whether the API is drifting from resource-oriented into RPC-shaped. ## Drawbacks **Ecosystem friction.** RFC 3986 permits `:` in a path segment, so this is standards-legal, but plenty of software was written by people who never expected it. Some routers treat colons as parameter markers in their own path syntax; some gateways, WAFs, or client libraries percent-encode the colon to `%3A`, which then may or may not be normalised back before routing. It usually works, but it is a class of integration bug you would not otherwise have. **Unfamiliarity.** Outside Google APIs and gRPC-transcoded services, most developers have never seen it. On a public API, an unusual syntax costs support time and invites clients to hand-build URLs incorrectly. **Moral hazard.** Adding `:doThing` is trivially easy, so a team under delivery pressure can grow dozens of custom methods and end up with RPC wearing resource clothing — precisely what the resource-oriented style was meant to avoid. AIP is explicit that custom methods are a last resort after checking whether a standard method, or a differently-modelled resource, would do. ## The alternatives you are choosing between - **Sub-resource nouns**: `POST /users/{id}/activation`. Familiar, no exotic characters, and gives the action a place to store its own data and be read back. Loses the strict resource-name grammar. - **State field updates**: `PATCH /users/{id}` with `{"state": "ACTIVE"}`. Smallest surface, but hides business rules behind what looks like a data write. - **Colon custom methods**: unambiguous and tool-friendly, at the price of familiarity and occasional infrastructure friction. None is wrong. The decision usually turns on audience: an internal or gRPC-adjacent platform benefits from AIP consistency; a broad public HTTP API is usually better served by the plainest syntax its consumers already recognise. What is not acceptable is mixing all three arbitrarily across one API — the inconsistency costs more than any of the individual choices.
- When does AIP allow a custom method to use GET instead of POST?Only when the operation is genuinely safe and has no side effects — a computed read such as a search or a rendered view. Anything that changes state must be POST, because GET is expected to be safe and may be issued by caches, crawlers, and prefetchers without user intent.
- If you dislike the colon syntax, what is the closest equivalent that keeps the intent?Model the action as a noun sub-resource and create it: POST /users/{id}/activation. You keep the action attached to the resource, get a natural home for its payload and history, and use only ordinary path characters. You give up the strict resource-name grammar that makes generic AIP tooling possible.
saying these in an interview costs you the question
- Saying colons are illegal in URL paths
- Treating custom methods as the default shape rather than a fallback
- Using GET for a colon method that changes state
- Assuming every proxy and client library handles a colon segment cleanly
- Mixing colon methods, verb sub-resources, and status PATCHes arbitrarily in one API