Learning Goals
3 minBy the end of this lesson you will be able to:
- Match each CRUD action to its HTTP verb: Create → POST, Read → GET, Update → PUT, Delete → DELETE.
- Build a full-CRUD resource on an in-memory array, giving each new item a fresh
id. - Read a POST body with
req.bodyand update or delete by:id. - Test a POST, PUT and DELETE from the terminal with
curland read the reply.
Warm-Up · Match the Verb
5 minLast lesson you built a read-only REST resource. It could only answer GET. Today we add the other three verbs.
Four HTTP verbs, four CRUD actions. Match each verb on the left to the action it performs on the right:
POST ? Read one or many
GET ? Delete one
PUT ? Create a new one
DELETE ? Update an existing oneReveal
The pairs line up like this:
POST→ Create a new one.GET→ Read one or many.PUT→ Update an existing one.DELETE→ Delete one.
That is the whole of CRUD. The first letters spell it: Create, Read, Update, Delete.
New Concept · The Four Things You Do to a List
12 minThink of the contacts list in your phone. There are really only four things you ever do to it: add a contact, view your contacts, change one, or remove one. That is CRUD — Create, Read, Update, Delete.
A REST API gives each of those four actions its own HTTP verb. Same resource, four verbs. The verb says what to do; the URL says to which thing.
The four route signatures
Here are the four routes for a students resource. Read the comment on each line — it names the CRUD action:
app.post('/api/students', (req, res) => {}) // Create
app.get('/api/students', (req, res) => {}) // Read many
app.get('/api/students/:id', (req, res) => {}) // Read one
app.put('/api/students/:id', (req, res) => {}) // Update
app.delete('/api/students/:id', (req, res) => {}) // DeleteNotice the pattern. Creating and reading-many act on the whole collection (/api/students). Reading-one, updating and deleting act on one item, so they carry an :id in the path.
Why it matters
Once you see CRUD, you see it everywhere. A to-do list, an online shop, a school attendance register — all of them are Create, Read, Update, Delete on some list. Learn the four verbs once, and you can build the backend for almost any app.
Worked Example · A Full-CRUD Students API
12 minFollow along in your Express project. Aisyah is building the backend for a small tuition centre in Ipoh. We will build all four verbs, one step at a time.
Step 1 — The array and express.json()
We have no database yet, so we store students in a plain array in memory. express.json() (from Lesson 6) fills req.body from JSON:
const express = require('express')
const app = express()
app.use(express.json()) // fills req.body from a JSON request
// our in-memory "database" for now
let students = [
{ id: 1, name: 'Aisyah' },
{ id: 2, name: 'Wei Jie' }
]
let nextId = 3 // the id to hand out to the next new studentThe nextId counter is our simple way to give every new student a unique id.
Step 2 — POST: create a student from req.body
A POST reads the name from the body, builds a student with a fresh id, pushes it, and returns the new record:
// Create — add a new student
app.post('/api/students', (req, res) => {
const student = { id: nextId, name: req.body.name }
nextId = nextId + 1 // move the counter on
students.push(student) // add to the array
res.json(student) // send the new student back
})You cannot open a POST in a browser — the address bar only sends GETs. So we test it from the terminal with curl:
$ curl -X POST http://localhost:3000/api/students -H "Content-Type: application/json" -d '{"name":"Priya"}'The server replies with the newly created student:
{ "id": 3, "name": "Priya" }Windows note: in PowerShell, type curl.exe (with the .exe) so you get the real curl, not a PowerShell alias. Prefer a click-based tool? The Thunder Client extension for VS Code sends the same requests from a panel.
Step 3 — GET: read many and read one
Two GET routes: one for the whole list, one for a single student by id:
// Read many — the whole list
app.get('/api/students', (req, res) => {
res.json(students)
})
// Read one — find by id in the path
app.get('/api/students/:id', (req, res) => {
const id = Number(req.params.id)
const student = students.find((s) => s.id === id)
res.json(student)
})GET routes are openable in a browser. Visit http://localhost:3000/api/students and you see the list, now including Priya:
[
{ "id": 1, "name": "Aisyah" },
{ "id": 2, "name": "Wei Jie" },
{ "id": 3, "name": "Priya" }
]Step 4 — PUT: update a student by id
A PUT finds the student, overwrites the name from the body, and returns the updated record:
// Update — change a student's name
app.put('/api/students/:id', (req, res) => {
const id = Number(req.params.id)
const student = students.find((s) => s.id === id)
student.name = req.body.name // overwrite with the new name
res.json(student)
})Change student 1's name with a PUT:
$ curl -X PUT http://localhost:3000/api/students/1 -H "Content-Type: application/json" -d '{"name":"Aisyah Rahman"}'{ "id": 1, "name": "Aisyah Rahman" }Step 5 — DELETE: remove a student by id
A DELETE keeps every student except the one whose id matches, using filter:
// Delete — remove a student by id
app.delete('/api/students/:id', (req, res) => {
const id = Number(req.params.id)
students = students.filter((s) => s.id !== id)
res.json({ deleted: id })
})Remove student 2 with a DELETE:
$ curl -X DELETE http://localhost:3000/api/students/2{ "deleted": 2 }What changed? Last lesson the resource only answered GET. Now the same /api/students path handles all four CRUD verbs. That is a complete, working REST resource.
Try It Yourself
13 minThree tasks in your server.js. Restart with node server.js after each change. Remember: the array resets every time you restart.
Task 1 — CRUD for your own resource
Pick a resource of your own —
books,songsorsnacks. Copy the five routes from the Worked Example and rename them. Start with a small seed array and anextIdcounter, exactly as we did for students.Check all four verbs work before moving on.
Task 2 — Accept a second field
Make your POST read a second field from the body, not only the name. For a students API that might be
form; for snacks, apricein RM:app.post('/api/students', (req, res) => { const student = { id: nextId, name: req.body.name, form: req.body.form // the new second field } nextId = nextId + 1 students.push(student) res.json(student) })Send both fields with curl and confirm both come back.
Task 3 — Test your DELETE with curl
Add one item with a POST, then delete it with a DELETE from the terminal. Read the reply, then GET the whole list and check the item is really gone:
$ curl -X DELETE http://localhost:3000/api/students/3On Windows, remember
curl.exein PowerShell. Did the list shrink by one?
Mini-Challenge · A Careful DELETE
8 minOur DELETE happily replies { "deleted": 2 } even when no student 2 exists. That is dishonest. Make it careful, using status codes — a small peek at the next lesson.
The rule: if the id is not found, reply 404 with a message. If it is found, delete it and reply 204 with an empty body.
It works if: deleting a real id returns status 204 and no content, but deleting a missing id returns 404 and a short error message.
Reveal a sample answer
// Delete — 404 if missing, 204 on success
app.delete('/api/students/:id', (req, res) => {
const id = Number(req.params.id)
const exists = students.some((s) => s.id === id)
if (!exists) {
return res.status(404).json({ error: 'No student with that id' })
}
students = students.filter((s) => s.id !== id)
res.status(204).end() // success, nothing to send back
})Deleting a missing id (say 99) returns:
404 { "error": "No student with that id" }Deleting a real id returns an empty body with the status:
204 (no content)Two ideas combine here: today's DELETE verb and status codes. 204 means “done, and there is nothing to send back”, so we use res.status(204).end() instead of res.json(...).
Recap
3 min- CRUD is the four things you do to a list: Create, Read, Update, Delete.
- They map to verbs: POST, GET, PUT, DELETE.
- POST reads
req.body; PUT and DELETE find the item by:id. - Give each new item a fresh
idwith a simple counter. - Test non-GET verbs from the terminal with
curl(curl.exeon Windows).
New words
- CRUD — Create, Read, Update, Delete: the four core actions on data.
- POST — the verb that creates a new item from the request body.
- GET — the verb that reads data; openable in a browser.
- PUT — the verb that replaces an existing item by id.
- PATCH — a cousin of PUT that changes only part of an item.
- DELETE — the verb that removes an item by id.
Homework
4 min to brief · ~20 min to doRequired
- Build a full-CRUD resource of your choice on an in-memory array — all five routes (POST, GET many, GET one, PUT, DELETE). Then test each verb with
curlfrom the terminal. Take a screenshot of the four requests and their replies, and bring it to next lesson.
Optional stretch
- Read one short paragraph on the difference between
PUTandPATCH. In two sentences of your own, explain when you would reach for each. Hint: one replaces the whole item, the other changes one field.