Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Node.js — Core Concepts to Full-Stack Todo Application

A progressive, hands-on Node.js repository that walks through foundational server-side JavaScript concepts — from raw HTTP server construction and custom logging to building a complete, file-persisted Todo application. Built entirely on Node.js built-in modules with no external framework dependencies.


Overview

This repository is structured as a series of self-contained modules, each targeting a distinct layer of backend engineering with Node.js. Rather than jumping straight to a framework, the codebase deliberately uses the native http, fs, and path modules to demonstrate what Express and similar frameworks abstract away. It culminates in a functional Todo application that serves static HTML, handles RESTful routes manually, and persists data to a local JSON file.

The project is suited for developers who want to understand what happens beneath the framework layer, or for reviewers who want to see evidence of first-principles backend thinking.


Repository Structure

Nodejs/
├── Basics/             # Core Node.js fundamentals (modules, fs, events, etc.)
├── LOGGER/             # Custom request/event logger implementation
├── SERVER/             # Standalone HTTP server — routing, request parsing, response handling
├── TODO/               # Full Todo application: CRUD routes + static file serving
├── static/             # Static HTML assets served by the application
└── tasks.json          # JSON flat-file data store for Todo tasks

Directory Breakdown

Directory Role
Basics/ Exploratory scripts covering Node.js core APIs: file system, event emitter, module system, streams, and the event loop
LOGGER/ A hand-rolled logger module that intercepts and records request/response data — written without any third-party logging library
SERVER/ A minimal HTTP server built using http.createServer() — demonstrates manual routing, response codes, content-type headers, and request body parsing
TODO/ The primary application module — integrates routing, static file serving, and JSON file I/O to deliver a working task management system
static/ HTML pages (UI layer) served directly by the Node.js server, covering the frontend of the Todo app
tasks.json Flat-file JSON database; stores the list of tasks with their state (pending/completed)

Tech Stack

Layer Technology
Runtime Node.js (LTS)
Language JavaScript (ES6+)
HTTP Layer Node.js built-in http module
File I/O Node.js built-in fs module (synchronous and async)
Path Handling Node.js built-in path module
Data Persistence JSON flat-file (tasks.json)
Frontend Plain HTML (served statically)
Logging Custom implementation (no winston/morgan dependency)
Package Manager npm (no external runtime dependencies inferred)

Note: No package.json is present at the repository root, which confirms the application is intentionally dependency-free at runtime. All functionality is implemented using Node.js built-in modules only.


Features

  • Zero-dependency HTTP server — built with http.createServer(), demonstrating raw request/response lifecycle management without Express
  • Manual routing — URL and method matching handled with explicit conditional logic, giving full visibility into how routing frameworks work under the hood
  • Static file serving — HTML assets from the static/ folder are served by reading files from disk via fs and setting appropriate Content-Type headers
  • Todo CRUD operations — create, read, update (toggle), and delete tasks through manually defined route handlers
  • JSON file persistencetasks.json acts as the data layer; the server reads from and writes to it on each operation using the fs module
  • Custom logger — a standalone logger module in LOGGER/ that records incoming requests, useful for debugging without attaching a third-party library
  • Progressive module structure — codebase is organized pedagogically: from Basics/LOGGER/SERVER/TODO/, each building on the previous

Architecture Overview

Request Flow

Client (Browser)
      │
      ▼
  Node.js HTTP Server  (http.createServer)
      │
      ├──► Static Route? → Read file from /static → Send HTML response
      │
      ├──► GET /tasks    → Read tasks.json → Send JSON array
      ├──► POST /tasks   → Parse request body → Append to tasks.json → 201 response
      ├──► PATCH /tasks/:id → Read → Find by ID → Toggle status → Write → 200 response
      └──► DELETE /tasks/:id → Read → Filter out by ID → Write → 200 response

Data Flow

Since there is no database, all persistence goes through tasks.json:

Request arrives
      │
      ▼
fs.readFile('tasks.json')      ← Deserialize current state
      │
      ▼
Apply mutation (add/update/delete)
      │
      ▼
fs.writeFile('tasks.json')     ← Serialize updated state
      │
      ▼
Send HTTP response

Logger Integration

The LOGGER/ module is designed to be pulled into the server as a utility. It intercepts request metadata (method, URL, timestamp) and writes it to the console or a log output, inserted before the main route-handling logic.

Module Progression

Basics/     → Learn: require, fs, events, path
LOGGER/     → Apply: custom function that wraps request logging
SERVER/     → Build: createServer, routing, response headers
TODO/       → Integrate: routing + fs I/O + static serving = full app

Getting Started

Prerequisites

  • Node.js v16 or higher
  • npm (optional — no npm install required if no dependencies are present)

Verify your Node.js installation:

node --version

Installation

# Clone the repository
git clone https://github.com/CoderNived/Nodejs.git

# Navigate into the project
cd Nodejs

No npm install step is needed if the project uses only built-in Node.js modules.

Running Locally

Each module can be run independently:

# Explore Basics
node Basics/<filename>.js

# Run the standalone HTTP server
node SERVER/<entry-file>.js

# Run the Logger module
node LOGGER/<entry-file>.js

# Run the full Todo application
node TODO/<entry-file>.js

Replace <entry-file> with the actual entry point filename (e.g., index.js, app.js, or server.js) found inside each directory.

Once the Todo server is running, open your browser at:

http://localhost:<PORT>

The port number will be logged to the console on startup.


Environment Variables

Based on the visible structure, the project does not appear to use a .env file. Configuration values such as port numbers are likely hardcoded as constants in the server entry file.

If you extend the project to use environment variables, a recommended .env.example would be:

PORT=3000
DATA_FILE=./tasks.json

API Endpoints

The following endpoints are inferred from the TODO/ module's purpose and the tasks.json data store. Exact route strings may vary from the source code.

Method Route Purpose Auth Required
GET / Serve the main HTML page (index) No
GET /tasks Retrieve all tasks as JSON array No
POST /tasks Create a new task No
PATCH /tasks/:id Toggle task completion status No
DELETE /tasks/:id Delete a task by ID No

Disclaimer: These routes are inferred from the project's structure and tasks.json data file. Refer to the actual source files in TODO/ for the exact implementation.


Example Request / Response

GET /tasks

Request:

GET /tasks HTTP/1.1
Host: localhost:3000

Response:

[
  { "id": 1, "title": "Buy groceries", "status": false },
  { "id": 2, "title": "Read documentation", "status": true }
]

POST /tasks

Request:

POST /tasks HTTP/1.1
Host: localhost:3000
Content-Type: application/json

{
  "title": "Write unit tests"
}

Response:

{
  "id": 3,
  "title": "Write unit tests",
  "status": false
}

Status: 201 Created

DELETE /tasks/:id

Request:

DELETE /tasks/2 HTTP/1.1
Host: localhost:3000

Response: 200 OK or 204 No Content


Error Handling

Without a framework's built-in error middleware, error handling in a vanilla Node.js server typically follows one of these patterns:

  • 404 Not Found — If no route matches the incoming URL, the server sends a 404 response with a plain-text or JSON error message
  • 405 Method Not Allowed — If the URL matches but the HTTP method does not, a 405 is returned
  • 500 Internal Server Error — If fs.readFile or fs.writeFile throws, the error is caught and a 500 response is emitted
  • Malformed JSON — POST body parsing wraps JSON.parse in a try/catch to handle bad input gracefully

All error responses are expected to include a descriptive message body:

{ "error": "Task not found" }

Security / Authentication

This project does not implement authentication or authorization — it is a learning-focused implementation with no protected routes or session management.

Noted absence of:

  • JWT or session-based auth
  • Password hashing
  • Input sanitization middleware
  • CORS headers
  • HTTPS/TLS configuration

These are deliberate omissions for a fundamentals-focused repository. A production version would require all of the above.


Development Notes

  • No framework = full transparency. Every line that handles a request, parses a body, or sends a response is written explicitly. This is a feature for learning, not a limitation.
  • Synchronous vs. async fs. Depending on the implementation, fs.readFileSync may be used for simplicity. In production, async reads with proper callback or Promise handling (fs.promises) are preferred to avoid blocking the event loop.
  • ID generation. Since there's no database, task IDs are likely generated by incrementing the current max ID in the array or using Date.now(). This is fine for a local application but would need a proper UUID strategy at scale.
  • tasks.json as a database. This is a classic beginner-to-intermediate pattern. It works for single-user, single-process scenarios but is not concurrency-safe and does not scale horizontally.
  • Static serving without a CDN. All HTML is read from disk on every request. A production app would serve static assets via a CDN or a dedicated static file server like nginx.

Possible Improvements

These are realistic next steps a senior engineer would suggest, in order of priority:

  1. Replace JSON file storage with SQLite or MongoDB. A lightweight database removes the concurrency risk and gives proper query capabilities without a heavy infrastructure dependency.
  2. Introduce Express.js. Once the raw HTTP fundamentals are understood, Express dramatically reduces boilerplate and makes the routing logic declarative and maintainable.
  3. Add input validation. Validate incoming request bodies (e.g., ensure title is a non-empty string) before writing to the data store. Libraries like zod or joi make this ergonomic.
  4. Write tests. Add unit tests for route handlers and the logger module using node:test (built-in since Node.js v18) or Jest.
  5. Add proper error logging. The custom LOGGER could be extended to write timestamped entries to a .log file for persistence across sessions.
  6. Introduce environment-based configuration. Move port numbers and file paths into a .env file and use process.env to read them — a basic but important production habit.
  7. Add a proper frontend build. The HTML in static/ is currently served raw. A simple build step (even just a bundler like Vite for local dev) would allow the frontend to grow without becoming unmanageable.
  8. Containerize with Docker. A minimal Dockerfile would make the application portable and deployment-ready.

Conclusion

This repository is a clean, deliberate journey through the parts of Node.js that most developers skip when they jump straight to Express. By building an HTTP server, a logger, and a data-persisted Todo application from scratch using only built-in modules, it demonstrates a genuine understanding of how the Node.js runtime works — not just how to use the tools built on top of it. That foundational fluency is what separates developers who can debug a framework from developers who can only use one.


License

This project is open source. No license file is currently present in the repository.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages