Skip to content

About

RESTful Task Manager API built with Node.js and Expess — CRUD routes, request logging, and centralized rror-handling middleware (AWDF Practical 4).

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Task Manager API

A RESTful backend for a task management system, built with Node.js and Express as part of AWDF Practical 4, then upgraded to store data in MongoDB via Mongoose for Practical 5 (schema design, validation, and real persistence instead of an in-memory array).

Set up MongoDB

You need a MongoDB instance to connect to — pick one:

Option A — local MongoDB. Install MongoDB Community Server, make sure mongod is running, then the default connection string (mongodb://127.0.0.1:27017/taskmanager) just works.

Option B — MongoDB Atlas (free, no local install). Create a free cluster at mongodb.com/atlas, add your IP to the access list, and grab the connection string from Database → Connect → Drivers.

Then:

cp .env.example .env
# edit .env and set MONGODB_URI to whichever option you picked

Run it

npm install
npm run seed      # optional: clears the tasks collection, inserts 4 sample tasks
npm start          # node server.js
# or, auto-restart on file changes:
npm run dev        # node --watch server.js

Server listens on http://localhost:5000 (override with PORT in .env). On startup it connects to MongoDB first — if the connection fails, it logs the error and exits instead of serving an API that would 500 on every request.

Schema design (Practical 5)

models/Task.js defines the Mongoose schema:

Field Type Rules
title String required, trimmed, 1-120 chars
description String optional, trimmed, up to 1000 chars, defaults to ''
completed Boolean defaults to false
createdAt, updatedAt Date added automatically (timestamps: true)
_id ObjectId Mongo's default primary key — ids are now 24-char hex strings, not sequential integers like Practical 4

Validation lives on the schema, not hand-rolled in the controller — it's enforced no matter what calls .save()/.create() (controller, seed script, or anything else that touches the model), and runValidators: true on updates makes sure partial PUT requests are checked too.

Middleware pipeline

Client (Postman/browser)
  │
  ▼
express.json()                  parses JSON bodies
  │
  ▼
requestLogger                   logs "METHOD URL - ISO timestamp" for every request
  │
  ▼
Express Router (/tasks)
  ├── requireJsonContentType    POST/PUT only — 415 if Content-Type isn't application/json
  ├── validateTaskId            :id routes only — 400 if the id isn't a valid Mongo ObjectId
  └── controller (CRUD)         talks to MongoDB via the Task model
  │
  ▼
notFoundHandler                 catches any request that matched nothing above — 404 JSON
  │
  ▼
errorHandler                    LAST middleware — catches every next(err):
                                   • Mongoose ValidationError → 400
                                   • Mongoose CastError (bad id reaching a query) → 400
                                   • everything else → err.status or 500

The error handler is registered after every route on purpose: Express only routes an error to a handler that comes after the point next(err) was called, so if it were registered first it would never see anything.

Endpoints

Method Path Status codes Description
GET /tasks 200 List all tasks
GET /tasks/:id 200, 400, 404 Get one task
POST /tasks 201, 400, 415 Create a task (title required)
PUT /tasks/:id 200, 400, 404, 415 Update a task (partial body allowed)
DELETE /tasks/:id 200, 400, 404 Delete a task

Task shape (as returned by the API):

{
  "_id": "665f1a2b3c4d5e6f7a8b9c0d",
  "title": "string",
  "description": "string",
  "completed": false,
  "createdAt": "2026-08-13T12:00:00.000Z",
  "updatedAt": "2026-08-13T12:00:00.000Z",
  "__v": 0
}

Try it with curl

Run npm run seed first if you want existing tasks to GET/PUT/DELETE against — copy an _id from its output, since ids are generated by Mongo (you can't hardcode 1/2/3 like Practical 4 anymore).

# list
curl http://localhost:5000/tasks

# create
curl -X POST http://localhost:5000/tasks \
  -H "Content-Type: application/json" \
  -d '{"title":"Write the README","description":"Document the API"}'

# get one (swap in a real _id from the response above)
curl http://localhost:5000/tasks/<id>

# update
curl -X PUT http://localhost:5000/tasks/<id> \
  -H "Content-Type: application/json" \
  -d '{"completed":true}'

# delete
curl -X DELETE http://localhost:5000/tasks/<id>

# 400 — missing title (schema validation)
curl -X POST http://localhost:5000/tasks \
  -H "Content-Type: application/json" -d '{"description":"no title"}'

# 400 — malformed id (not a valid ObjectId)
curl http://localhost:5000/tasks/abc

# 404 — well-formed id, but no matching task
curl http://localhost:5000/tasks/665f00000000000000000000

# 404 — undefined route
curl http://localhost:5000/nope

# 415 — missing Content-Type
curl -X POST http://localhost:5000/tasks -d '{"title":"no header"}'

# 500 — deliberately thrown error, to prove the global handler works
curl http://localhost:5000/debug/throw

Or import the routes above into Postman/Thunder Client.

What changed from Practical 4

  • In-memory let tasks = [] array → real persistence in MongoDB via the Task Mongoose model (models/Task.js).
  • Manual if (!title) ... checks in the controller → schema-level validation (required, minlength/maxlength) that Mongoose enforces automatically and reports back as a ValidationError.
  • validateTaskId now checks for a valid Mongo ObjectId instead of a positive integer, since ids are generated by MongoDB, not an in-process counter.
  • errorHandler gained two new branches to translate Mongoose-specific errors (ValidationError, CastError) into the same clean { error } JSON shape as everything else.
  • New config/db.js (connection helper), .env.example (connection string template), and scripts/seed.js (sample data loader).

What's implemented (Practical 4 + 5 rubric)

  • Express server on a defined port, confirmed via terminal + curl/Postman
  • All 4 CRUD endpoints with correct HTTP methods and status codes (200/201/400/404/415/500)
  • Global request-logging middleware (method, URL, timestamp) applied to every request
  • Global error-handling middleware, registered last, returns structured JSON and never leaks stack traces to the client
  • Mongoose schema with field-level validation (required, length bounds, defaults, timestamps)
  • Real MongoDB persistence via config/db.js, with a fail-fast startup if the DB is unreachable
  • Content-Type validation on POST/PUT, ObjectId-format validation on :id routes, structured 404 handler
  • Seed script for reproducible sample data

About

RESTful Task Manager API built with Node.js and Expess — CRUD routes, request logging, and centralized rror-handling middleware (AWDF Practical 4).

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages