Sari la conținutul principal

Construiește un manager simplu de sarcini cu categorii folosind Node.js și MongoDB

Învață cum să-ți organizezi sarcinile pe categorii folosind Node.js și MongoDB. Construiește un API REST cu endpointuri de creare, listare, obținere, actualizare, ștergere și filtru după categorie.
Actualizat 10 sept. 2026  · 10 min. citire

Explorează cu AI

ChatGPTClaudePerplexity

O listă simplă de to-do merge perfect la început: adaugi câteva sarcini și le poți bifa după ce le termini. Dar pe măsură ce sarcinile se înmulțesc, devine greu de folosit. Un lucru care poate rezolva asta este adăugarea de categorii, astfel încât fiecare sarcină să aparțină unor categorii precum Work, Study, Personal etc., iar tu să poți filtra lista după categoria dorită.

În acest tutorial, vei învăța cum să construiești un API REST care îți permite să organizezi sarcinile pe categorii folosind Node.js și MongoDB. La final, vei avea un server Node.js funcțional cu cinci endpointuri: create, list, get, update și delete, plus un filtru după categorie. Vei vedea, de asemenea, cum să impui validarea categoriilor folosind driverul nativ MongoDB, fără să te bazezi pe un ODM precum Mongoose.

Ce vei învăța

  • Cum să construiești un API REST cu Node.js, Express și MongoDB, inclusiv endpointuri CRUD complete
  • Cum să validezi inputul, să impui categorii și să gestionezi în siguranță valorile ObjectId
  • Cum să structurezi și să testezi API-ul și apoi să îl conectezi la un frontend

Poți găsi codul complet pentru acest tutorial pe GitHub, dacă preferi să îl clonezi și să citești pe parcurs.

Cerințe preliminare

Înainte să începi, ar trebui să ai:

  • Node.js 18+ instalat (npm este inclus implicit)
  • MongoDB local sau un cluster MongoDB Atlas gratuit
  • Postman sau orice client HTTP
  • Cunoștințe de bază de JavaScript și concepte REST

Pasul 1: Configurează proiectul

Hai să construim managerul nostru simplu de sarcini. Mai întâi vom crea un folder nou și vom inițializa un proiect Node rulând comenzile de mai jos în terminal:

mkdir task-manager-categories
cd task-manager-categories
npm init -y

Apoi vom instala cele patru dependențe runtime de care are nevoie aplicația: express pentru rutare, driverul oficial MongoDB, dotenv pentru încărcarea variabilelor de mediu și, în final, helmet pentru antete de securitate.

npm install express mongodb dotenv helmet

Pentru dezvoltare, instalează nodemon ca dependență de dev cu comanda de mai jos, astfel încât serverul să se reîncarce automat când se schimbă fișierele:

npm install --save-dev nodemon

Apoi, deschide folderul proiectului în IDE și actualizează secțiunea scripts din package.json pentru a include următoarele. Astfel poți porni serverul cu npm start sau îl poți rula în modul de dezvoltare cu npm run dev:

"scripts": {
  "start": "node server.js",
  "dev": "nodemon server.js"
}

Iată structura pe care o vom construi pe parcurs. Fiecare folder are un rol clar: db/ se ocupă de conexiunea la bază, lib/ conține funcții helper, middleware/ este pentru middleware Express, iar routes/ definește handler-ele pentru requesturi. Folderul public/ va conține un mic frontend pe care îl vom adăuga mai târziu. Chiar și într-un proiect mic, această structură menține lucrurile ușor de urmărit și clarifică unde să adaugi cod nou. Poți crea acum scheletul de foldere și să-l completezi pe parcurs sau poți sări peste asta și să adaugi fiecare fișier pe măsură ce parcurgem pașii:

task-manager-categories/
├── db/
│ └── connect.js
├── lib/
│ └── taskDocument.js
├── middleware/
│ └── parseObjectId.js
├── routes/
│ └── tasks.js
├── public/
│ ├── index.html
│ ├── styles.css
│ └── app.js
├── .env
├── .env.example
├── .gitignore
├── package.json
└── server.js

Pasul 2: Conectează-te la MongoDB

Pentru a stoca și a prelua sarcini, mai întâi trebuie să conectăm aplicația la MongoDB. Asta se face folosind un connection string, care îi spune driverului MongoDB cum să se conecteze la baza ta de date. În loc să îl pui direct în cod, e mai bine să-l păstrezi într-un fișier de mediu. Astfel, valorile sensibile rămân în afara codului și e mai ușor să comuți între medii.

Creează un fișier .env.example pentru a documenta variabilele necesare și un fișier .env pentru valorile tale reale, astfel:

# Copy this file to `.env` and fill in real values.

# --- Local MongoDB ---
# Use this if you're running MongoDB locally
MONGO_URI=mongodb://127.0.0.1:27017

# --- MongoDB Atlas ---
# Replace <username>, <password>, and <cluster-url> with your actual values
# Example: mongodb+srv://user:pass@cluster0.abcde.mongodb.net/
# MONGO_URI=mongodb+srv://<username>:<password>@<cluster-url>/?retryWrites=true&w=majority

DB_NAME=taskmanager
PORT=3000

Acum că avem un connection string, îl putem folosi pentru a configura conexiunea la MongoDB. Creează un fișier db/connect.js. Aici vom inițializa clientul MongoDB și îl vom face disponibil în restul aplicației:

const { MongoClient } = require("mongodb");

let client;
let db;

async function connectDB() {
  if (!process.env.MONGO_URI) {
    throw new Error("MONGO_URI is not set. Check your .env file.");
  }
  client = new MongoClient(process.env.MONGO_URI, {
    appName: "devrel-tutorial-javascript-crud-geeksforgeeks",
  });
  await client.connect();
  db = client.db(process.env.DB_NAME || "taskmanager");
  await db.collection("tasks").createIndex({ category: 1 });

  console.log(`MongoDB connected (db: ${db.databaseName})`);
}

function getTasksCollection() {
  if (!db) {
    throw new Error("Database not initialized. Call connectDB() first.");
  }
  return db.collection("tasks");
}

async function closeDB() {
  if (client) await client.close();
}

module.exports = { connectDB, getTasksCollection, closeDB };

Acest fișier configurează un singur client MongoDB pe care îl poate reutiliza restul aplicației. Vrei să-l creezi o singură dată, deoarece driverul se ocupă deja de connection pooling. Crearea unui client nou la fiecare request poate părea ok la început, dar va cauza destul de repede probleme de performanță.

Pasul 3: Definește structura și validarea sarcinii

În acest punct, aplicația se poate conecta la MongoDB. Acum trebuie să definim cum arată, de fapt, o sarcină înainte să începem să salvăm ceva.

Aici folosirea driverului nativ MongoDB începe să se simtă puțin diferit. Nu există un fișier de schemă ca în Mongoose. În schimb, „schema” este pur și simplu forma obiectului pe care îl inserezi în bază. Poate părea mai lejer la început, dar e util, pentru că rămâi aproape de cum funcționează MongoDB în realitate, fără abstracții care ascund detalii.

Totuși, vrem în continuare validare. Așa că, în loc să împrăștiem logica prin rute diferite, o vom păstra într-un singur loc, astfel încât totul să urmeze aceleași reguli. Creează un fișier numit lib/taskDocument.js și adaugă codul de mai jos:

class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = 'ValidationError';
  }
}

const ALLOWED_CATEGORIES = ['Work', 'Personal', 'Study', 'Other'];

function assertValidCategory(category) {
  if (!ALLOWED_CATEGORIES.includes(category)) {
    throw new ValidationError(
      `category must be one of: ${ALLOWED_CATEGORIES.join(', ')}`
    );
  }
}

function buildTaskDocument(body = {}) {
  if (!body.title || typeof body.title !== 'string' || !body.title.trim()) {
    throw new ValidationError('title is required and must be a non-empty string');
  }
  if (body.category != null) {
    assertValidCategory(body.category);
  }
  const now = new Date();
  return {
    title: body.title.trim(),
    description: typeof body.description === 'string' ? body.description.trim() : '',
    category: body.category != null ? body.category : 'Other',
    completed: Boolean(body.completed),
    createdAt: now,
    updatedAt: now
  };
}

function buildTaskUpdate(body = {}) {
  const updates = {};
  if (typeof body.title === 'string' && body.title.trim()) {
    updates.title = body.title.trim();
  }
  if (typeof body.description === 'string') {
    updates.description = body.description.trim();
  }
  if (body.category != null) {
    assertValidCategory(body.category);
    updates.category = body.category;
  }
  if (body.completed != null) {
    updates.completed = Boolean(body.completed);
  }
  if (Object.keys(updates).length === 0) {
    throw new ValidationError('no valid fields provided for update');
  }
  updates.updatedAt = new Date();
  return updates;
}

module.exports = {
  ALLOWED_CATEGORIES,
  buildTaskDocument,
  buildTaskUpdate,
  ValidationError
};

Acest fișier acționează ca un portar pentru orice ajunge în baza ta de date. Fiecare cerere de creare sau actualizare trece pe aici, astfel încât regulile sunt impuse într-un singur loc.

Se asigură că sarcinile au mereu forma corectă, păstrează categoriile consecvente și evită surprizele atunci când începi să interoghezi datele. ValidationError personalizat îți oferă și o modalitate clară de a separa inputul greșit de problemele reale ale serverului, astfel încât API-ul tău să poată răspunde adecvat. Cu asta pus la punct, restul aplicației poate rămâne simplu. Fiecare rută se poate concentra pe treaba ei, știind că datele primite sunt deja valide. Următorul pas: conectăm rutele și începem să salvăm sarcini în MongoDB.

Pasul 4: Gestionează ObjectId și validarea cererilor

Acum că știm cum arată o sarcină, să vedem cum o referim. Ori de câte ori o rută include un parametru :id, acesta vine ca un string simplu. Dar MongoDB se așteaptă la un ObjectId. Dacă stringul e greșit formatat, driverul aruncă o eroare destul de neclară. În loc să gestionăm asta în fiecare rută, vom centraliza prin middleware, astfel încât fiecare endpoint să se comporte la fel.

Pentru asta, creează un fișier numit middleware/parseObjectId.js și adaugă următoarele:

const { ObjectId } = require('mongodb');

function parseObjectId(req, res, next) {
  const { id } = req.params;
  if (!ObjectId.isValid(id)) {
    return res.status(400).json({ error: 'invalid task id' });
  }
  req.taskId = new ObjectId(id);
  next();
}

module.exports = parseObjectId;

Acest middleware rulează înaintea handlerului de rută. Verifică dacă id este valid, îl convertește într-un ObjectId și îl atașează la req.taskId. Astfel, până ajunge logica din rută să ruleze, lucrezi deja cu un ObjectId corect, iar inputurile greșite sunt respinse devreme cu un răspuns clar 400. În continuare, îl vom conecta la rutele noastre și vom pune totul cap la cap.

Pasul 5: Construiește rutele pentru sarcini (CRUD + filtrare)

În acest punct, mare parte din treabă e deja făcută. Am definit cum arată o sarcină validă și am gestionat modul în care ID-urile sunt analizate și validate. Asta înseamnă că handler-ele de rute se pot concentra pe un singur lucru: să vorbească cu baza de date.

Hai să construim rutele reale ale API-ului, creând un fișier numit routes/tasks.js și adăugând următoarele:

const express = require('express');
const { getTasksCollection } = require('../db/connect');
const {
  ALLOWED_CATEGORIES,
  buildTaskDocument,
  buildTaskUpdate,
  ValidationError
} = require('../lib/taskDocument');
const parseObjectId = require('../middleware/parseObjectId');

const router = express.Router();

// POST /tasks
router.post('/', async (req, res, next) => {
  try {
    const doc = buildTaskDocument(req.body);
    const result = await getTasksCollection().insertOne(doc);
    res.status(201).json({ _id: result.insertedId, ...doc });
  } catch (err) {
    if (err instanceof ValidationError) {
      return res.status(400).json({ error: err.message });
    }
    next(err);
  }
});

// GET /tasks (optionally ?category=Work)
router.get('/', async (req, res, next) => {
  try {
    const { category } = req.query;
    if (category && !ALLOWED_CATEGORIES.includes(category)) {
      return res.status(400).json({
        error: `category must be one of: ${ALLOWED_CATEGORIES.join(', ')}`
      });
    }
    const filter = category ? { category } : {};
    const tasks = await getTasksCollection()
      .find(filter)
      .sort({ createdAt: -1 })
      .toArray();
    res.json(tasks);
  } catch (err) { next(err); }
});

// GET /tasks/:id
router.get('/:id', parseObjectId, async (req, res, next) => {
  try {
    const task = await getTasksCollection().findOne({ _id: req.taskId });
    if (!task) return res.status(404).json({ error: 'task not found' });
    res.json(task);
  } catch (err) { next(err); }
});

// PUT /tasks/:id
router.put('/:id', parseObjectId, async (req, res, next) => {
  try {
    const updates = buildTaskUpdate(req.body);
    const result = await getTasksCollection().findOneAndUpdate(
      { _id: req.taskId },
      { $set: updates },
      { returnDocument: 'after' }
    );
    if (!result) return res.status(404).json({ error: 'task not found' });
    res.json(result);
  } catch (err) {
    if (err instanceof ValidationError) {
      return res.status(400).json({ error: err.message });
    }
    next(err);
  }
});

// DELETE /tasks/:id
router.delete('/:id', parseObjectId, async (req, res, next) => {
  try {
    const result = await getTasksCollection().deleteOne({ _id: req.taskId });
    if (result.deletedCount === 0) {
      return res.status(404).json({ error: 'task not found' });
    }
    res.status(204).end();
  } catch (err) { next(err); }
});

module.exports = router;

Fiecare rută din codul de mai sus urmează același tipar: ia inputul din request, îl trece prin helper-ele construite anterior, apelează MongoDB și apoi returnează un răspuns. Cu validarea și parsarea ID-ului deja gestionate, codul rămâne scurt și previzibil. În practică, iată cum funcționează:

  • Ruta POST construiește o sarcină nouă folosind buildTaskDocument înainte de a o insera
  • Rutele GET filtrează opțional după categorie și returnează rezultatele sortate de la cele mai noi
  • Ruta PUT folosește buildTaskUpdate, astfel încât actualizările parțiale sunt sigure și consecvente
  • Ruta DELETE elimină o sarcină după ObjectId deja analizat

Mai sunt câteva detalii în acest cod care merită menționate:

  • find() returnează un cursor, nu un array, așa că înlănțuim .toArray() după sortare pentru a obține efectiv rezultatele
  • findOneAndUpdate cu returnDocument: 'after' îți oferă imediat documentul actualizat
  • Returnăm coduri HTTP corecte: 201 pentru creare, 204 pentru ștergere și 400 sau 404 acolo unde e cazul
  • Erorile neașteptate sunt transmise către next(err), pentru a fi gestionate într-un singur loc, nu în fiecare rută

Pasul 6: Conectează totul în server

Acum toate piesele sunt la locul lor. Avem validare, rute curate și o conexiune funcțională la bază. Mai trebuie doar să legăm totul și să pornim serverul. Creează un fișier server.js. Acesta este punctul de intrare al aplicației, unde se adună toate:

require('dotenv').config();

const path = require('path');
const express = require('express');
const helmet = require('helmet');
const { connectDB, closeDB } = require('./db/connect');
const tasksRouter = require('./routes/tasks');

if (!process.env.MONGO_URI) {
  console.error('Fatal: MONGO_URI is not set. Copy .env.example to .env and fill it in.');
  process.exit(1);
}

const PORT = Number(process.env.PORT) || 3000;

const app = express();

app.use(helmet());
app.use(express.json({ limit: '100kb' }));
app.use(express.static(path.join(__dirname, 'public')));

app.get('/health', (req, res) => {
  res.json({ status: 'ok', service: 'task-manager-with-categories' });
});
app.use('/tasks', tasksRouter);

app.use((req, res) => {
  res.status(404).json({ error: 'not found' });
});

app.use((err, req, res, next) => {
  if (err.type === 'entity.too.large') {
    return res.status(413).json({ error: 'payload too large' });
  }
  if (err.type === 'entity.parse.failed') {
    return res.status(400).json({ error: 'invalid JSON body' });
  }
  console.error(err);
  res.status(500).json({ error: 'internal server error' });
});

async function start() {
  try {
    await connectDB();
    const server = app.listen(PORT, () => {
      console.log(`Server running on http://localhost:${PORT}`);
    });

    const shutdown = () => {
      console.log('\nShutting down gracefully...');
      server.close(async () => {
        await closeDB();
        process.exit(0);
      });
      setTimeout(() => process.exit(1), 10_000).unref();
    };
    process.on('SIGINT', shutdown);
    process.on('SIGTERM', shutdown);
  } catch (err) {
    console.error('Failed to start server:', err);
    process.exit(1);
  }
}

if (require.main === module) {
  start();
}

module.exports = { app, start };

Acest fișier pune totul cap la cap într-un mod curat. Verifică dacă variabilele de mediu sunt setate înainte de a rula orice, aplică securitate de bază cu helmet și limitează JSON-ul primit, astfel încât aplicația ta să nu accepte din greșeală payloaduri uriașe. De asemenea, servește folderul public/, astfel încât frontendul să poată rula în aceeași aplicație, fără un server separat.

Toate rutele tale sunt montate sub /tasks, iar orice nu se potrivește returnează un 404 curat. Erorile sunt gestionate într-un singur loc, nu repetate în fiecare rută, ceea ce păstrează consecvența și mentenanța ușoară. Conexiunea la bază este stabilită înainte ca serverul să înceapă să asculte, astfel încât nu accepți cereri înainte de a fi pregătit, iar oprirea este gestionată grațios, închizând corect conexiunile.

Acum pornește totul și verifică dacă funcționează rulând npm run dev. Dacă totul este conectat corect, ar trebui să vezi ceva de genul:

MongoDB connected (db: taskmanager)
Server running on http://localhost:3000

În acest punct, totul este pornit și funcțional! Avem acum un API complet funcțional, așa că hai să îl testăm.

Pasul 7: Testează endpointurile API-ului

Înainte de a construi o interfață, merită să confirmi că fiecare endpoint funcționează de unul singur. Asta face depanarea mult mai ușoară, deoarece poți spune rapid dacă o problemă vine din API sau din frontend. Vom folosi Postman (sau orice client HTTP) și vom rula câteva cereri în ordine. Fiecare se bazează pe datele create de pasul anterior.

Creează o sarcină: Trimite o cerere POST cu un title, description și category. Dacă totul merge, API-ul returnează 201 Created cu noua sarcină și _id generat.

POST http://localhost:3000/tasks
Content-Type: application/json

{
  "title": "Write GeeksForGeeks article",
  "description": "First draft by Friday",
  "category": "Work"
}

Creează câteva în plus: Rulează aceeași cerere POST cu corpuri diferite, ca să ai destule date pentru listare și filtrare. După asta, vei avea un mic set de date pentru interogare.

{ "title": "Go for a run", "category": "Personal" }
{ "title": "Read MongoDB docs", "category": "Study" }
{ "title": "Buy groceries" } // category defaults to "Other"

Listează toate sarcinile: Aceasta returnează toate sarcinile, sortate de la cele mai noi.

GET http://localhost:3000/tasks

Filtrează după categorie: Aceasta returnează doar sarcinile din Work. Indexul adăugat mai devreme menține această interogare rapidă pe măsură ce datele cresc.

GET http://localhost:3000/tasks?category=Work

Actualizează o sarcină: Folosește _id de la una dintre sarcinile tocmai create (îl poți copia din răspunsul la POST sau din endpointul de listare). Aceasta returnează sarcina actualizată. Trebuie să trimiți doar câmpurile pe care vrei să le schimbi, astfel încât actualizările parțiale rămân simple.

PUT http://localhost:3000/tasks/<paste-task-id-here>
Content-Type: application/json

{ "completed": true }

Șterge o sarcină: Folosește _id de la sarcina pe care vrei să o ștergi. Aceasta returnează 204 No Content. Dacă încerci să obții din nou aceeași sarcină, vei primi un 404 cu "task not found".

DELETE http://localhost:3000/tasks/<paste-task-id-here>

În acest punct, ai confirmat că toate rutele se comportă așa cum trebuie. API-ul își face treaba, așa că putem trece la construirea unei interfețe peste el.

Pasul 8: Adaugă un frontend pentru a interacționa cu API-ul

Postman e grozav pentru a verifica API-ul, dar ar fi plăcut să vezi cum funcționează pe un site real, așa că hai să adăugăm ceva cod de frontend în aplicație.

În loc să lipesc aici fișiere HTML și CSS mari, am adăugat codul în acest repo GitHub. Mergi acolo și copiază conținutul fișierelor index.html, styles.css și favicon.svg în folderul public/ din rădăcina proiectului tău. Salvează modificările și apoi mergi la localhost:3000. Apoi lipește codul de mai jos în fișierul app.js:

const form = document.getElementById('task-form');
const titleEl = document.getElementById('title');
const descEl = document.getElementById('description');
const catEl = document.getElementById('category');
const errEl = document.getElementById('form-error');
const listEl = document.getElementById('task-list');
const emptyEl = document.getElementById('empty');
const filterEl = document.getElementById('filter');
const countEl = document.getElementById('task-count');

async function api(method, path, body) {
  const res = await fetch(path, {
    method,
    headers: body ? { 'Content-Type': 'application/json' } : {},
    body: body ? JSON.stringify(body) : undefined
  });

  if (res.status === 204) return null;

  const data = await res.json();
  if (!res.ok) throw new Error(data.error || `Request failed (${res.status})`);
  return data;
}

const fetchTasks = (category) =>
  api('GET', '/tasks' + (category ? `?category=${encodeURIComponent(category)}` : ''));

const createTask = (body) => api('POST', '/tasks', body);
const updateTask = (id, body) => api('PUT', `/tasks/${id}`, body);
const deleteTask = (id) => api('DELETE', `/tasks/${id}`);

function updateCount(tasks) {
  const active = tasks.filter((t) => !t.completed).length;
  const total = tasks.length;

  if (total === 0) {
    countEl.textContent = '';
    return;
  }

  const scope = filterEl.value ? ` in ${filterEl.value}` : '';
  countEl.textContent = `${total} tasks${scope} · ${active} active`;
}

function renderTask(task) {
  const li = document.createElement('li');
  li.className = 'task' + (task.completed ? ' completed' : '');

  const checkbox = document.createElement('input');
  checkbox.type = 'checkbox';
  checkbox.checked = task.completed;
  checkbox.addEventListener('change', () =>
    updateTask(task._id, { completed: checkbox.checked }).then(refresh)
  );

  const title = document.createElement('div');
  title.textContent = task.title;

  const badge = document.createElement('span');
  badge.textContent = task.category;

  const del = document.createElement('button');
  del.textContent = 'Delete';
  del.onclick = () => deleteTask(task._id).then(refresh);

  li.append(checkbox, title, badge, del);
  return li;
}

function render(tasks) {
  listEl.innerHTML = '';
  emptyEl.classList.toggle('hidden', tasks.length > 0);

  for (const task of tasks) {
    listEl.appendChild(renderTask(task));
  }

  updateCount(tasks);
}

async function refresh() {
  try {
    const tasks = await fetchTasks(filterEl.value);
    render(tasks);
  } catch (e) {
    errEl.textContent = e.message;
  }
}

form.addEventListener('submit', async (e) => {
  e.preventDefault();
  errEl.textContent = '';

  const title = titleEl.value.trim();
  if (!title) {
    errEl.textContent = 'Title is required.';
    return;
  }

  try {
    await createTask({
      title,
      description: descEl.value.trim(),
      category: catEl.value
    });

    form.reset();
    await refresh();
  } catch (e) {
    errEl.textContent = e.message;
  }
});

filterEl.addEventListener('change', refresh);

refresh();

Codul JavaScript este locul în care totul se reconectează la API-ul pe care l-ai construit. Fiecare funcție corespunde uneia dintre rutele tale, ceea ce păstrează frontendul ușor de urmărit. Toate cererile trec și printr-un singur helper api(), astfel încât gestionezi erorile într-un singur loc, nu repeți aceeași logică peste tot.

Filtrarea funcționează prin trecerea unui query string precum ?category=Work, care se leagă direct de logica din backend pe care ai adăugat-o deja. După crearea, actualizarea sau ștergerea unei sarcini, aplicația preia din nou lista actualizată, astfel încât UI-ul rămâne în sincron. Contorul de sarcini e un detaliu mic, dar face aplicația să pară mai vie în utilizare.

Acum repornește serverul cu npm run dev, apoi deschide http://localhost:3000 pentru a încerca Task Manager-ul. Adaugă câteva sarcini, actualizează-le, comută între categorii și șterge unele. În acest punct, frontendul și backendul sunt complet conectate și funcționează cap-coadă.

Rezumat

Felicitări! Ai construit cu succes un API complet pentru gestionarea sarcinilor de la zero folosind Node.js, Express și MongoDB. Ai gestionat validarea, ai păstrat rutele concise și ai conectat totul într-un sistem funcțional. Mai important, ai rămas aproape de modul în care funcționează efectiv MongoDB, fără a ascunde totul în spatele abstracțiilor. De aici, poți începe să evoluezi aplicația pentru producție.

Idei principale

  • Folosirea middleware-ului și centralizarea validării îți păstrează codul curat și previzibil.
  • Driverul nativ MongoDB îți oferă control fără abstracții inutile.
  • Un API bine structurat e ușor de extins într-o aplicație gata de producție.

Întrebări frecvente

Am nevoie de Mongoose pentru a construi un API MongoDB?

Nu. Acest tutorial folosește driverul nativ MongoDB, care îți oferă mai mult control și păstrează lucrurile suple. Poți adăuga Mongoose mai târziu dacă vrei abstracții de tip schemă.

Cum validez datele fără o schemă?

Poți centraliza validarea în funcții helper (cum ar fi buildTaskDocument), asigurându-te că fiecare rută impune aceleași reguli înainte de a scrie în bază.

Ce se întâmplă dacă trimit un ObjectId invalid?

Middleware-ul o respinge devreme cu un răspuns 400, prevenind erori confuze aruncate de MongoDB.

Subiecte
MongoDB

Top cursuri DataCamp

course

Introducere în MongoDB cu Python

3 oră
24.2K
Învață să manipulezi și să analizezi date cu structură flexibilă cu MongoDB.
Vezi detaliiRight Arrow
Începeți Cursul
Vezi mai multRight Arrow