IPA-103: Methods
An API is composed of one or more methods, which represent a specific operation that a service can perform on behalf of the consumer.
Guidance
API authors should choose from the defined categories in the following order:
- Standard methods (on collections and resources)
- Custom methods (on collections, resources, or stateless)
paths:
/orders/{orderId}:
delete:
operationId: deleteOrderWhy:Cancelling an order is removal of a resource, so the standard
deletemethod covers it. A standard method is the first category that fits, so it is the one used.paths:
/orders/{orderId}:cancel:
post:
operationId: cancelOrderWhy:A custom
:cancelmethod is introduced for an operation that a standarddeletealready expresses. The custom method is chosen ahead of the standard one, reversing the intended order.Enumerate every operation under
pathsand pair it with the resource path it acts on.For each operation, determine the action it performs: create, read, list, update, delete, or something else.
When the action is a plain create/read/list/update/delete on a collection or resource, confirm it is expressed as the matching standard method rather than a custom method.
Report any custom method whose behavior a standard method on the same resource would already cover.
Standard methods must not cause side effects.
paths:
/projects/{projectId}:
patch:
operationId: updateProject
responses:
"200":
description: The updated project.Why:The
updatemethod changes only the project named in the path. No other resource is mutated as a consequence, so the standard method stays free of side effects.paths:
/projects/{projectId}:
patch:
operationId: updateProject
description: >-
Updates the project and also deactivates every team that belongs to it.Why:Updating one project mutates a different set of resources, the teams. A standard method that reaches beyond its target hides the second effect from anyone reading the contract.
List the standard methods in the spec (create, read, list, update, delete on collections and resources).
For each one, identify the target resource named in the path.
Inspect the implementation or the documented behavior to find every resource the operation mutates, not only the target.
Report any standard method that mutates a resource other than its target, since that is a side effect.
In scenarios where a side effect is necessary, a custom method should be used.
paths:
/projects/{projectId}:archive:
post:
operationId: archiveProject
description: >-
Archives the project and disables its teams.Why:The operation deliberately touches more than its target, so it is expressed as a custom method. The custom verb signals up front that the call carries an effect a plain update would not.
paths:
/projects/{projectId}:
patch:
operationId: updateProject
description: >-
Updates the project and disables its teams.Why:The same effect is folded into a standard
update. The required side effect is hidden behind a method that callers expect to be effect-free.Start from the operations flagged as carrying a necessary side effect by IPA-103-must-not-cause-side-effects.
For each, check whether it is modeled as a standard method or a custom method.
Report any that carry a deliberate side effect yet are still expressed as a standard method.
Depends onA side effect specifically includes mutating client-owned fields of any resource other than the target of the request. The dependent mutation must be performed through the dependent resource's own endpoint.
paths:
/projects/{projectId}:
patch:
operationId: updateProject
/teams/{teamId}:
patch:
operationId: updateTeamWhy:Changing a team's client-owned fields goes through the team's own
updateendpoint. Each resource owns the writes to its own fields.paths:
/projects/{projectId}:
patch:
operationId: updateProject
description: >-
Also rewrites the name field on each team in the project.Why:The project update writes client-owned fields on teams. Those writes belong to the team endpoint, so routing them through the project endpoint hides the mutation from anyone working with the team resource.
For each operation, identify the target resource named in its path.
From the implementation or documented behavior, list the client-owned fields the operation writes on any resource.
Flag any operation that writes client-owned fields on a resource other than its target.
Confirm that an endpoint owned by the dependent resource exists and that the mutation is routed through it instead.
Depends onIf the operation is fundamentally multi-resource by design, it must be modeled as a custom method.
paths:
/projects/{projectId}:transfer:
post:
operationId: transferProject
description: >-
Moves the project to another owner and reassigns its teams.Why:The operation touches several resources by design, so it is a custom method. The custom verb makes the multi-resource scope explicit.
paths:
/projects/{projectId}:
patch:
operationId: updateProject
description: >-
Moves the project to another owner and reassigns its teams.Why:A genuinely multi-resource operation is squeezed into a standard
update. The standard method advertises a single-resource change while doing much more.For each operation, determine from the implementation or documented behavior how many distinct resources it mutates.
Identify operations whose purpose inherently spans more than one resource.
Report any such operation that is modeled as a standard method rather than a custom method.
Depends onSide effects limited to read-only or effective values of another resource may occur in standard methods.
Standard methods must guarantee atomicity.
paths:
/orders/{orderId}:
patch:
operationId: updateOrder
description: >-
Applies all field changes together; a failure leaves the order
unchanged.Why:The update either lands in full or not at all. A partial result is never observable, which is what atomicity guarantees.
paths:
/orders/{orderId}:
patch:
operationId: updateOrder
description: >-
Updates each field in turn; a mid-way failure leaves some fields
changed.Why:A failure partway through leaves the order in a mixed state. The standard method exposes a half-applied result, which atomicity forbids.
List the standard methods that mutate state (create, update, delete).
For each, inspect the implementation or documented behavior to see whether a partial failure can leave the resource half-changed.
Report any mutating standard method that can produce an observable partial result. When atomicity cannot be guaranteed, the operation belongs in a sub-resource, a singleton resource, or a custom method instead.
If a standard method is unsuitable, then custom methods offer a lesser, but still valuable level of consistency, helping the user reason about the scope of the action and the object whose configuration is read to inform that action.
Selecting a custom method may be valuable for:
- State management of a resource since they usually carry side effects
- If atomic modifications are required when adding or removing from repeated fields
Response bodies
Every endpoint must support a versioned JSON content type (e.g.
application/vnd.atlas.YYYY-MM-DD+json), per IPA-900.paths:
/orders/{orderId}:
get:
operationId: getOrder
responses:
"200":
content:
application/vnd.example.2023-01-01+json:
schema:
$ref: "#/components/schemas/Order"Why:The response is offered under a dated, versioned JSON media type, so the payload shape can evolve under a new date without breaking existing callers.
paths:
/orders/{orderId}:
get:
operationId: getOrder
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/Order"Why:The response uses a bare, unversioned JSON media type. There is no version handle, so a later change to the shape cannot be rolled out without breaking callers pinned to the old shape.
For each operation under
paths, collect the media type keys declared under every response'scontent.For each operation, check that at least one media type is a versioned JSON type carrying a version token and ending in
+json.Report any operation whose responses offer no versioned JSON media type.
Additional content types (e.g.
+csv) may be offered alongside JSON.When a response body is returned as a JSON content type, it must be a JSON object with a fixed set of named properties at the root. Top-level arrays, primitives, or objects with dynamic (unknown) keys at the root are prohibited because they cannot be consistently typed by schema-based clients and tooling.
components:
schemas:
OrderList:
type: object
properties:
results:
type: array
items:
$ref: "#/components/schemas/Order"
totalCount:
type: integerWhy:The root is an object with named, declared properties. A schema-based client can generate one stable type for the response.
components:
schemas:
OrderList:
type: array
items:
$ref: "#/components/schemas/Order"Why:The root is a bare array. A top-level array leaves no place to add fields later and cannot be typed as a named object, so it is prohibited at the root.
For each operation under
paths, find the schema of every JSON response body, following any$ref.Confirm the root schema declares
type: objectwith a namedpropertiesmap.Flag any root schema that is an array, a primitive, or an object that declares only
additionalPropertieswith no named properties.
Collections must be wrapped in an envelope object per IPA-110 (e.g.
{"results": [...], "links": [...], "totalCount": 42}).paths:
/orders:
get:
operationId: listOrders
responses:
"200":
content:
application/json:
schema:
type: object
properties:
results:
type: array
items:
$ref: "#/components/schemas/Order"
totalCount:
type: integerWhy:The list response wraps the array in an envelope object that also carries pagination fields. The array sits under a named property, so the envelope can grow without changing the root type.
paths:
/orders:
get:
operationId: listOrders
responses:
"200":
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Order"Why:The list response returns the array directly. With no envelope there is nowhere to carry pagination links or a total count, and the root cannot be extended later.
Identify the operations that return a collection — typically
listoperations on a collection path.For each, inspect the JSON response schema and confirm the array is held under a named property of a root object rather than returned at the root.
Confirm the envelope carries the pagination fields required by IPA-110.
Report any collection response whose array is returned directly at the root.
Depends on
Naming
The method name is the
Operation ID
(operationId) in the OpenAPI Specification.
Operation IDs must be unique.
paths:
/orders:
get:
operationId: listOrders
/orders/{orderId}:
get:
operationId: getOrderWhy:Each operation carries a distinct
operationId, so generated SDKs produce one method per operation with no name collisions.paths:
/orders:
get:
operationId: getOrders
/orders/{orderId}:
get:
operationId: getOrdersWhy:Two operations share
getOrders. A duplicate id makes the mapping from operation to generated method ambiguous.Collect the
operationIdof every operation underpaths.Compare the values and find any that appear more than once.
Report each repeated
operationIdalong with the operations that share it.
Operation IDs must be in
camelCase.paths:
/orders/{orderId}:
get:
operationId: getOrderWhy:The
operationIdis camelCase: a lowercase first letter and no separators. SDK generators map it straight to an idiomatic method name.paths:
/orders/{orderId}:
get:
operationId: Get_OrderWhy:The
operationIduses an uppercase first letter and an underscore separator. It is neither camelCase nor a clean basis for a generated method name.For each operation under
paths, read itsoperationId.Check that the value starts with a lowercase letter and contains only letters and digits, with no spaces, underscores, or hyphens.
- Report any
operationIdthat is not camelCase.