A simple Node.js project to log your daily learning entries. This project demonstrates core Node.js concepts such as environment variables, file system operations, routing, and serving static files.
- Project Overview
- Getting Started
- Environment Variables
- Why Use the
pathModule? - Handling Directory Paths in Node.js
- CORS and OPTIONS Preflight Requests
- Routing and URL Parsing
- API vs Static File Routing
- Project Structure
Dev Journal is a Node.js application that allows you to record and view daily learning entries. It uses a simple JSON file as a database and serves both API endpoints and static HTML/CSS files.
- Clone the repository
- Install dependencies (if any)
- Set up your
.envfile (see below) - Run the server:
node index.js
- Visit http://localhost:9000 (or your configured port)
This pattern sets the port number for your server:
const PORT = process.env.PORT || 3000;process.env.PORT: Uses the port defined in your environment (e.g., by cloud providers like Heroku, AWS, Azure).3000: Fallback default if no environment variable is set.
Why is this important?
- Cloud providers dynamically assign ports at runtime.
- Hardcoding a port (like 3000) can cause your app to crash on deployment.
- Using
.envfiles lets you easily switch between development, testing, and production environments without changing your source code.
File paths differ across operating systems:
- Windows:
data\entries.json - Mac/Linux:
data/entries.json
Hardcoding / or \ can break your code on another OS. The Node.js path module ensures your file paths are always correct, regardless of the platform.
const __dirname = import.meta.dirname;
const __filename = import.meta.filename;import { fileURLToPath } from "url";
import path from "path";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);This ensures compatibility and correct path resolution in all environments.
When making POST, PUT, or DELETE requests from a browser, an OPTIONS preflight request is sent first. If your server doesn't handle this, requests from real frontends will fail.
Example handling:
if (req.method === "OPTIONS") {
res.writeHead(204, {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
});
res.end();
return;
}This enables cross-origin requests and ensures smooth API communication.
To determine which route a user is visiting, Node.js uses the URL object:
const requestUrl = new URL(req.url, `http://${req.headers.host}`);
const pathname = requestUrl.pathname;req.url: The requested path (e.g.,/about?name=favour)req.headers.host: The domain and port (e.g.,localhost:3000)pathname: Extracts just the path, without query parameters.
| Full URL | Pathname |
|---|---|
| http://localhost:3000/ | / |
| http://localhost:3000/about | /about |
| http://localhost:3000/user?id=5 | /user |
This makes route handling clean and robust.
In routes.js:
- API routes (e.g.,
/api/entries) must be handled before static file routes. - Static files (HTML, CSS) are served for paths like
/,/entries.html,/style.css. - Unmatched routes return a 404 JSON error.
.env
.gitignore
index.js
package.json
Readme.md
routes.js
controllers/
entryController.js
data/
entries.json
public/
entries.html
index.html
style.css
utils/
helper.js
- controllers/: API logic (reading/writing entries)
- data/: JSON "database"
- public/: Static HTML/CSS files
- utils/: Helper functions (responses, static file serving)
Happy journaling!