今日已更新 240 条资讯 | 累计 23823 条内容
关于我们

标签:#express

找到 12 篇相关文章

AI 资讯

The x-tenant-id Pattern: Multi-Tenant API Without Multi-Tenant Complexity

When you're building a multi-tenant SaaS, the first architectural question is usually: how do you keep tenant data isolated? The options range from separate databases per tenant (maximum isolation, maximum cost) to a shared database with row-level filtering (minimum cost, more careful coding required). But there's an equally important question that gets less attention: how does your API know which tenant context a request belongs to? This post covers a pattern we've used in production: a custom request header for tenant scoping, combined with JWT authentication. Simple to implement, easy to audit, and flexible enough to support multi-tenant access from a single user account. The Three Common Approaches 1. Subdomain-based ( tenant.yourdomain.com ) The tenant is encoded in the hostname. Each subdomain routes to the same backend, which extracts the tenant from the Host header. Good: Intuitive, visible in the URL. Bad: Requires wildcard TLS certs, more complex DNS setup, awkward in development, doesn't work for mobile API clients the same way. 2. URL path-based ( /api/tenants/{tenantId}/... ) The tenant identifier is part of every route path. Good: RESTful, self-documenting. Bad: Bloats all route definitions, requires every endpoint to include the tenant segment, makes API versioning messier. 3. Header-based ( x-tenant-id: <id> ) A custom header carries the tenant context. Routes stay clean. The tenant scope is resolved in middleware before the handler runs. Good: Routes stay simple, middleware handles scoping uniformly, works well with JWT auth, easy to test. Bad: Less visible (the tenant isn't in the URL), requires clients to always include the header. We use the header approach. The Implementation The API accepts two forms of auth: A JWT token in the Authorization header — identifies who is making the request A tenant ID in the x-tenant-id header — identifies on behalf of which tenant POST /api/v1/members Authorization: Bearer eyJhbGciOiJIUzI1NiIs... x-tenant-id: ten

2026-07-24 原文 →
AI 资讯

Request validation with Zod in Express

Express does not validate request input for you. Without a check at the edge, handlers get raw req.body , req.query , and req.params - strings where you expected numbers, missing fields, and shapes that only blow up deep in business logic. Zod is a TypeScript-first schema library. You declare the shape once, infer types with z.infer , and parse at the HTTP boundary so route handlers only see valid data. Invalid input becomes HTTP 400 before your code runs. This post covers Zod 4 schemas ( z.email() , z.uuid() , z.coerce ), Express validation middleware, error formatting and pitfalls. Prerequisites Node.js version 26 Zod 4: npm i zod Express: npm i express and npm i -D @types/express Zod 3 method forms like z.string().email() still work but are deprecated in v4. Prefer the top-level APIs below. Schemas // schemas.ts import { z } from ' zod ' ; export const createUserSchema = z . object ({ email : z . email (), name : z . string (). min ( 1 ). max ( 100 ), age : z . number (). int (). min ( 0 ). max ( 150 ). optional () }); export type CreateUserInput = z . infer < typeof createUserSchema > ; export const userIdParamSchema = z . object ({ id : z . uuid () }); export const listUsersQuerySchema = z . object ({ limit : z . coerce . number (). int (). min ( 1 ). max ( 100 ). default ( 10 ), q : z . string (). trim (). min ( 1 ). optional () }); z.coerce.number() is useful for query strings - HTTP query values arrive as strings. Prefer safeParse over parse at the edge so you control the HTTP status and response body. Format errors once Map ZodError.issues into a stable JSON body, or use Zod 4 helpers z.flattenError() / z.treeifyError() when you want field-keyed or nested shapes. // format-zod-error.ts import { ZodError } from ' zod ' ; export function formatZodError ( error : ZodError ) { return { message : ' Validation failed ' , issues : error . issues . map (( issue ) => ({ path : issue . path . join ( ' . ' ) || ' (root) ' , message : issue . message , code : issue . c

2026-07-23 原文 →
AI 资讯

Impact of deployment topology on rate-limiting and trust proxy

The trust proxy setting is an important concept in backend development, especially when implementing rate-limiting in our APIs. But deciding its accurate value depends heavily on our deployment topology. When we deploy our application in production, the client may not talk directly to our backend. There may be 1 or more proxies in between who forward the request to the next proxy or the backend server. Those proxies can be Load balancers, API gateways, reverse proxy like nginx or any custom service. So effectively, our request has to do some 'hops' over these proxies to reach backend. When we implement rate limiting in app to prevent the DOS attack, we generally intend this rate limit on the basis of client IP address. And this works fine when client request reaches our backend directly. But when we have multi-hop architecture, the simple setup won't work as expected. Because the most recent IP will be of the proxy and not the client. So all the traffic coming from different users will be considered from the single client(our own proxy) and thus there will be false positives as the rate limiting will trigger much often. In this scenario, we must tell our backend to ignore these extra hops(i.e. to trust our proxies). This is done by specifying trust proxy. If there is 1 proxy between client-server we set trust proxy to 1; if there are 2, or more, we set it accordingly. This will ensure our express app skips(trusts) these IPs, and accurately figures out actual client IP. The originating IP address of client is identified from 'X-Forwarded-For' header by the express app. But setting trust proxy is not that straightforward. The numerical value for trust proxy will not work in every case. If there are different paths from which our request reaches backend, there is a chance that the number of proxies may be different in each path. For example - internal vs external traffic: External(public) traffic: (Client -> Web Application Firewall -> Load balancer -> Reverse Proxy ->

2026-07-18 原文 →
AI 资讯

Node.js Internals Explained by Uncle to Nephew — Part 4: Express Plumbing, Error Handling & The Full Roadmap

Bonus round. Parts 1–3 covered why Node exists, what's happening inside it, and the full request journey. This part mops up the pieces that didn't fit anywhere else — the Express plumbing, error handling, and a checklist to test yourself against. Saturday, Round 4 Nephew: Uncle, one more round? I promise this is the last one for a while. Uncle: pours chai — you said that last time too. Fine, what's bugging you now? Nephew: Small things, actually. express.json() , cookie-parser , express.Router() — I use all of them, copy-pasted from old projects, but I couldn't explain any of them if you asked me directly. Uncle: That's exactly the right instinct — the things you copy-paste without understanding are always the things that break at 2 AM. Let's fix that. Part 4.1 — Two Directions Node Never Confuses Uncle: Before plumbing, one small but important idea that ties Parts 2 and 3 together. Everything Node does falls into exactly two directions . DIRECTION 1 — Incoming Events "The outside world is telling Node something happened" OS → libuv → Event Loop → Your JavaScript Examples: HTTP request arrives, TCP connection opens, WebSocket message arrives DIRECTION 2 — Outgoing Async Operations "Your JavaScript is asking Node to go do something" JavaScript → libuv → Worker Thread → OS → Disk/DB ↓ result comes back through libuv → Event Loop → your callback Examples: fs.readFile(), crypto.pbkdf2(), dns.lookup() Nephew: So an incoming HTTP request and a fs.readFile() call both eventually pass through libuv and the event loop — but they enter from completely opposite directions? Uncle: Exactly. One is the world pushing something at Node. The other is Node reaching out to go get something. Same event loop handles both, but the journey to get there is different — an HTTP request never touches the thread pool; a file read almost always does. Incoming HTTP Request: File Reading: Browser JavaScript | | OS libuv | | libuv Worker Thread | | Event Loop Operating System | | JavaScript Disk |

2026-07-10 原文 →
AI 资讯

Day 71 of Learning MERN Stack

Hello Dev Community! 👋 It is officially Day 71 of my unbroken 100-day full-stack engineering run! After mastering polymorphic multi-part storage configurations yesterday, today I successfully crossed into core transactional operations: Engineering a High-Fidelity "Confirm and Pay" Checkout View and Wiring Database Inbound Array Modifications! In real-world booking platforms, processing a successful transaction requires more than updating an absolute view; you have to link documents relationally across collections. Today, I wired that entire execution pipeline together! 🧠 What I Handled on Day 71 (Checkout Engineering & Target Mutations) As displayed across my latest system files in "Screenshot (164).png" and "Screenshot (165).jpg" , handling payments runs through structured backend steps: 1. High-Fidelity Checkout Component ( /reserve ) I built out the detailed split-pane verification interface visible in "Screenshot (164).png" . The layout captures target trip date selections, total guests parameter caps, card input structures, and computes subtotal ledgers dynamically: Base Compute: $9000 x 5 nights = $45000 . Transactional Upgrades: Appending structured service charges ( $85 ) and local tax calculations ( $42 ) to update the final sum directly to $45127 . 2. Live Document Array Mutators (MongoDB User List Insertion) The most crucial logic happens when the user clicks the primary validation trigger labeled Confirm and pay : The inbound route controller extracts the targeted property identity token ( home._id ) via an embedded hidden input container. Instead of running isolation updates, it issues an atomized update operation straight into our MongoDB user records array (e.g., using Mongoose operators like $push or tracking active profiles inside our custom data state loops). This appends the exact property listing target ID directly into the user's booking history array database matrix! 🛠️ View Markup Code Integration View As showcased in my VS Code script structu

2026-06-23 原文 →
AI 资讯

Day 50 of Learning MERN Stack

Hello Dev Community! 👋 It is officially Day 50 — a massive half-century milestone on my daily, unbroken streak toward mastering full-stack MERN engineering! Reaching Day 50 feels absolutely incredible. Yesterday, I mapped out dynamic path parameters. Today, I wired the input engine by building a complete asset workflow: Capturing Host "Add New Product" data payloads and committing them to local file storage pipelines! Following Prashant Sir's backend sequence , today was all about bridging the gap between host client forms and backend architecture using the Model-View-Controller framework. 🧠 Key Learnings From Day 50 (Product Ingestion & Storage) Processing data mutations sent from input forms requires tight coordination between parsing middlewares and file serialization engines. Here is how I structured the logic today: 1. Intercepting Form Submissions ( POST /host/add-product ) Set up a clean route mapping inside hostRouter.js to process dynamic data blocks sent by the host. The endpoint parses input parameters securely via backend streams. 2. Utilizing Class Instances for Storage Instead of directly pushing raw unstructured dictionaries into file records, I initialized a new object instance using my Day 48 structural class framework ( new houseList(...) ). This forces incoming data attributes—like name, price, location, and images—to match my exact system layout blueprint. 3. Asynchronous File Serialization Invoked the instance method .save() , which runs a non-blocking background task: it reads the active database layout array inside homesdata.json , appends the newly formulated object safely, and flushes the stringified update back onto the hard drive array using Node's fs operations. javascript // A conceptual look at how my controller hands data over to the model layer today const Product = require("../model/home"); exports.postAddProduct = (req, res) => { const { title, price, location, rating, imageUrl } = req.body; // Instantiating the core class data mold

2026-06-20 原文 →
AI 资讯

Day 48 of Leaning MERN Stack

Hello Dev Community! 👋 It is officially Day 48 of my unbroken full-stack engineering journey! Yesterday, I refactored my modular core patterns into MVC architecture. Today, I linked up a major functional extension inside the /model layer by introducing JavaScript Classes (OOP) to coordinate my local file operations and storage data patterns! Instead of writing loose object definitions, I stepped up my enterprise game by structuring a reusable class footprint that encapsulates data parameters and handles non-blocking file-system persistence asynchronously. 🧠 Key Learnings From Day 48 (OOP Modeling & File Systems) As clearly shown in my development workspace layout within "Screenshot (116).png" , modeling data with dedicated classes shifts your core structural logic from simple scripts into highly scalable engines: 1. The Model Data Blueprinter ( constructor ) I used the standard ES6 class framework inside home.js to structure an explicit data mold ( houseList ) with attributes tracking: houseName , price , location , rating , and photoUrl . This ensures every entry traveling through our server follows an identical structure. 2. Streamlining Async Persistence ( save() ) Rather than relying on globally declared floating arrays, my .save() blueprint method triggers an internal lookup to read existing data stacks asynchronously before safely using fs.writeFile() to serialize and flash mutated JSON rows into a local data asset ( homesdata.json ). 3. Static Decoupled Fetchers ( static fetchAll() ) I mastered using static methods. Since reading a data grid requires pulling records without creating an instance of a single house first, making fetchAll(callback) static allows our controllers to tap the hard disk records straight from the class reference layout: javascript // A conceptual look at my file-reading design today static fetchAll(callback) { const filePath = path.join(rootDir, 'data', 'homesdata.json'); fs.readFile(filePath, (err, data) => { if (err) { callback(JSON.

2026-06-20 原文 →
AI 资讯

Day 41 of Learning MERN stack

Hello Dev Community! 👋 It is officially Day 41 of my continuous streak toward full-stack MERN engineering! Yesterday, I migrated my codebase from native Node boilerplate to Express.js. Today, I dived straight into the absolute core mechanism that makes Express so incredibly powerful in Prashant Sir's (Complete Coding) masterclass : Middlewares . Before today, I thought requests hit an endpoint and immediately returned a response. Today, I learned how to intercept, inspect, and modify that request before it ever reaches the final route handler! 🧠 Key Learnings From Node.js Lecture 9 (Middlewares) A middleware is essentially a function that executes during the Request-Response cycle, having full access to the req , res , and the next middleware function in line. Here is the technical breakdown: 1. The Anatomy of Middleware Unlike a standard route handler that takes (req, res) , a middleware takes a third powerful argument: next . If you don't invoke next() , your request will hang forever and the browser will eventually timeout! 2. Built-in vs. Custom Middleware Custom Middleware: Wrote my own custom functions using app.use((req, res, next) => { ... }) to act as a security guard or global logger. Built-in Middleware: Explored how Express natively handles data types using structures like express.json() and express.urlencoded() , which automatically parse inbound request bodies so we don't have to manually handle streams anymore! javascript const express = require("express"); const app = express(); // Custom Global Logging Middleware app.use((req, res, next) => { console.log(`[${new Date().toISOString()}] ${req.method} request to ${req.url}`); next(); // Pass control to the next handler in line! }); app.get("/dashboard", (req, res) => { res.send("Welcome to the secure dashboard layer!"); }); app.listen(8000);

2026-06-18 原文 →
AI 资讯

Architecting a Production-Ready Express + TypeScript Backend: Type Augmentation, Global Errors, and Middleware Factories

When building a personal finance tracker, data integrity and system reliability are non-negotiable. One missing try/catch block can crash your whole server, and weak types can let invalid financial payloads corrupt your database. While building the backend for my personal finance tracker, I decided to move past generic tutorials and build a bulletproof, production-grade API core using Express, TypeScript, and Zod. In this post, I’ll show you how I implemented a type-safe middleware ecosystem, leveraged TypeScript declaration merging to extend the native Request object, and eliminated repetitive try/catch boilerplate across the entire codebase. 1. The Weapon Against Boilerplate: The asyncHandler HOC Writing try/catch blocks in every single controller handler clutters code and introduces human error—it’s easy to forget to pass an error to next() . To solve this, I engineered a Higher-Order Function (HOC) factory that wraps asynchronous request handlers and automatically catches rejected promises, safely routing them into the global error handler. import { Request , Response , NextFunction , RequestHandler } from ' express ' ; export const asyncHandler = ( fn : RequestHandler ): RequestHandler => { return ( req : Request , res : Response , next : NextFunction ) => { Promise . resolve ( fn ( req , res , next )). catch ( next ); }; }; Why this matters: Reliability: Async errors always reach the centralized error middleware. Readability: Route controllers stay beautifully clean, focusing only on business logic rather than async control flow wiring. 2. TypeScript Magic: Declaration Merging & Type Augmentation When dealing with authentication tokens, request tracing ( requestId ), or custom validated payloads, developers frequently resort to casting the request as any (e.g., (req as any).userId ). This completely destroys Type Safety. Instead of fighting the compiler, I leveraged TypeScript Declaration Merging to reopen Express's internal Request interface and merge my cust

2026-06-10 原文 →
AI 资讯

How to Integrate the OpenAI API into a Production Express App

Last year I helped a startup integrate the OpenAI API into their product. It was a chat feature — users could ask questions about their data and get natural language answers. The integration took about a day. Three days after launch, the founder messaged me: "Hey, something's wrong. Our AWS bill just showed an unexpected charge." It was $340. For three days. They had 60 users. The issue wasn't a bug — it was that production API usage looks nothing like a tutorial. The tutorial shows you openai.chat.completions.create() and returns a response. The tutorial doesn't show you what happens when users send 500-token messages, when they open 15 browser tabs each maintaining their own chat context, or when one user fires requests 30 times per minute because they think it's broken. This guide covers what the tutorials skip: rate limiting, token counting, cost guards, streaming, error handling with retries, and model selection. These aren't optional additions — they're what separates a demo from a production feature. Why Production Is Different Here's the gap between tutorial code and production code, stated plainly: Concern Tutorial Code Production Code Cost control Not mentioned Token counting, spending limits, model selection by task Rate limiting Not mentioned Per-user and per-IP limits to prevent abuse Error handling try/catch that logs to console Typed errors, retries with backoff, user-facing messages Response delivery Wait for full completion, return at once Streaming via SSE — response appears as it generates Context management Each request is independent Conversation history managed, truncated at token limit Secrets management API key hardcoded or in .env (no rotation) Rotation strategy, usage monitoring, per-feature keys Let's build a production-grade Express API that addresses all of this. We'll go layer by layer. The Architecture ┌─────────────────────────────────────────────────────────┐ │ CLIENT (Browser / Mobile) │ │ POST /api/chat { messages: [...] } │ │ GET

2026-06-03 原文 →
AI 资讯

DaloyJS Is the Latest Modern Enterprise TypeScript Framework, and It Has Your Back on Security

I want to tell you something that took me years to learn, so you can learn it on a Tuesday afternoon instead of during a production incident: most developers who build REST APIs do not actually know all the security protections their API needs. I did not know them when I started. I learned them slowly, usually right after something broke. I am a Filipino fullstack developer, about ten years in, now based in Norway. I built DaloyJS ( @daloyjs/core ) partly so that newer developers do not have to learn security the painful way I did. This post is a gentle walk through the problem and how DaloyJS helps. No gatekeeping, I promise. First, what even is a "security protection"? When your API is on the internet, anyone can send it anything. Most people are nice. Some are not, and a few are running automated tools that poke at every API they can find. So your server needs some basic defenses. Here are a few, in plain words: Body-size limit: stop someone from sending a giant 2GB request that fills up your server's memory and crashes it. Timeouts: if a request takes forever, give up on it so it does not clog everything. Prototype-pollution protection: block a sneaky trick where a special key in the JSON ( __proto__ ) can mess with your whole app. Header safety: reject weird characters in headers so attackers cannot inject their own. Path-traversal protection: stop a path like ../../etc/passwd from reading files it should not. Hiding error details in production: do not show strangers your stack traces and internal info. Rate limiting: stop one person from hammering your API thousands of times a second. Secure headers and CORS: tell browsers how to safely talk to your API. You do not need to memorize all of these today. The point I want you to take away is simpler: this list exists, it is longer than most people think, and nobody hands it to you when you write your first endpoint. Why this is a trap, especially with AI tools Here is the part that matters most for you right now,

2026-06-01 原文 →