From 1befa1f115e3fb2eb1e403707e7bb5f568b3408e Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Mon, 15 Jun 2026 13:24:14 +0100 Subject: [PATCH] feat(ipa): enrich IPA-104 Get with Guideline components CLOUDP-399898 --- ipa/general/0101.mdx | 10 +- ipa/general/0104.md | 56 ---- ipa/general/0104.mdx | 751 +++++++++++++++++++++++++++++++++++++++++++ ipa/general/0105.md | 2 +- ipa/general/0106.md | 2 +- ipa/general/0107.md | 4 +- ipa/general/0113.md | 4 +- ipa/general/0127.md | 2 +- ipa/general/0129.md | 2 +- 9 files changed, 764 insertions(+), 69 deletions(-) delete mode 100644 ipa/general/0104.md create mode 100644 ipa/general/0104.mdx diff --git a/ipa/general/0101.mdx b/ipa/general/0101.mdx index 7033239..3b34a00 100644 --- a/ipa/general/0101.mdx +++ b/ipa/general/0101.mdx @@ -57,7 +57,7 @@ resource. The methods can be: -- The standard methods ([Get](0104.md), [List](0105.md), [Create](0106.md), +- The standard methods ([Get](0104.mdx), [List](0105.md), [Create](0106.md), [Update](0107.md), [Delete](0108.md)) - [Custom methods](0109.md) @@ -72,7 +72,7 @@ standard methods: | Delete | None | None | | List | None | Are the resources | -- A resource **must** support at minimum [Get](0104.md) +- A resource **must** support at minimum [Get](0104.mdx) - Clients **must** be able to validate the state of resources after performing a mutation such as [Create](0106.md), [Update](0107.md), or [Delete](0108.md) @@ -86,7 +86,7 @@ standard methods: Read-only resources are resources that cannot be modified by API consumers. -- Read-only resources **must** have [Get](0104.md) and [List](0105.md) methods +- Read-only resources **must** have [Get](0104.mdx) and [List](0105.md) methods - Read-only resources **must not** have [Create](0106.md), [Update](0107.md), or [Delete](0108.md) methods - Read-only resources **may** have [custom methods](0109.md) as appropriate @@ -373,7 +373,7 @@ components: -A resource **must** support at minimum the [Get](0104.md) method. +A resource **must** support at minimum the [Get](0104.mdx) method. @@ -580,7 +580,7 @@ paths: effort="reason" > -Read-only resources **must** have [Get](0104.md) and [List](0105.md) methods. +Read-only resources **must** have [Get](0104.mdx) and [List](0105.md) methods. diff --git a/ipa/general/0104.md b/ipa/general/0104.md deleted file mode 100644 index 7bed3ac..0000000 --- a/ipa/general/0104.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -id: 104 -state: adopt ---- - -# IPA-104: Get - -In REST APIs, it is customary to make a `GET` request to a resource's URI (for -example, `/groups/{groupId}/clusters/{clusterName}`) to retrieve that resource. - -## Guidance - -- APIs **must** provide a Get method for resources -- The purpose of the Get method is to return data from a single resource -- The HTTP verb **must** be - [`GET`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET) -- The method **must not** [cause side effects](0103.mdx) -- The request **must not** include a body -- API producers **should** implement as a `Response` suffixed object - - A `Response` object **must not** include fields available only on creation - or update - - In OpenAPI, this means that the `Response` object **must not** include - fields with `writeOnly: true` -- The response status code **must** be - [200 OK](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200) -- The response **may** include a - [HATEOAS](https://en.wikipedia.org/wiki/HATEOAS) `links` field - -Example - -```http request -GET /groups/${groupId}/clusters/${clusterName} -``` - -### Naming - -- Operation ID **must** be unique -- Operation ID **must** be in `camelCase` -- Operation ID **must** start with the verb “get” -- Operation ID **should** be followed by a noun or compound noun - - The noun(s) in the Operation ID **should** be the collection identifiers - from the resource identifier in singular form - - If the resource is a [singleton](0113.md), the last noun **may** be the - plural form of the collection identifier - -Examples: - -| Resource Identifier | Operation ID | -| -------------------------------------------- | ------------------ | -| `/groups/${groupId}/clusters/${clusterName}` | `getGroupCluster` | -| (Singleton) `/groups/${groupId}/settings` | `getGroupSettings` | - -### Error Handling - -See [IPA-114: Errors](0114.md) for guidance on error handling and documentation, -in particular Authentication, Authorization and Not Found. diff --git a/ipa/general/0104.mdx b/ipa/general/0104.mdx new file mode 100644 index 0000000..9e4b562 --- /dev/null +++ b/ipa/general/0104.mdx @@ -0,0 +1,751 @@ +--- +id: 104 +state: adopt +--- + +# IPA-104: Get + +In REST APIs, it is customary to make a `GET` request to a resource's URI (for +example, `/groups/{groupId}/clusters/{clusterName}`) to retrieve that resource. + +## Guidance + +- APIs **must** provide a Get method for resources +- The purpose of the Get method is to return data from a single resource +- The HTTP verb **must** be + [`GET`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET) +- The method **must not** [cause side effects](0103.mdx) +- The request **must not** include a body +- API producers **should** implement as a `Response` suffixed object + - A `Response` object **must not** include fields available only on creation + or update + - In OpenAPI, this means that the `Response` object **must not** include + fields with `writeOnly: true` +- The response status code **must** be + [200 OK](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200) +- The response **may** include a + [HATEOAS](https://en.wikipedia.org/wiki/HATEOAS) `links` field + +Example + +```http request +GET /groups/${groupId}/clusters/${clusterName} +``` + +### Naming + +- Operation ID **must** be unique +- Operation ID **must** be in `camelCase` +- Operation ID **must** start with the verb “get” +- Operation ID **should** be followed by a noun or compound noun + - The noun(s) in the Operation ID **should** be the collection identifiers + from the resource identifier in singular form + - If the resource is a [singleton](0113.md), the last noun **may** be the + plural form of the collection identifier + +Examples: + +| Resource Identifier | Operation ID | +| -------------------------------------------- | ------------------ | +| `/groups/${groupId}/clusters/${clusterName}` | `getGroupCluster` | +| (Singleton) `/groups/${groupId}/settings` | `getGroupSettings` | + + + + + +APIs **must** provide a Get method for resources. + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + summary: Return One Cluster + operationId: getGroupCluster + responses: + "200": + description: OK +``` + + + The resource exposes a `GET` method so clients have a standard, side-effect + free way to retrieve its current representation. + + + + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + delete: + summary: Remove One Cluster + operationId: deleteGroupCluster + responses: + "204": + description: No Content +``` + + + The resource path supports `DELETE` but offers no way to read the resource, so + clients cannot retrieve its representation. + + + + + + + + +The HTTP verb used to retrieve a single resource **must** be `GET`. + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + summary: Return One Cluster + operationId: getGroupCluster + responses: + "200": + description: OK +``` + + + Retrieval uses the `GET` verb, which HTTP defines as safe and idempotent — + exactly the semantics expected for reading a resource. + + + + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + post: + summary: Fetch One Cluster + operationId: fetchGroupCluster + responses: + "200": + description: OK +``` + + + Using `POST` to read a resource breaks HTTP safety semantics and prevents + caching and proxy intermediaries from treating the call as a pure read. + + + + + + + Locate the operation intended to retrieve a single resource for the path. + + + Confirm the operation is declared under the `get` key of the path item, not + `post`, `put`, `patch`, or `delete`. + + + Flag any single-resource retrieval implemented with a verb other than `GET`. + + + + + + + +The Get method **must not** cause side effects; it is a safe, read-only +operation. + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + summary: Return One Cluster + operationId: getGroupCluster + responses: + "200": + description: OK +``` + + + The handler only reads and returns the cluster; repeated calls leave server + state unchanged. + + + + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + summary: Return One Cluster + operationId: getGroupCluster + description: Returns the cluster and resets its last-accessed timestamp. + responses: + "200": + description: OK +``` + + + Mutating the last-accessed timestamp as part of a read makes `GET` unsafe, so + clients and caches can no longer treat the call as a pure retrieval. + + + + + + + Identify the `GET` operation and the source-code handler that implements it. + + + Inspect the handler for writes: database inserts/updates/deletes, queued + jobs, external calls that mutate state, or counters incremented on read. + + + Confirm the operation declares no `requestBody` and performs no action that + changes resource state. + + + Report any state mutation as a side effect violating the safe-read contract. + + + + + + + +The Get method request **must not** include a body. + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + summary: Return One Cluster + operationId: getGroupCluster + parameters: + - name: groupId + in: path + required: true + schema: + type: string + responses: + "200": + description: OK +``` + + + All inputs are carried in the path; the operation declares no `requestBody`, + matching the read-only semantics of `GET`. + + + + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + summary: Return One Cluster + operationId: getGroupCluster + requestBody: + content: + application/json: + schema: + type: object + responses: + "200": + description: OK +``` + + + A request body on `GET` is undefined by HTTP for reads and is dropped by many + intermediaries, so any payload it carries cannot be relied upon. + + + + + + + + +API producers **should** implement the Get method response as a `Response` +suffixed object. + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + operationId: getGroupCluster + responses: + "200": + content: + application/vnd.atlas.2024-08-05+json: + schema: + $ref: "#/components/schemas/ClusterResponse" +``` + + + The response references a named, reusable `Response` suffixed schema, which + keeps the read shape distinct from request schemas and consistent across the + API. + + + + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + operationId: getGroupCluster + responses: + "200": + content: + application/vnd.atlas.2024-08-05+json: + schema: + type: object + properties: + name: + type: string +``` + + + An inline, unnamed schema cannot follow the `Response` suffix convention and + is not reusable, breaking the consistent read-model naming across resources. + + + + + + + + +The `Response` object **must not** include fields that are available only on +creation or update. + + + +```yaml +components: + schemas: + ClusterResponse: + type: object + properties: + name: + type: string + mongoDBVersion: + type: string + readOnly: true +``` + + + The read model exposes only fields a client can observe; creation/update-only + inputs such as one-time provisioning options are absent. + + + + + + +```yaml +components: + schemas: + ClusterResponse: + type: object + properties: + name: + type: string + rootPassword: + type: string +``` + + + `rootPassword` is supplied only when creating or updating the cluster; + surfacing it on a read implies it can be retrieved, which is misleading and + unsafe. + + + + + + + Resolve the schema referenced by the `GET` 2xx response. + + + For each property, determine whether it is meaningful only at creation or + update time (e.g., secrets, one-time provisioning inputs, write-only + credentials). + + + Compare against the Create/Update request schemas for the same resource to + identify input-only fields that leaked into the response. + + + Report any creation/update-only field present in the response object. + + + + + + + +In OpenAPI, the Get method `Response` object **must not** include fields marked +`writeOnly: true`. + + + +```yaml +components: + schemas: + ClusterResponse: + type: object + properties: + name: + type: string + mongoDBVersion: + type: string + readOnly: true +``` + + + No property is marked `writeOnly: true`, so every field in the response is one + a client is allowed to read. + + + + + + +```yaml +components: + schemas: + ClusterResponse: + type: object + properties: + name: + type: string + rootPassword: + type: string + writeOnly: true +``` + + + A `writeOnly: true` property is by definition input-only; including it in a + read response contradicts its own declaration. + + + + + + + + +The Get method response status code **must** be `200 OK`. + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + operationId: getGroupCluster + responses: + "200": + description: OK +``` + + + A successful read returns `200 OK`, the standard HTTP success code for + retrieving an existing resource representation. + + + + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + operationId: getGroupCluster + responses: + "201": + description: Created +``` + + + `201 Created` signals resource creation, not retrieval, so it misrepresents + what a Get method does and confuses clients relying on status semantics. + + + + + + + + +The Get method response **may** include a HATEOAS `links` field to advertise +related resources and navigation. + + + + + +The Get method Operation ID **must** be unique across the specification. + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + operationId: getGroupCluster + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}/processes: + get: + operationId: getGroupClusterProcess +``` + + + Each Get operation has a distinct `operationId`, so generated SDK method names + and tooling references never collide. + + + + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + operationId: getGroupCluster + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}/processes: + get: + operationId: getGroupCluster +``` + + + Two operations share `getGroupCluster`, which breaks code generators and any + client that resolves operations by ID. + + + + + + + Collect the `operationId` of every operation in the specification, not only + Get methods. + + + Check whether the Get method's `operationId` appears more than once across + that collection. + + + Report any duplicate `operationId` value as a uniqueness violation. + + + + + + + +The Get method Operation ID **must** be in `camelCase`. + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + operationId: getGroupCluster +``` + + + `camelCase` matches the convention SDK generators expect, producing idiomatic + method names across languages. + + + + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + operationId: get_group_cluster +``` + + + `snake_case` deviates from the API-wide `camelCase` convention and yields + non-idiomatic generated client code. + + + + + + + + +The Get method Operation ID **must** start with the verb `get`. + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + operationId: getGroupCluster +``` + + + The `get` prefix communicates the operation's intent and aligns the + `operationId` with its HTTP verb. + + + + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + operationId: fetchGroupCluster +``` + + + `fetch` is not the standardized retrieval verb; readers and tooling cannot + infer the operation type from the ID. + + + + + + + + +The Get method Operation ID **should** be followed by a noun or compound noun. + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + operationId: getGroupCluster +``` + + + The noun phrase `GroupCluster` names the resource being retrieved, so the ID + reads as a clear verb-plus-object phrase. + + + + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + operationId: getOne +``` + + + `getOne` carries no noun identifying the resource, leaving the operation's + target ambiguous. + + + + + + + + +The noun(s) in the Get method Operation ID **should** be the collection +identifiers from the resource identifier in singular form. + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + operationId: getGroupCluster +``` + + + The path's collection segments `groups` and `clusters` appear singularized as + `Group` and `Cluster`, so the ID maps directly onto the resource hierarchy. + + + + + + +```yaml +paths: + /api/atlas/v2/groups/{groupId}/clusters/{clusterName}: + get: + operationId: getGroupsClusters +``` + + + Plural `Groups`/`Clusters` reads like a list operation, obscuring that a + single resource is being retrieved. + + + + + + + + +If the resource is a singleton, the last noun in the Get method Operation ID +**may** be the plural form of the collection identifier (for example, +`getGroupSettings`). + + + + + +### Error Handling + +See [IPA-114: Errors](0114.md) for guidance on error handling and documentation, +in particular Authentication, Authorization and Not Found. diff --git a/ipa/general/0105.md b/ipa/general/0105.md index 92f67d4..f8b027c 100644 --- a/ipa/general/0105.md +++ b/ipa/general/0105.md @@ -19,7 +19,7 @@ which lives within that collection. - The method **must not** [cause side effects](0103.mdx) - The request **must not** include a body - The response body **should** consist of the same resource object returned by - the [Get](0104.md) method + the [Get](0104.mdx) method - The object **may** include any [HATEOAS](https://en.wikipedia.org/wiki/HATEOAS) `links` field from the individual resource diff --git a/ipa/general/0106.md b/ipa/general/0106.md index 6b373c1..9527088 100644 --- a/ipa/general/0106.md +++ b/ipa/general/0106.md @@ -25,7 +25,7 @@ collection. - In OpenAPI, this means that the `Request` object **must not** include fields with `readOnly: true` - The response body **should** be the same resource returned by the - [Get](0104.md) method + [Get](0104.mdx) method - Create operations **must not** accept query parameters - Query parameters are usually a sign of a side effect that standard methods **must not** cause diff --git a/ipa/general/0107.md b/ipa/general/0107.md index b519eb6..8061b2f 100644 --- a/ipa/general/0107.md +++ b/ipa/general/0107.md @@ -28,13 +28,13 @@ resource. - `PUT` is strongly discouraged because it becomes a backward-incompatible change to add fields to the resource - The request body **must** contain the resource being updated, i.e. the - resource or parts of the resource returned by the [Get method](0104.md) + resource or parts of the resource returned by the [Get method](0104.mdx) - API producers **should** implement as a `UpdateRequest` suffixed object - A `UpdateRequest` object **must** include only input fields - In OpenAPI, this means that the `UpdateRequest` object **must not** include fields with `readOnly: true` - The response body **should** be the same resource returned by the - [Get method](0104.md) + [Get method](0104.mdx) - The Update method **should** return the complete resource to avoid complexities for clients - The Update method **must** respect the client provided values, or lack diff --git a/ipa/general/0113.md b/ipa/general/0113.md index 1e3d244..35f62b6 100644 --- a/ipa/general/0113.md +++ b/ipa/general/0113.md @@ -16,7 +16,7 @@ parent. [Delete](0108.md) standard methods - The singleton is implicitly created or deleted when its parent is created or deleted -- Singleton resources **must** define the [Get](0104.md) method +- Singleton resources **must** define the [Get](0104.mdx) method - Singleton resources **should** define the [Update](0107.md) method, unless the resource is [read-only](0113.md#read-only-singleton-resources) - Singleton resources **may** define [custom methods](0109.md) as appropriate @@ -34,7 +34,7 @@ PATCH /groups/${groupId}/settings Read-only singleton resources are [singleton resources](0113.md) that cannot be modified by API consumers. -- Read-only singleton resources **must** have only the [Get](0104.md) method +- Read-only singleton resources **must** have only the [Get](0104.mdx) method - Read-only singleton resources **must not** have [Create](0106.md), [Update](0107.md), or [Delete](0108.md) methods - Read-only singleton resources **may** have [custom methods](0109.md) as diff --git a/ipa/general/0127.md b/ipa/general/0127.md index 49a304f..b87042d 100644 --- a/ipa/general/0127.md +++ b/ipa/general/0127.md @@ -56,7 +56,7 @@ error-prone development. ### Further Reading - [IPA-101: Resource-Oriented Design](0101.mdx) -- [IPA-104: Get](0104.md) +- [IPA-104: Get](0104.mdx) - [IPA-105: List](0105.md) - [IPA-106: Create](0106.md) - [IPA-108: Delete](0108.md) diff --git a/ipa/general/0129.md b/ipa/general/0129.md index 866b1c0..7cc1ce7 100644 --- a/ipa/general/0129.md +++ b/ipa/general/0129.md @@ -76,7 +76,7 @@ values. - [List Methods](0105.md) - [Custom Methods](0109.md) used for retrieving data - Filtering and searching **must not** be implemented for - - [Get Methods](0104.md) + - [Get Methods](0104.mdx) - [Create Methods](0106.md) - [Update Methods](0107.md) - [Delete Methods](0108.md)