Beginner · APIs and request handling · topic 9 of 54 · 30 min
Handling requests: a full CRUD API
Explanation
CRUD: the four basic actions
CRUD stands for Create, Read, Update, Delete. Nearly every app is built from these four actions: a shop adds products, shows them, changes prices and removes old ones. In a REST API, they map to POST, GET, PATCH or PUT, and DELETE.
An in-memory store
A store is where the data lives. For now we use a plain array in memory. Each product gets an id from a counter called nextId, which goes up by one for every new product, so two products never share an id.
const products = [
{ id: 1, name: 'Basmati rice 1kg', price: 120, stock: 40 },
{ id: 2, name: 'Toor dal 1kg', price: 160, stock: 25 },
];
let nextId = 3;
function findProduct(id) {
return products.find((p) => p.id === id);
}
console.log(findProduct(2)); // the toor dal object
console.log(findProduct(99)); // undefinedOne handler, many actions
const items = [{ id: 1, name: 'Sugar 1kg', price: 45 }];
let nextId = 2;
function handle(request) {
const parts = request.path.split('/').filter(Boolean);
const id = Number(parts[1]);
if (request.method === 'GET' && parts.length === 1) {
return { status: 200, body: items };
}
if (request.method === 'POST' && parts.length === 1) {
const item = { id: nextId++, name: request.body.name, price: request.body.price };
items.push(item);
return { status: 201, body: item };
}
const index = items.findIndex((p) => p.id === id);
if (index === -1) return { status: 404, body: { error: 'Product not found' } };
if (request.method === 'GET') return { status: 200, body: items[index] };
if (request.method === 'DELETE') {
items.splice(index, 1);
return { status: 204, body: null };
}
return { status: 405, body: { error: 'Method not allowed' } };
}
console.log(handle({ method: 'POST', path: '/products', body: { name: 'Tea 250g', price: 140 } }));
console.log(handle({ method: 'GET', path: '/products/2' }));
console.log(handle({ method: 'DELETE', path: '/products/2' }).status); // 204
console.log(handle({ method: 'GET', path: '/products/2' }).status); // 404Step by step for each request
- Read the method and path; find the id if there is one.
- For an item, look it up. If it is not there, return 404 straight away.
- Do the action: push a new object, change fields, or splice it out.
- Return the right status: 200 for reads and updates, 201 for create, 204 for delete.
- Return the record in the body (except after delete), so the app can show it.
| Request | Store change | Response |
|---|---|---|
| GET /products | none | 200 with the array |
| GET /products/2 | none | 200 with one product, or 404 |
| POST /products | push a new object with nextId | 201 with the new product |
| PATCH /products/2 | change only the fields sent | 200 with the updated product, or 404 |
| DELETE /products/2 | splice it out | 204 with no body, or 404 |
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Handling requests: a full CRUD API · 1/6
Most apps do four basic things with data: create, read, update and delete. We call it CRUD.
Prefer a video by a teacher? Find free videos on “build crud rest api javascript beginners” on YouTube ↗
In real life: A kirana shop billing app
A shop owner in Nagpur uses a phone app to manage stock. Adding a new brand of biscuits sends POST /products and gets back 201 with id 57. When the price changes, the app sends PATCH /products/57 with {"price": 30}. When stock runs out for good, it sends DELETE /products/57. If a staff member's old phone still shows product 57 and tries to open it, the backend answers 404 and the app shows "This product was removed".
Practice (0/3 done)
The products array is given. Write a function getProduct(id) that returns { status: 200, body: product } when a product with that id exists, and { status: 404, body: { error: "Product not found" } } when it does not.
Write a function createProduct(body). If body.name is a non-empty string and body.price is a number, add { id, name, price, stock } to products (id from nextId, which then goes up by one; stock is body.stock or 0) and return { status: 201, body: newProduct }. Otherwise return { status: 400, body: { error: "name and price are required" } } and add nothing.
Write handle(request) for request { method, path, body }. GET /products returns 200 with the whole array. For /products/:id: if the id is not found return 404 with { error: "Product not found" }; GET returns 200 with the product; PATCH changes only price and/or stock if they are in the body and returns 200 with the product; DELETE removes it and returns { status: 204, body: null }. Anything else returns 404 with { error: "Not found" }.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Validating inputAPIs and request handling · same module
- REST APIs and JSONComputer Networking (CCNA level) · Automation, SDN and cloud networking
- REST API design and JSON handlersGo Programming (backend and cloud) · Building a REST API with a database
- How web requests work (and why that matters)Ethical Hacking and Penetration Testing (legal labs) · Web application testing: Burp Suite and the basics
- Route handlers that follow the contractFull-Stack Development · Building the backend
- Validating input and handling errors on the serverFull-Stack Development · Building the backend
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What does CRUD stand for?
Answer: Create, Read, Update, Delete
CRUD names the four basic actions almost every app performs on its data.
A POST /products request adds a new product. What should the response contain?
Answer: Status 201 and the new product with its id
201 Created, with the new record, so the app knows the new id.
PATCH /products/8 arrives but there is no product 8. What do you return?
Answer: 404 with an error message
The resource does not exist, so 404 Not Found.
Why is a JavaScript array not enough to store a real shop's data?
Answer: The data is lost when the server restarts
Memory is wiped on restart, and each server copy has its own array. Real apps use a database.
Why use a nextId counter instead of products.length + 1 for new ids?
Answer: After a delete, length + 1 can repeat an id that was already used
If product 3 of 3 is deleted, length + 1 gives 3 again. A counter never goes back.
What does "stateless" mean for a REST API?Related
Answer: Each request carries everything needed, such as the token; the server does not remember earlier requests
Stateless means no memory of earlier requests, so every request includes its own authentication and data.
From REST APIs and JSON
Why put a request id in both the log and the error message?Related
Answer: So support can find the exact log line when a user reports a problem
The user quotes the reference, and engineers search the logs for it.
From Handling errors well
Why make handlers depend on a Store interface?Related
Answer: The storage can change and tests can use a fake without touching handlers
This is the "accept interfaces" idea applied to APIs.
With a GET request, data usually goes in the…Related
Answer: URL
GET carries data in the URL (query string).
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 2 more topics in “APIs and request handling” before its exam: Validating input, Handling errors well.
- Exam: APIs and request handling · 13 questions · 30 min, without help. 5 topics of this module still to finish first.
- Then the next module, Node.js and Express. 54 topics left in the course before the final exam.