The CRUD (Create, Read, Update, Delete) pattern is often the first interaction style developers learn.

While simple and powerful, CRUD is frequently misapplied to domains that require more expressiveness (e.g., workflows, state transitions, business actions).

This section clarifies when CRUD is appropriate and how to design consistent, resource-oriented CRUD APIs aligned with governance expectations.

4.1. Overview

CRUD is a pattern for managing simple, data-centric resources where the primary interactions are creating new records, retrieving them, modifying them, and deleting them.

Key characteristics:

  • Entity-focused: CRUD works best when modeling information that behaves like stored records.
  • State-agnostic: CRUD implies no formal lifecycle beyond basic creation and modification.
  • Uniform semantics: CRUD uses standard HTTP verbs consistently across resources.
  • Stable structure: CRUD endpoints rarely change unless the resource schema evolves.

CRUD excels in systems where operations have minimal business logic and primarily manipulate data.

4.2. When to Use CRUD

Use CRUD when the resource represents a simple, stable entity and the domain’s interactions can be expressed through basic data modifications.

Use cases include:

  • Reference data (countries, currencies, categories, settings)
  • Basic records (contacts, profiles, accounts, stores, locations)
  • Simple configuration objects
  • Resources with no notable workflow or state transitions
  • Domain objects whose rules are enforced via validation, not workflow

CRUD is ideal when:

  • The consumer expects predictable, consistent operations.
  • The resource is primarily a bag of attributes with simple validation.
  • Side-effects are minimal or non-existent.
  • Multiple clients can safely perform basic operations without domain conflicts.

4.3. When NOT to Use CRUD

Avoid CRUD when operations imply business intent, workflow steps, or state transitions.

Signs CRUD is the wrong pattern:

  • “PATCH /order/123” actually means “ship order.”
  • “PATCH /loan/456” actually triggers a risk review.
  • “DELETE /user/789” actually disables an account with downstream effects.
  • Resource fields are used as a “command transport system.”

CRUD should NOT be used when the resource:

  • Has a defined lifecycle (draft → submitted → approved → published)
  • Requires stepwise progression or domain-specific transitions
  • Triggers significant side effects (notifications, workflows, system integrations)
  • Needs auditability of specific actions, not generic updates
  • Involves approval, rejection, confirmation, or business decisions
  • Will evolve into a workflow later — better to model the workflow explicitly now

In these cases, use Extended CRUD or Functional Resource (Commands) instead.

4.4. What CRUD Looks Like (URI Structure, Verbs, Status Codes)

CRUD uses a consistent and predictable structure based on REST resource semantics.

Standard CRUD Endpoint Set

Operation HTTP Verb URI Pattern Description
Create POST /resources Creates a new item.
Read (collection) GET /resources Returns a list of items.
Read (item) GET /resources/{id} Returns one item.
Update PUT or PATCH /resources/{id} Updates all or part of an item.
Delete DELETE /resources/{id} Removes an item.

Best Practices for CRUD URI/Verb Design

  • Use plural nouns for collections: /books, /orders, /customers.
  • Use globally unique identifiers: /orders/{orderId}.
  • Use PUT for full replacements; PATCH for partial updates.
  • DELETE should be idempotent — repeated calls should be safe.
  • POST should return 201 + Location header when creating new items.
  • Avoid including verbs in the URI (e.g., /createUser, /update-profile).
  • Response bodies should follow your API platform’s response envelope and error model (Problem Details).

Typical Status Codes

  • 201 Created — Successful resource creation
  • 200 OK — Successful read or update
  • 204 No Content — Successful delete
  • 400 Bad Request — Validation errors
  • 404 Not Found — Resource not found
  • 409 Conflict — Duplicate resource or state conflict

4.5. Anti-Patterns to Avoid

CRUD misuse is one of the most common governance issues in enterprise platforms. Typical anti-patterns include:

1. Overloading CRUD for business workflows

Using CRUD semantics to trigger domain actions:

  • PATCH /invoice/123 { status: "PAID" }
  • PATCH /shipment/567 { status: "DELIVERED" }

These obscure intent, weaken authorization boundaries, and break auditability.

2. “Field-driven commands”

Putting commands in the payload instead of the API structure:

{ "action": "approve" }

This is effectively reimplementing commands inside CRUD and should be refactored into Extended CRUD or Functional Resources.

3. Bloated resource representations

Trying to capture too many concepts in one object, resulting in:

  • Entities with dozens of optional fields
  • Overloaded PATCH logic
  • Tight coupling to backend data models

4. CRUDifying complex domains

When a domain has processes, steps, or roles, CRUD can’t represent:

  • What’s allowed
  • What’s next
  • Who can do what
  • How state transitions are governed

Use the right pattern for the job.

4.6. OpenAPI Example

Below is a canonical CRUD example demonstrating collection and item operations.

openapi: 3.0.3
info:
  title: Books API - CRUD Pattern Example
  version: 1.0.0
servers:
  - url: https://api.example.com

paths:
  /books:
    get:
      summary: List books
      tags: [Books]
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Book'
              examples:
                default:
                  value:
                    - id: bk_12345
                      title: "Domain-Driven Design"
                      author: "Eric Evans"
                      isbn: "978-0321125217"
                      publishedDate: "2003-08-30"
                      status: "PUBLISHED"
                    - id: bk_67890
                      title: "Implementing Domain-Driven Design"
                      author: "Vaughn Vernon"
                      isbn: "978-0321834577"
                      publishedDate: "2013-02-13"
                      status: "PUBLISHED"
    post:
      summary: Create a new book
      tags: [Books]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BookCreateRequest'
            examples:
              default:
                value:
                  title: "Patterns of Enterprise Application Architecture"
                  author: "Martin Fowler"
                  isbn: "978-0321127426"
                  publishedDate: "2002-11-15"
      responses:
        '201':
          description: Created
          headers:
            Location:
              schema:
                type: string
                example: https://api.example.com/books/bk_24680
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Book'
              examples:
                default:
                  value:
                    id: bk_24680
                    title: "Patterns of Enterprise Application Architecture"
                    author: "Martin Fowler"
                    isbn: "978-0321127426"
                    publishedDate: "2002-11-15"
                    status: "DRAFT"

  /books/{bookId}:
    get:
      summary: Get a book by ID
      tags: [Books]
      parameters:
        - in: path
          name: bookId
          required: true
          schema:
            type: string
            example: bk_12345
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Book'
              examples:
                default:
                  value:
                    id: bk_12345
                    title: "Domain-Driven Design"
                    author: "Eric Evans"
                    isbn: "978-0321125217"
                    publishedDate: "2003-08-30"
                    status: "PUBLISHED"
        '404':
          description: Not Found
    patch:
      summary: Update a book
      tags: [Books]
      parameters:
        - in: path
          name: bookId
          required: true
          schema:
            type: string
            example: bk_12345
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BookUpdateRequest'
            examples:
              default:
                value:
                  title: "Domain-Driven Design (Anniversary Edition)"
                  status: "PUBLISHED"
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Book'
              examples:
                default:
                  value:
                    id: bk_12345
                    title: "Domain-Driven Design (Anniversary Edition)"
                    author: "Eric Evans"
                    isbn: "978-0321125217"
                    publishedDate: "2003-08-30"
                    status: "PUBLISHED"
        '404':
          description: Not Found
    delete:
      summary: Delete a book
      tags: [Books]
      parameters:
        - in: path
          name: bookId
          required: true
          schema:
            type: string
            example: bk_12345
      responses:
        '204':
          description: No Content
        '404':
          description: Not Found

components:
  schemas:
    Book:
      type: object
      properties:
        id:
          type: string
          example: bk_12345
        title:
          type: string
          example: "Domain-Driven Design"
        author:
          type: string
          example: "Eric Evans"
        isbn:
          type: string
          example: "978-0321125217"
        publishedDate:
          type: string
          format: date
          example: "2003-08-30"
        status:
          type: string
          enum: [DRAFT, PUBLISHED, ARCHIVED]
          example: PUBLISHED
      required:
        - id
        - title
        - author
        - isbn
        - status

    BookCreateRequest:
      type: object
      properties:
        title:
          type: string
          example: "Patterns of Enterprise Application Architecture"
        author:
          type: string
          example: "Martin Fowler"
        isbn:
          type: string
          example: "978-0321127426"
        publishedDate:
          type: string
          format: date
          example: "2002-11-15"
      required:
        - title
        - author
        - isbn

    BookUpdateRequest:
      type: object
      properties:
        title:
          type: string
          example: "Domain-Driven Design (Anniversary Edition)"
        author:
          type: string
          example: "Eric Evans"
        isbn:
          type: string
          example: "978-0321125217"
        publishedDate:
          type: string
          format: date
          example: "2003-08-30"
        status:
          type: string
          enum: [DRAFT, PUBLISHED, ARCHIVED]
          example: PUBLISHED

4.7. Visualizing the CRUD Pattern (Mermaid)

The following Mermaid diagram shows how a client interacts with a typical CRUD-style Books API, and how those calls map to data store operations. This helps learners connect the HTTP surface to the underlying resource lifecycle.

sequenceDiagram
    autonumber
    participant C as Client
    participant API as Books API
    participant DB as Data Store

    Note over C,API: Read (List)
    C->>API: GET /books
    API->>DB: SELECT * FROM books
    DB-->>API: [Book...]
    API-->>C: 200 OK<br/>[Book[]]

    Note over C,API: Create
    C->>API: POST /books<br/>{BookCreateRequest}
    API->>DB: INSERT INTO books (...)
    DB-->>API: new row (id = bk_24680)
    API-->>C: 201 Created<br/>Location: /books/bk_24680<br/>[Book]

    Note over C,API: Read (Single)
    C->>API: GET /books/bk_24680
    API->>DB: SELECT * FROM books WHERE id = 'bk_24680'
    DB-->>API: Book row
    API-->>C: 200 OK<br/>[Book]

    Note over C,API: Update (Partial)
    C->>API: PATCH /books/bk_24680<br/>{BookUpdateRequest}
    API->>DB: UPDATE books SET ... WHERE id = 'bk_24680'
    DB-->>API: updated row
    API-->>C: 200 OK<br/>[Book]

    Note over C,API: Delete
    C->>API: DELETE /books/bk_24680
    API->>DB: DELETE FROM books WHERE id = 'bk_24680'
    DB-->>API: success
    API-->>C: 204 No Content