█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Programming Languages/Node.js/File Uploads, Email, and Third-Party APIs
40 minIntermediate

File Uploads, Email, and Third-Party APIs

After this lesson, you will be able to: Handle file uploads (multer), send email (Resend / Nodemailer), call external APIs (fetch).

The three side-quests every real Node app needs.

Prerequisites:Databases from Node

File uploads with multer

For form-data uploads (the legacy approach).

python
import multer from "multer";
import path from "node:path";
const upload = multer({
storage: multer.diskStorage({
destination: "./uploads/",
filename: (_req, file, cb) => cb(null, `${Date.now()}-${file.originalname}`),
}),
limits: { fileSize: 5 * 1024 * 1024 }, // 5MB cap
fileFilter: (_req, file, cb) => {
if (![".jpg", ".png"].includes(path.extname(file.originalname))) {
return cb(new Error("only images"));
}
cb(null, true);
},
});
app.post("/upload", upload.single("image"), (req, res) => {
res.json({ filename: req.file?.filename });
});
// Modern preference: presigned S3 URLs (browser uploads direct).

Email with Resend

Best modern email API for Node.

html
import { Resend } from "resend";
const resend = new Resend(process.env.RESEND_API_KEY);
await resend.emails.send({
from: "[email protected]",
to: "[email protected]",
subject: "Welcome",
html: "<h1>Hello</h1><p>Welcome to our service.</p>",
});
// Always set up SPF, DKIM, DMARC on your sending domain.
// Test with mail-tester.com; aim for 10/10 score.

Calling external APIs with fetch + retries

fetch is global in Node 18+. Add timeout + retry for production.

tsx
async function fetchWithRetry(url, opts = {}, { tries = 3, timeoutMs = 5000 } = {}) {
for (let i = 0; i < tries; i++) {
try {
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), timeoutMs);
const r = await fetch(url, { ...opts, signal: ctrl.signal });
clearTimeout(t);
if (!r.ok) throw new Error(`HTTP ${r.status}`);
return await r.json();
} catch (e) {
if (i === tries - 1) throw e;
await new Promise((res) => setTimeout(res, 2 ** i * 500)); // backoff
}
}
}
// For heavy use: undici (Node's underlying fetch impl) supports connection pooling explicitly.

Common mistakes only experienced Node devs avoid

Trusting user-supplied filenames. Always sanitize or rename. Storing uploads on local disk in cloud deploys. Ephemeral container filesystems lose data. Use S3/R2/Blob. Sending email from `[email protected]` without proper SPF/DKIM/DMARC. Goes to spam. No timeout on fetch. Hangs forever when API is slow.

Quick Check

Why is storing uploads on the local Lambda/container filesystem a bad idea?

Pick the cleanest answer.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←Working with Databases from Node
Back to Node.js
WebSockets and Real-Time→