Menu
CoddyTech

Creating with POST

Part of the REST APIs section of Coddy's Node.js journey. Lesson 2 of 25.

A client that adds a task needs to know where the new task lives. It sends the new resource to the list's URL with POST, and the server answers 201 Created with the resource and a Location header naming its URL.

POST /api/events   { "name": "Launch party" }

201 Created
Location: /api/events/12
{ "id": 12, "name": "Launch party" }

The server picks the id, so two clients can never claim the same one. With the Location header the client can fetch the new event without building the URL itself. res.location(path) sets that header, and it chains like res.status:

res.status(201).location(`/api/events/${event.id}`).json(event);
challenge icon

Challenge

Easy

Clients need a way to add tasks. Add a POST route that creates a task and tells the client where the new task lives.

  1. In routes/tasks.js, add a route for POST /api/tasks (inside the router, that path is '/'). It reads title from the JSON body, for example { "title": "Order new chairs" }.
  2. Build the new task with four fields:
    • id: from the nextId() function in store.js. Import it next to tasks.
    • title: from the body.
    • done: false.
    • createdAt: new Date().toISOString(), the current time as text.

    Add it to the tasks array, so GET /api/tasks shows it too.

  3. Respond with status 201 and the new task as JSON. Set the Location header to the task's own URL: for task 4 that is /api/tasks/4. On a fresh Run the response body looks like this (your createdAt is the moment you send it):
    { "id": 4, "title": "Order new chairs", "done": false, "createdAt": "2026-10-30T09:12:44.512Z" }
  4. When the body has no title, respond with status 400 and { "error": "title is required" }, and add nothing to the list.

Try it: choose POST, path /api/tasks, body { "title": "Order new chairs" }. You should see 201 and the task above with id 4, and the response's Headers tab shows Location: /api/tasks/4. Send GET /api/tasks/4: you get the same task back. Then POST {} to /api/tasks: you get 400 with the error, and GET /api/tasks still lists 4 tasks, because the refused POST added nothing.

Try it yourself

import { Router } from 'express';
import { tasks } from '../store.js';

const router = Router();

router.get('/', (req, res) => {
    res.json(tasks);
});

router.get('/:id', (req, res) => {
    const task = tasks.find((t) => t.id === Number(req.params.id));
    if (!task) {
        return res.status(404).json({ error: 'Task not found' });
    }
    res.json(task);
});

export default router;

All lessons in REST APIs

Practice on your own: Express playground