WEB API's Lesson 13 – CRUD Operations | Dataplexa
Web APIs · Lesson 13

CRUD Operations

Map database operations to HTTP methods and build the four core API endpoints every application needs.
GitHub handles over 100 million repositories through just four types of operations. Create a repo, read its contents, update the README, delete a branch. That is CRUD in action — the foundation that powers every data-driven API on the internet.

CRUD stands for Create, Read, Update, Delete. These four operations represent everything you can do with data in any system. When you post a photo to Instagram, that is Create. When you scroll through your feed, that is Read. When you edit your bio, that is Update. When you remove an old post, that is Delete.

The genius of REST architecture is how it maps these universal data operations to HTTP methods. POST creates new resources. GET reads existing ones. PUT and PATCH update resources in different ways. DELETE removes resources entirely.

But here is where most developers stumble. They think CRUD means just copying database operations into API endpoints. Wrong approach. CRUD in APIs is about designing intuitive interfaces that make sense to client applications, not exposing your database schema to the world.

Real-World Impact
Stripe processes billions in payments through clean CRUD operations. Their API lets you create charges, read payment history, update customer details, and delete saved cards. Each operation maps perfectly to business needs, not database tables.

Understanding CRUD Fundamentals

Every piece of data in your application follows a lifecycle. Resources get created when users sign up or upload content. They get read when other users browse or search. They get updated as information changes or users edit their content. Eventually, some resources get deleted when they are no longer needed.

This lifecycle maps naturally to HTTP methods, but the mapping is not always obvious. Consider a user profile. Creating a profile uses POST, reading it uses GET, updating the email address uses PATCH. But what about deactivating an account? Some APIs use DELETE, others use PATCH to update a status field.

The key insight is that CRUD operations should match how clients think about resources, not how your database stores them. A client wants to "create a new project" or "update this task description." They should not need to think about foreign keys, junction tables, or database constraints.

Concept
Resource Lifecycle
Data Management
RFC 7231
Production Ready
CRUD operations provide the standard interface for all data manipulation in REST APIs. Each operation has specific HTTP method mappings, expected behaviors, and appropriate response codes that clients depend on for reliable integration.

The Four Core Operations

Create operations bring new resources into existence. When Slack creates a new workspace, Shopify adds a product to your store, or Twitter posts a new tweet, they are performing Create operations. These always use POST method because you are asking the server to process new data and assign it an identifier.

Read operations retrieve existing resources without changing them. Every time you load a GitHub repository, check your bank balance through an app, or browse Netflix recommendations, you are triggering Read operations. GET method handles all reading, from single resources to filtered lists.

Update operations modify existing resources. But here is where it gets interesting — REST provides two different update approaches. PUT replaces the entire resource with new data. PATCH applies partial changes to specific fields. The choice between them depends on how much control you want to give clients.

Delete operations remove resources from the system. When you delete a photo from Google Photos, remove a contact from your phone, or cancel a subscription, the API performs a Delete operation. DELETE method signals permanent removal, though the actual implementation might just mark records as inactive.

Operation HTTP Method Purpose Example
Create POST Add new resource POST /api/projects
Read GET Retrieve existing resource GET /api/projects/123
Update PUT/PATCH Modify existing resource PATCH /api/projects/123
Delete DELETE Remove resource DELETE /api/projects/123

Create Operations (POST)

Creating resources is where most APIs start getting complex. The operation seems simple — accept some data, validate it, store it, return the created resource. But production systems need to handle duplicate submissions, validate business rules, trigger side effects, and maintain data consistency.

POST requests carry the new resource data in the request body. Unlike GET requests that put everything in the URL, POST can handle large payloads with complex nested data structures. This makes POST perfect for creating resources with multiple fields, uploaded files, or related data.

The response to a successful Create operation should return HTTP status 201 Created, not 200 OK. Status 201 specifically indicates that a new resource was created, and clients often rely on this distinction. The response should include the full created resource with any server-generated fields like ID, timestamps, or computed values.

Location Header Pattern
Best practice is to include a Location header in 201 responses pointing to the newly created resource. This gives clients the exact URL to fetch the resource later: Location: /api/projects/456

Validation happens at multiple levels during Create operations. Input validation checks data types, required fields, and format constraints. Business validation enforces domain rules like unique usernames or valid date ranges. Some validation requires database queries to check references or uniqueness constraints.

Error responses for failed Create operations typically return 400 Bad Request with detailed validation errors. The response body should explain exactly what went wrong and how to fix it. Generic error messages frustrate developers and slow down integration.

# APIForge Backend team creating a new developer project
POST /api/v1/projects HTTP/1.1
Host: api.apiforge.dev
Content-Type: application/json
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

{
  "name": "Mobile Payment Gateway",
  "description": "Secure payment processing for mobile apps",
  "tech_stack": ["Node.js", "PostgreSQL", "Redis"],
  "team_size": 4,
  "deadline": "2024-06-15",
  "priority": "high"
}
HTTP/1.1 201 Created Content-Type: application/json Location: /api/v1/projects/proj_7x9k2m8n4p1q X-RateLimit-Remaining: 4999 { "id": "proj_7x9k2m8n4p1q", "name": "Mobile Payment Gateway", "description": "Secure payment processing for mobile apps", "tech_stack": ["Node.js", "PostgreSQL", "Redis"], "team_size": 4, "deadline": "2024-06-15T00:00:00Z", "priority": "high", "status": "planning", "created_at": "2024-02-15T14:30:22Z", "updated_at": "2024-02-15T14:30:22Z", "created_by": "user_dev_sarah_chen" }
What just happened?
The API accepted the project data, validated all fields, generated a unique project ID, set default values like status and timestamps, then returned the complete created resource with 201 status. The Location header tells clients where to find this new project. Try this: Always return the full created resource so clients do not need a separate GET request to see server-generated fields.

Read Operations (GET)

Reading data is the most frequent operation in most APIs. Every page load, every refresh, every search triggers Read operations. GET requests should be fast, cacheable, and predictable because they form the backbone of user experience.

GET operations never modify server state. This property, called idempotence, means clients can safely retry GET requests, browsers can cache responses, and CDNs can serve responses from edge locations. Breaking this rule by using GET to trigger side effects confuses caching systems and violates HTTP semantics.

Single resource reads return one specific item identified by its ID or unique key. Collection reads return multiple resources, usually with filtering, sorting, and pagination options. The URL structure should make this distinction clear — `/api/projects/123` for single resources, `/api/projects` for collections.

Response data should include everything clients need to display or work with the resource. But avoid returning sensitive data that only some users should see. Consider the requesting user's permissions and filter response fields accordingly. Some APIs return different field sets based on access level.

# APIForge Frontend team fetching project details for dashboard
GET /api/v1/projects/proj_7x9k2m8n4p1q HTTP/1.1
Host: api.apiforge.dev
Accept: application/json
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
If-None-Match: "etag-abc123def456"
HTTP/1.1 200 OK Content-Type: application/json ETag: "etag-xyz789ghi012" Cache-Control: private, max-age=300 Last-Modified: Tue, 15 Feb 2024 14:30:22 GMT { "id": "proj_7x9k2m8n4p1q", "name": "Mobile Payment Gateway", "description": "Secure payment processing for mobile apps", "tech_stack": ["Node.js", "PostgreSQL", "Redis"], "team_size": 4, "deadline": "2024-06-15T00:00:00Z", "priority": "high", "status": "in_progress", "progress_percentage": 23, "created_at": "2024-02-15T14:30:22Z", "updated_at": "2024-02-15T16:45:33Z" }
What just happened?
The API returned the requested project with 200 OK status. Cache headers allow browsers to store this response for 5 minutes. ETag support lets clients check if the resource changed since last fetch. Notice how the response includes computed fields like progress_percentage that help the frontend display rich information. Try this: Use ETag headers to reduce bandwidth when resources have not changed.

Collection reads often need additional parameters for filtering, sorting, and pagination. Query parameters handle these concerns cleanly. `GET /api/projects?status=active&sort=deadline` reads all active projects sorted by deadline. Keep query parameter names intuitive and document the supported options clearly.

Error handling for Read operations focuses on resource existence and access permissions. Return 404 Not Found when the resource does not exist. Return 403 Forbidden when the user lacks permission to read it. Avoid exposing whether resources exist when users should not know about them — use 404 for both cases.

Update Operations (PUT & PATCH)

Update operations split into two approaches with different semantics and use cases. PUT replaces the entire resource with new data. PATCH applies partial modifications to specific fields. The choice affects how clients prepare requests and how servers process them.

PUT semantics require sending the complete resource representation. If a project resource has ten fields, PUT requests should include all ten fields, even unchanged ones. The server replaces the entire resource with the provided data. Missing fields get set to null or default values, which can cause data loss if clients are not careful.

PATCH semantics allow partial updates with just the fields that changed. A PATCH request might include only the project name and deadline, leaving other fields untouched. This approach reduces payload size and prevents accidental data loss, making it more popular for most update scenarios.

Response handling for updates typically returns the modified resource with 200 OK status. Some APIs return 204 No Content if the response body would just duplicate the request data. Include any server-computed fields like updated timestamps or version numbers in the response.

# APIForge Product team updating project priority and deadline
PATCH /api/v1/projects/proj_7x9k2m8n4p1q HTTP/1.1
Host: api.apiforge.dev
Content-Type: application/json
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
If-Match: "etag-xyz789ghi012"

{
  "priority": "urgent",
  "deadline": "2024-05-30T23:59:59Z",
  "team_size": 6
}
HTTP/1.1 200 OK Content-Type: application/json ETag: "etag-new456def789" Last-Modified: Wed, 16 Feb 2024 09:15:44 GMT { "id": "proj_7x9k2m8n4p1q", "name": "Mobile Payment Gateway", "description": "Secure payment processing for mobile apps", "tech_stack": ["Node.js", "PostgreSQL", "Redis"], "team_size": 6, "deadline": "2024-05-30T23:59:59Z", "priority": "urgent", "status": "in_progress", "progress_percentage": 23, "created_at": "2024-02-15T14:30:22Z", "updated_at": "2024-02-16T09:15:44Z" }
What just happened?
The PATCH request updated only the three specified fields while preserving all other project data. The server returned the complete updated resource with a new ETag and updated timestamp. The If-Match header prevented conflicting updates if another user modified the project simultaneously. Try this: Use PATCH for most updates and reserve PUT for complete resource replacement scenarios.

Optimistic locking prevents lost updates when multiple clients modify the same resource simultaneously. ETags provide a clean mechanism for this. Clients include the If-Match header with the ETag from their last read. The server processes the update only if the ETag matches, returning 412 Precondition Failed if another client modified the resource first.

Validation for updates checks both field-level constraints and business rules. Some fields might be read-only after creation. Others might have complex validation that depends on the resource's current state. Update operations should validate only the fields being changed, not require all validation to pass.

Aspect PUT PATCH
Payload Complete resource Only changed fields
Missing fields Set to null/default Unchanged
Use case Full replacement Partial updates
Risk Accidental data loss Minimal

Delete Operations (DELETE)

Deletion seems straightforward but raises complex questions about data permanence, cascading effects, and user intent. Real-world systems rarely delete data immediately. Instead, they mark resources as deleted, archive them, or require multi-step confirmation processes.

Hard deletes permanently remove data from the system with no recovery option. Soft deletes mark resources as deleted while preserving the underlying data for potential recovery or audit purposes. The choice depends on business requirements, regulatory constraints, and user expectations.

DELETE operations should return appropriate status codes based on the outcome. Return 204 No Content for successful deletions with no response body. Return 200 OK if the response includes confirmation details or related information. Return 404 Not Found if the resource does not exist or was already deleted.

Cascading deletes affect related resources when a parent resource gets deleted. Deleting a project might also delete its tasks, files, and comments. Some APIs handle this automatically, others require explicit confirmation, and some block deletion until related resources are handled separately.

# APIForge Security team removing a completed security audit project
DELETE /api/v1/projects/proj_7x9k2m8n4p1q HTTP/1.1
Host: api.apiforge.dev
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
X-Confirmation-Token: delete_confirm_abc123def456
HTTP/1.1 200 OK Content-Type: application/json X-RateLimit-Remaining: 4998 { "id": "proj_7x9k2m8n4p1q", "name": "Mobile Payment Gateway", "status": "deleted", "deleted_at": "2024-02-16T11:30:15Z", "recovery_deadline": "2024-03-16T11:30:15Z", "affected_resources": { "tasks": 15, "files": 8, "team_members": 6 } }
What just happened?
The API performed a soft delete, marking the project as deleted while preserving the data for 30-day recovery. The response includes details about affected resources and the recovery deadline. The confirmation token prevented accidental deletion. Try this: Implement soft deletes for important resources and provide clear recovery mechanisms for users who change their minds.

Permission checks for Delete operations should be more restrictive than other operations. Consider requiring additional confirmation for destructive actions. Some systems require manager approval for deleting shared resources or implement cooling-off periods before permanent deletion.

Error responses for Delete operations should distinguish between different failure reasons. Return 403 Forbidden for insufficient permissions, 409 Conflict for resources that cannot be deleted due to dependencies, and 404 Not Found for resources that do not exist.

Production Considerations
Always log delete operations with user identification and timestamps. Implement backup strategies that can restore deleted resources. Consider rate limiting delete operations more aggressively than other operations to prevent accidental bulk deletion.

CRUD Best Practices

Production CRUD APIs need patterns that handle edge cases, performance requirements, and user experience concerns. These patterns separate hobby projects from systems that serve millions of users reliably.

Idempotency keys prevent duplicate resource creation when clients retry failed requests. POST operations are not naturally idempotent, but you can make them behave that way by accepting an idempotency key in the request. If the same key appears twice, return the original resource instead of creating a duplicate.

Bulk operations allow clients to perform multiple CRUD operations in a single request. Creating ten resources with ten separate POST requests creates network overhead and consistency challenges. Bulk endpoints accept arrays of operations and process them efficiently, though they complicate error handling since some operations might succeed while others fail.

Versioning becomes critical when CRUD operations evolve over time. Adding optional fields is usually safe, but removing fields or changing validation rules can break existing clients. API versioning strategies help manage these changes while maintaining backward compatibility.

Audit trails track who performed which operations when. This becomes essential for compliance, debugging, and user accountability. Store enough context to understand what changed, who made the change, and why. Consider privacy requirements when deciding how much detail to log.

Without CRUD Structure
Endpoints like /createProject, /getProjectInfo, /updateProjectName create inconsistent interfaces. Clients must learn different patterns for each operation, caching becomes difficult, and HTTP semantics get ignored.
With CRUD Structure
Standard resource URLs like /api/projects support all operations through different HTTP methods. Clients learn one pattern that works everywhere, HTTP caching works naturally, and the API becomes predictable.

Response consistency across all CRUD operations improves client development experience. Use the same field names, date formats, and nested structures whether returning resources from CREATE, READ, or UPDATE operations. Clients should be able to use the same data structures for all operations.

Error message quality directly affects how quickly developers can integrate with your API. Provide specific error codes for different validation failures. Include the field name that caused the error and suggest how to fix it. Generic "bad request" messages waste everyone's time.

Best Practice What It Does APIForge Use Case
Idempotency Keys Prevent duplicate creation on retry Avoid duplicate project creation when network fails
Optimistic Locking Prevent conflicting updates Handle multiple team members editing project details
Soft Deletion Enable recovery of deleted resources Allow project recovery within 30-day window
Bulk Operations Process multiple resources efficiently Import multiple team members in single request
Audit Logging Track all data changes Monitor security-sensitive project modifications

Quiz

1. The APIForge Frontend team needs to update just the deadline and priority of a project without affecting other fields. What is the most appropriate approach?

2. When a CREATE operation successfully adds a new project to the APIForge system, what should the API response include?

3. The APIForge mobile app needs to create a new project, but the network connection is unreliable and might cause request timeouts. How should the app handle potential duplicate submissions?

Up Next
Pagination & Filtering
APIForge handles thousands of projects and users, requiring efficient techniques to return manageable data sets without overwhelming clients or servers.