DEV Community

Ameh Mathias Ejeh
Ameh Mathias Ejeh

Posted on • Edited on

Task API

A simple task‑tracking API powered by Node.js, Express, and PostgreSQL, containerized with Docker Compose.
Run the entire stack with one command — no manual setup required.


Installation & Run

# 1. Clone the repository
git clone <your-repo-url>
cd hello-server

# 2. Install dependencies
npm install

# 3. Start the server
node app.js
Enter fullscreen mode Exit fullscreen mode

Endpoints Table

Method Endpoint Description Status Codes
GET /tasks List all tasks 200
GET /tasks/{id} Get a single task by ID 200, 404
POST /tasks Create a new task 201, 400
PUT /tasks/{id} Update a task 200, 400, 404
DELETE /tasks/{id} Delete a task 204, 404

Example curl -i Output

curl -i http://localhost:3000/tasks
Enter fullscreen mode Exit fullscreen mode
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 123

[
  { "id": 1, "title": "Read a bible", "done": false },
  { "id": 2, "title": "Build an app", "done": true },
  { "id": 3, "title": "Go for lecture", "done": false }
]
Enter fullscreen mode Exit fullscreen mode

Swagger UI Screenshot

Notes

  • Uses Express ESM syntax ("type": "module" in package.json).
  • In-memory task list (no database).
  • Fully documented with OpenAPI 3.0 spec served via swagger-ui-express.

Docker Implementation

QuickStart

docker compose up

Enter fullscreen mode Exit fullscreen mode

This command builds and starts both the API and Postgres services.

Environment Variables

Copy .env.example to .envand set:

DATABASE_URL=postgres://postgres:dev@db:5432/tasks
PORT=3000
Enter fullscreen mode Exit fullscreen mode

Database Verification

After running docker compose up, connect to Postgres:

docker exec -it self-version-db-1 psql -U postgres -d tasks

Enter fullscreen mode Exit fullscreen mode

Then check your data:

\dt
SELECT * FROM "Tasks";
Enter fullscreen mode Exit fullscreen mode

AI vs Me

My full prompt.

I’m building a simple Task API using Node.js, Express, and ESM modules.
Follow these stages to implement a complete CRUD API with Swagger UI documentation and a README.

Stage 0 – Hello Server
Set up a basic Express server on port 3000.

Return a “hello” message at /.

Confirm with curl -i http://localhost:3000 → status 200.

Stage 1 – Root and Health Endpoints
Add GET / returning JSON:
{"name": "Task API", "version": "1.0", "endpoints": ["/tasks"]}

Add GET /health returning {"status": "ok"}.

Stage 2 – Read Endpoints
Create an in‑memory array of 3 tasks: each with id, title, and done.

Add GET /tasks → returns all tasks.

Add GET /tasks/:id → returns one task or {"error": "Task not found"} with status 404.

Stage 3 – Create Endpoint
Add POST /tasks → accepts JSON {"title": "Buy milk"}.

Assign next id, set done: false, return created task with status 201.

Validate input: missing/empty title → status 400.

Stage 4 – Update & Delete
Add PUT /tasks/:id → updates title and/or done. Unknown id → 404, invalid body → 400.

Add DELETE /tasks/:id → removes task, returns 204 or 404 if not found.

Confirm CRUD works with correct status codes (200, 201, 204, 400, 404).

Stage 5 – Swagger UI
Install swagger-ui-express.

Write a small openapi.json describing the five task endpoints.

Serve it at /docs.

In Swagger UI, use “Try it out” to create, list, update, and delete tasks.

/docs should show all endpoints and support the full CRUD cycle.

Stage 6 – README
Write a README that includes:

What the project is and what it does.

How to install and run it (one documented command).

A table listing all endpoints with their methods and expected responses.

One pasted curl -i output example.

A screenshot of your Swagger UI page.

Use modern JavaScript (ESM imports/exports) and keep everything in a single file for simplicity.

Enter fullscreen mode Exit fullscreen mode

Comparing AI Code with My Code

  • What did the AI do better — and do you understand its version well enough to explain it? The AI generated the code with better error handling with a detailed documentation.
  • What did it get wrong or quietly ignore from your prompt? - The AI did not ignore anything or got anything wrong from my prompt.
  • What did your prompt forget to specify — My prompt did not forget any details. I described the complete details of the project in my prompt.

Why I Did Not Use SQLite

I initially planned to use SQLite (via better‑sqlite3) because it’s simple, lightweight, and requires no external server. However, on my Windows 10 system, the installation failed with a native C++ compilation error.

better‑sqlite3 depends on node‑gyp and Visual Studio Build Tools to compile its bindings. My setup lacked the required “Desktop development with C++” workload, and Node 22 no longer supports older Visual Studio versions. As a result, the module couldn’t build successfully — even after verifying Python and Node‑gyp versions.

Why I Chose Postgres + Sequelize

To avoid native compilation issues and gain a more scalable setup, I switched to PostgreSQL with Sequelize ORM.
This choice offers several advantages:

  • No native compilation — Sequelize uses pure JavaScript drivers (pg and pg‑hstore).
  • Cross‑platform reliability — works seamlessly on Windows without extra build tools.
  • Automatic table creation and seeding — the app initializes the database automatically on startup.

The server connects to Postgres, creates the Tasks table, and seeds three example tasks — no manual setup required.

DB Screenshot

Top comments (0)