Skip to main content
Adopt

IPA-106: Create

In REST APIs, it is customary to make a POST request to a collection's URI (for example, /groups/{groupId}/clusters) to create a new resource within that collection.

Guidance

  1. APIs should provide a create method for resources unless it is not valuable for users to do so

    paths:
    /groups/{groupId}/clusters:
    post:
    operationId: createGroupCluster
    responses:
    "201":
    description: The created cluster.
    content:
    application/json:
    schema:
    $ref: "#/components/schemas/Cluster"
    Why:

    The clusters collection lets users create new clusters, so it exposes a Create method via POST on the collection URI.

    1. For each resource collection in the spec, determine whether users need to create new resources within it.

    2. Confirm the resource is neither read-only nor a singleton — both must not have a Create method.

    3. If creating a resource is valuable for users, confirm the collection exposes a POST create method. Flag collections that omit it without a clear reason.

  2. The HTTP verb must be POST

    paths:
    /groups/{groupId}/clusters:
    post:
    operationId: createGroupCluster
    responses:
    "201":
    description: The created cluster.
    Why:

    The create operation uses POST on the collection URI, the HTTP verb defined for creating a new resource within a collection.

  3. The resource must be the request body

    • API producers should implement as a Request suffixed object
      • A Request object must include only input fields
        • In OpenAPI, this means that the Request object must not include fields with readOnly: true
    paths:
    /groups/{groupId}/clusters:
    post:
    operationId: createGroupCluster
    requestBody:
    content:
    application/json:
    schema:
    $ref: "#/components/schemas/ClusterRequest"
    components:
    schemas:
    ClusterRequest:
    type: object
    properties:
    name:
    type: string
    instanceSize:
    type: string
    Why:

    The request body is the resource, modeled as a Request-suffixed object that carries only input fields and omits server-owned readOnly fields.

  4. The response body must be the same resource returned by the Get method

    paths:
    /groups/{groupId}/clusters:
    post:
    operationId: createGroupCluster
    responses:
    "201":
    content:
    application/json:
    schema:
    $ref: "#/components/schemas/Cluster"
    /groups/{groupId}/clusters/{clusterId}:
    get:
    operationId: getGroupCluster
    responses:
    "200":
    content:
    application/json:
    schema:
    $ref: "#/components/schemas/Cluster"
    Why:

    Create and Get both return #/components/schemas/Cluster, so the resource a client receives on creation matches what it reads back later.

    paths:
    /groups/{groupId}/clusters:
    post:
    operationId: createGroupCluster
    responses:
    "201":
    content:
    application/json:
    schema:
    $ref: "#/components/schemas/ClusterCreateResult"
    /groups/{groupId}/clusters/{clusterId}:
    get:
    operationId: getGroupCluster
    responses:
    "200":
    content:
    application/json:
    schema:
    $ref: "#/components/schemas/Cluster"
    Why:

    Create returns ClusterCreateResult while Get returns Cluster. The client cannot rely on the create response to reflect the resource it will later read, so it must issue a follow-up Get to learn the resource's true shape.

    1. For the create operation, find the response body schema for 201.

    2. Find the response body schema for the resource's Get method.

    3. Flag any case where the two schemas differ; the create response must return the same resource as Get.

  5. Create operations must not accept query parameters

    • Query parameters are usually a sign of a side effect that standard methods must not cause
    paths:
    /groups/{groupId}/clusters:
    post:
    operationId: createGroupCluster
    parameters:
    - name: groupId
    in: path
    required: true
    schema:
    type: string
    responses:
    "201":
    description: The created cluster.
    Why:

    The only parameter is the groupId path parameter; there are no query parameters that would signal a side effect on a standard method.

  6. The response status code must be 201 Created

    paths:
    /groups/{groupId}/clusters:
    post:
    operationId: createGroupCluster
    responses:
    "201":
    description: The created cluster.
    Why:

    The create operation defines a 201 response, the status code for a successfully created resource.

Example

POST /groups/${groupId}/clusters

Error Handling

See IPA-114: Errors for guidance on error handling and documentation.

Naming

  1. Operation ID must be unique

    paths:
    /groups/{groupId}/clusters:
    post:
    operationId: createGroupCluster
    Why:

    createGroupCluster is not reused by any other operation, so each operation in the spec has a distinct identifier.

  2. Operation ID must be in camelCase

    paths:
    /groups/{groupId}/clusters:
    post:
    operationId: createGroupCluster
    Why:

    createGroupCluster is camelCase: lowercase first word, each subsequent word capitalized, no separators.

  3. Operation ID must start with the verb "create"

    paths:
    /groups/{groupId}/clusters:
    post:
    operationId: createGroupCluster
    Why:

    The operation ID begins with the verb create, identifying it as a create method.

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

    paths:
    /groups/{groupId}/clusters:
    post:
    operationId: createGroupCluster
    Why:

    The verb create is followed by the compound noun GroupCluster, naming the resource being created.

  5. The noun(s) in the Operation ID should be the collection identifiers from the resource identifier in singular form

    paths:
    /groups/{groupId}/clusters:
    post:
    operationId: createGroupCluster
    Why:

    The resource identifier /groups/${groupId}/clusters has collection identifiers groups and clusters; the operation ID uses their singular forms, Group and Cluster.

Examples:

Resource IdentifierOperation ID
/groups/${groupId}/clusterscreateGroupCluster