Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/midudev/jscamp/llms.txt

Use this file to discover all available pages before exploring further.

En este módulo exploramos las APIs nativas de Node.js sin ningún framework externo. Aprenderás a construir un servidor HTTP completo desde cero, manipular el sistema de archivos con permisos granulares, obtener información del sistema operativo y comprender las diferencias entre los sistemas de módulos CommonJS y ESM.

Lo que aprenderás

  • node:http — crear un servidor HTTP raw con routing manual
  • node:crypto — generar UUIDs únicos con randomUUID()
  • node:stream/consumers — leer el body de requests con json()
  • node:fs/promises — operaciones de archivos asíncronas con permisos
  • node:path — manipulación de rutas de forma portable
  • node:os — información del sistema operativo y CPU
  • CommonJS vs ESM — diferencias entre require() y import/export
  • Scripts CLI — leer argumentos con process.argv y listar directorios

Estructura del Módulo

04-node/
├── server.js          # Servidor HTTP completo con routing, paginación y CRUD
├── manage-files.js    # Operaciones de sistema de archivos con permisos
├── system-info.js     # Información del SO con node:os y la librería ms
├── cli.js             # Script CLI para listar archivos de un directorio
├── index.js           # Ejemplo de módulo ESM con import/export
├── commonjs.js        # Ejemplo de módulo CommonJS con require/module.exports
├── math.js            # Módulo auxiliar exportado con ESM
├── archivo.txt        # Archivo de prueba para manage-files.js
└── .env               # Variables de entorno (PORT=1234)

Servidor HTTP desde Cero

El archivo server.js implementa un servidor HTTP completo usando únicamente node:http, sin Express ni ningún framework. Esto permite entender cómo funcionan internamente los frameworks web.

Punto de entrada y helper de respuesta

import { createServer } from 'node:http'
import { randomUUID } from 'node:crypto'
import { json } from 'node:stream/consumers'

process.loadEnvFile()

const port = process.env.PORT ?? 3000

function sendJson(res, statusCode, data) {
  res.statusCode = statusCode
  res.setHeader('Content-Type', 'application/json; charset=utf-8')
  res.end(JSON.stringify(data))
}
La función sendJson actúa como helper para evitar repetir la lógica de serialización y cabeceras en cada endpoint.

Routing manual con GET

const server = createServer(async (req, res) => {
  const { method, url } = req

  const [pathname, querystring] = url.split('?')
  const searchParams = new URLSearchParams(querystring)

  if (method === 'GET') {
    if (pathname === '/users') {
      const limit = Number(searchParams.get('limit')) || users.length
      const offset = Number(searchParams.get('offset')) || 0

      const paginatedUsers = users.slice(offset, offset + limit)
      return sendJson(res, 200, paginatedUsers)
    }

    if (pathname === '/health') {
      return sendJson(res, 200, { status: 'ok', uptime: process.uptime() })
    }

    if (pathname === '/cookies') {
      res.setHeader('Set-Cookie', 'token=abc123; HttpOnly; Path=/; Max-Age=3600')
      return res.end('Cookies set')
    }
  }
El routing se implementa manualmente comparando method y pathname. Los query params (limit, offset) se parsean con URLSearchParams para implementar paginación sin dependencias externas.

Endpoint POST con lectura del body

  if (method === 'POST') {
    if (pathname === '/users') {
      const body = await json(req)

      if (!body || !body.name) {
        return sendJson(res, 400, { error: 'Name is required' })
      }

      const newUser = {
        name: body.name,
        id: randomUUID(),
      }

      users.push(newUser)
      return sendJson(res, 201, { message: 'Usuario creado' })
    }
  }

  return sendJson(res, 404, { error: 'Not Found' })
})

server.listen(port, () => {
  const address = server.address()
  console.log(`Servidor escuchando en http://localhost:${address.port}`)
})
La función json() de node:stream/consumers permite leer y parsear el body de forma nativa, sin necesitar body-parser ni Express. Los IDs se generan con crypto.randomUUID(), también nativo de Node.js.
El servidor incluye los endpoints GET /health (uptime del proceso), GET /users (con paginación ?limit= y ?offset=), POST /users (crear usuario) y GET /cookies (demostración de Set-Cookie).

Módulos Nativos de Node.js

Gestión de archivos con node:fs

El archivo manage-files.js demuestra cómo usar permisos granulares de Node.js (--allow-read, --allow-write) antes de operar con el sistema de archivos:
import { mkdir, readFile, writeFile } from 'node:fs/promises'
import { join, basename, extname } from 'node:path'

let content = ''

if (process.permission.has('fs.read', 'archivo.txt')) {
  content = await readFile('archivo.txt', 'utf-8')
  console.log(content)
} else {
  console.log('No tienes permiso para leer el archivo.')
}

if (process.permission.has('fs.write', 'output/files/documents')) {
  const outputDir = join('output', 'files', 'documents')
  await mkdir(outputDir, { recursive: true })

  const uppercaseContent = content.toUpperCase()
  const outputFilePath = join(outputDir, 'archivo-uppercase.txt')

  console.log('La extensión es: ', extname(outputFilePath))
  console.log('El nombre del archivo es: ', basename(outputFilePath))

  await writeFile(outputFilePath, uppercaseContent)
  console.log('Archivo creado con contenido en mayúsculas')
} else {
  console.log('No tienes permiso para escribir en el directorio especificado.')
}
process.permission.has() es parte del Permission Model de Node.js (v20+). Permite verificar en tiempo de ejecución si el proceso tiene acceso a un recurso específico antes de intentar usarlo.

Información del sistema con node:os

El archivo system-info.js utiliza el módulo node:os para exponer métricas del sistema operativo:
import os from 'node:os'
import ms from 'ms'

console.log('Tipo de SO:', os.type())
console.log('Plataforma:', os.platform())
console.log('Arquitectura:', os.arch())
console.log('Memoria total (bytes):', os.totalmem())
console.log('Memoria libre (bytes):', os.freemem())
console.log('Directorio home del usuario:', os.homedir())
console.log('Tiempo de actividad del sistema:', ms(os.uptime() * 1000, { long: true }))

console.log('-----------------------------------')
console.log('CPUS:', os.cpus())
console.log('-----------------------------------')
La única dependencia externa (ms) convierte milisegundos a formato legible como "2 hours" o "3 days".

CommonJS vs ESM

Node.js soporta dos sistemas de módulos. El archivo commonjs.js ilustra la sintaxis CommonJS (la original de Node.js):
// commonjs.js
const { sum } = require('./math')

const result = sum(2, 3)
console.log(`The sum of 2 and 3 is: ${result}`)

/* en math.js */
const sum = (a, b) => a + b
module.exports = { sum }

CommonJS

  • Sintaxis: require() / module.exports
  • Carga síncrona
  • Default en Node.js histórico
  • Extensión .js o .cjs
  • No necesita "type": "module" en package.json

ESM (ES Modules)

  • Sintaxis: import / export
  • Carga asíncrona (top-level await soportado)
  • Estándar moderno (igual que en el navegador)
  • Extensión .js con "type": "module" o .mjs
  • Requerido en este módulo ("type": "module")

Cómo Ejecutar

1

Posiciónate en el directorio

cd 04-node
2

Instala las dependencias

npm install
3

Arranca el servidor

node server.js
4

Prueba los endpoints

# Listar usuarios con paginación
curl "http://localhost:1234/users?limit=3&offset=0"

# Crear un usuario
curl -X POST http://localhost:1234/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Carlos"}'

# Health check
curl http://localhost:1234/health
El archivo .env del proyecto define PORT="1234". Node.js lo carga automáticamente con process.loadEnvFile() (disponible desde Node.js v20.6), sin necesidad de instalar dotenv.

Build docs developers (and LLMs) love