Skip to main content
Adopt

IPA-109: Custom Methods

Resource-oriented design uses custom methods to provide a means to express arbitrary actions that are difficult to model using only the standard methods.

Guidance

  1. Custom methods should only be used for functionality that cannot be easily expressed via standard methods

    • Prefer standard methods if possible, due to their consistent semantics
    paths:
    /groups/{groupId}/clusters/{clusterName}:pause:
    post:
    operationId: pauseGroupCluster
    summary: Pause a cluster
    parameters:
    - name: groupId
    in: path
    required: true
    schema:
    type: string
    - name: clusterName
    in: path
    required: true
    schema:
    type: string
    responses:
    "200":
    description: The paused cluster.
    Why:

    Pausing a cluster is a state transition with side effects, not a field edit or a read. No standard method captures it, so a custom :pause is justified.

    paths:
    /groups/{groupId}/clusters/{clusterName}:setName:
    post:
    operationId: setGroupClusterName
    summary: Set the name of a cluster
    parameters:
    - name: groupId
    in: path
    required: true
    schema:
    type: string
    - name: clusterName
    in: path
    required: true
    schema:
    type: string
    requestBody:
    content:
    application/json:
    schema:
    type: object
    properties:
    name: { type: string }
    responses:
    "200":
    description: The updated cluster.
    Why:

    Setting a field is a partial update of an existing resource, which the standard Update method already covers. A custom :setName verb provides none of Update's consistent semantics and tooling that knows the standard methods can't see what the call does.

    1. Identify the custom method by its :verb suffix in the path (e.g. /groups/ {groupId}/clusters/{clusterName}:pause).

    2. Read its summary, request body, and response to work out what state it reads or changes, and on which resource.

    3. Ask whether that intent maps onto a standard method: retrieving one resource (Get), retrieving a collection (List), creating a resource (Create), modifying an existing resource's fields (Update), or removing a resource (Delete).

    4. If the intent fits a standard method, flag it — the standard method should be used instead. The custom method is fine only when no standard method captures the behavior.

  2. The name of the method should be a verb and may be followed by a noun

    paths:
    /groups/{groupId}/clusters/{clusterName}:pause:
    post:
    operationId: pauseGroupCluster
    /groups/{groupId}/clusters/{clusterName}:addNode:
    post:
    operationId: addGroupClusterNode
    Why:

    pause is a bare verb; addNode is a verb followed by a noun. Both name an action, which is what a custom method represents.

    1. Read the custom method name from the path section after the colon (:).

    2. Confirm the name begins with a verb describing the action performed.

    3. Flag any custom method whose name is not a verb (for example a bare noun or adjective).

  3. The HTTP method must be GET or POST:

    • GET must be used for methods retrieving data or resource state.
    • POST must be used if the method has side effects or mutates resources or data
    paths:
    /groups/{groupId}/clusters:search:
    get:
    operationId: searchGroupClusters
    summary: Search clusters
    /groups/{groupId}/clusters/{clusterName}:pause:
    post:
    operationId: pauseGroupCluster
    summary: Pause a cluster
    Why:

    :search only reads data, so it uses GET. :pause mutates the cluster's state, so it uses POST. The HTTP method matches whether the call reads or changes state.

    paths:
    /groups/{groupId}/clusters/{clusterName}:pause:
    put:
    operationId: pauseGroupCluster
    summary: Pause a cluster
    Why:

    A custom method must use GET or POST. :pause has side effects, so it must use POST; PUT is not a permitted HTTP method for a custom method.

  4. Custom methods using the GET HTTP method must return a 200 OK response.

    paths:
    /groups/{groupId}/clusters:search:
    get:
    operationId: searchGroupClusters
    summary: Search clusters
    responses:
    "200":
    description: The matching clusters.
    Why:

    The GET custom method :search retrieves data and documents a 200 OK response, the expected success status for a read.

    paths:
    /groups/{groupId}/clusters:search:
    get:
    operationId: searchGroupClusters
    summary: Search clusters
    responses:
    "204":
    description: No content.
    Why:

    A GET custom method retrieves data, so it must return 200 OK. A 204 No Content advertises that the read produces no body, which contradicts the purpose of the method.

  5. The HTTP URI must use a colon(:) character followed by the custom method name

    • This aims to clearly distinguish between custom methods and other resources
    • The custom method name must be written in camelCase
    paths:
    /groups/{groupId}/clusters/{clusterName}:addNode:
    post:
    operationId: addGroupClusterNode
    Why:

    The custom method is appended to the resource identifier with a colon, and addNode is camelCase. The colon clearly separates the custom method from the resources in the path.

    paths:
    /groups/{groupId}/clusters/{clusterName}/add-node:
    post:
    operationId: addGroupClusterNode
    Why:

    add-node is appended as a path segment rather than after a colon, so it reads as another resource instead of a custom method, and add-node is not camelCase.

  6. See Declarative-friendly resources for further guidance

Example

POST /groups/${groupId}/clusters/${clusterName}:pause
GET /groups/${groupId}/clusters:search
POST /groups/${groupId}/clusters/${clusterName}:addNode
POST /groups/${groupId}/clusters/${clusterName}:removeNode

Naming

  1. Operation ID must be unique

    paths:
    /groups/{groupId}/clusters/{clusterName}:pause:
    post:
    operationId: pauseGroupCluster
    /groups/{groupId}/clusters/{clusterName}:addNode:
    post:
    operationId: addGroupClusterNode
    Why:

    Each operation has its own distinct operationId. Unique operation IDs let generated clients expose one unambiguous method per operation.

    paths:
    /groups/{groupId}/clusters/{clusterName}:pause:
    post:
    operationId: clusterAction
    /groups/{groupId}/clusters/{clusterName}:resume:
    post:
    operationId: clusterAction
    Why:

    Two operations share the operationId clusterAction. A duplicate operation ID collides in generated code, where one method name would have to stand for two different operations.

  2. Operation ID must be in camelCase

    paths:
    /groups/{groupId}/clusters/{clusterName}:pause:
    post:
    operationId: pauseGroupCluster
    Why:

    pauseGroupCluster is camelCase, matching the convention used for operation IDs across the API.

    paths:
    /groups/{groupId}/clusters/{clusterName}:pause:
    post:
    operationId: pause_group_cluster
    Why:

    pause_group_cluster is snake_case, not camelCase, breaking the operation ID naming convention.

  3. Operation ID must start with the custom method verb

    • Derived from the path section delimited by the colon (:) character
    paths:
    /groups/{groupId}/clusters/{clusterName}:pause:
    post:
    operationId: pauseGroupCluster
    Why:

    The custom method verb is pause (the path section after the colon), and the operation ID pauseGroupCluster starts with it.

    paths:
    /groups/{groupId}/clusters/{clusterName}:pause:
    post:
    operationId: groupClusterPause
    Why:

    The verb pause from the path is buried at the end of groupClusterPause rather than leading it. The operation ID must start with the custom method verb.

    1. Take the path section after the colon (:) — this is the custom method verb (for example, pause in :pause).

    2. Confirm the operationId begins with that verb.

    3. Flag any operation ID that does not start with the custom method verb.

  4. Operation ID should be followed by a noun or compound nouns

    paths:
    /groups/{groupId}/clusters/{clusterName}:pause:
    post:
    operationId: pauseGroupCluster
    Why:

    After the verb pause, the operation ID continues with the nouns GroupCluster, naming what the action applies to.

    1. Strip the leading verb from the operation ID.
    2. Confirm what remains is a noun or compound nouns describing the target of the action.

    3. Flag an operation ID that is a bare verb with no following noun.

  5. The noun(s) in the Operation ID should be

    • The collection identifiers from the resource identifier in singular form
    • The custom method noun(s)
      • Derived from the path section delimited by the colon (:) character
    paths:
    /groups/{groupId}/clusters/{clusterName}:addNode:
    post:
    operationId: addGroupClusterNode
    Why:

    The nouns in addGroupClusterNode are the singular collection identifiers from the path — groupsGroup, clustersCluster — followed by the custom method noun Node from :addNode.

    1. List the collection identifiers in the resource identifier (for example groups and clusters) and put each in singular form.

    2. Take any noun(s) from the custom method name in the path section after the colon (:).

    3. Confirm the operation ID's nouns are composed of the singular collection identifiers followed by the custom method noun(s).

    4. Flag an operation ID whose nouns do not derive from the resource identifier and the custom method name.

Resource IdentifierOperation ID
/groups/${groupId}/clusters/${clusterName}:pausepauseGroupCluster
/groups/${groupId}/clusters/${clusterName}:addNodeaddGroupClusterNode
/groups/${groupId}/clusters:searchsearchGroupClusters

Declarative-friendly resources

  1. Declarative-friendly resources should not use custom methods. To learn more, see IPA-127.

    • Custom methods require manual curation, implementation, and review for API tooling, which increases feature latency.
    • Declarative-friendly tools are unable to automatically determine what to do with them
    1. Determine whether the resource is declarative-friendly (see IPA-127).

    2. Look for custom methods (paths with a :verb suffix) on that resource.

    3. Flag any custom method on a declarative-friendly resource, since declarative tooling cannot automatically determine what to do with it.

tip

State transitions that carry side effects are usually good candidates for custom methods