CRUD, Create, Read, Update, Delete, is the foundation almost every REST resource is built on. This lesson builds a complete CRUD API for a tasks resource using Express, starting with an in-memory array.
The Four CRUD Operations
Every CRUD resource needs, at minimum, a way to list and read records (Read), add new ones (Create), modify existing ones (Update), and remove them (Delete). In Express, each operation maps to one HTTP method and route.
The example below uses a plain in-memory array so you can focus purely on the routing and logic; the same shape applies once you swap in a real database (see the Databases section).
GET /tasks reads the whole collection; POST /tasks creates a new task and returns it with a 201 Created status.
Full CRUD Route Set
GET /tasks list all tasks
GET /tasks/:id get one task
POST /tasks create a task
PUT /tasks/:id replace a task
PATCH /tasks/:id update part of a task
DELETE /tasks/:id delete a task
Each route corresponds to exactly one CRUD operation.
Always validate that a :id resource exists before updating or deleting it, returning 404 otherwise.
Return the created/updated resource in the response body so the client sees the final state.
DELETE typically returns 204 No Content with an empty body.
CRUD API Cheatsheet
The full route table for a typical CRUD resource.
Operation
Method + Path
Body Required
Response
List
GET /tasks
No
Array of tasks
Read one
GET /tasks/:id
No
Single task or 404
Create
POST /tasks
Yes
Created task, 201
Replace
PUT /tasks/:id
Yes
Updated task
Update
PATCH /tasks/:id
Yes (partial)
Updated task
Delete
DELETE /tasks/:id
No
204 No Content
Full In-Memory CRUD Example
Here is a complete router implementing all five routes for the tasks resource, including 404 handling.
Swapping the in-memory array for a real database changes only the implementation inside each route, tasks.find(...) becomes Task.findById(...), the route signatures and HTTP contract stay exactly the same.
Common Mistakes
Not checking whether a resource exists before updating or deleting it, silently "succeeding" on nothing.
Using PUT semantics (full replace) but only updating the fields present in the body, corrupting the rest of the resource.
Returning 200 OK for a delete when 204 No Content better matches the empty response body.
Storing state in a plain in-memory array in production, it resets on every restart and doesn't scale across multiple server instances.
Key Takeaways
CRUD maps directly onto GET, POST, PUT/PATCH, and DELETE routes.
Always check for resource existence before update/delete, responding 404 when missing.
The in-memory array pattern is great for learning, but must be replaced with a real database for production.
Route shapes stay stable even as the underlying data layer changes.
Pro Tip
Build and test your CRUD routes against an in-memory array first, once all the HTTP behavior and status codes are correct, swapping in a real database becomes a small, isolated change.
You've built a complete CRUD API. Next, learn how to move route logic into reusable Controllers.