Application, Request and Response
By Syncfusion®, Inc. · Last updated
The app object and its settings, app.locals and sub-apps, everything req holds, every way res can answer, the one-response rule, and caching with ETags, 304 answers and range requests.
What you will learn
- Create and configure the app object
- Read params, query, body and headers from req
- Send text, JSON and status-only responses
- Avoid double responses with return
- Use ETags and 304 Not Modified
The Express Application
Application object = the object that express() returns. We always call it app.
appholds your routes, middleware and settings.appis also a function. Node.js calls it for every request.app.listenstarts a server that sends requests toapp.- One project usually has one main
app. - You can mount smaller apps inside it.
Simple lesson: app is the brain of your server. Everything starts from it.
A Real-World Example
The canteen manager keeps a notice board in the kitchen.
- "Opening time: 8 AM."
- "Dark mode on the menu screen: off."
- "School name: Green Valley."
- Every cook reads the same board.
app has a notice board too. It is called settings, plus a shared shelf called app.locals.
In this lesson, you will learn:
- What the application object holds and how settings work.
- The two meanings of
app.get, andapp.localsvsres.locals. - How
NODE_ENVchanges error output, and how to mount a sub-app. - What
reqtells you: URL details, params, query, body and headers. - How
ressends content, status codes and headers. - The one-response rule, ETags, 304 answers and ranges.
Application Settings
- app.set(name, value) = saves a setting.
- app.get(name) = reads a setting.
- app.enable(name) = sets it to
true. - app.disable(name) = sets it to
false. - app.enabled(name) = asks "is it true?".
- app.disabled(name) = asks "is it false?".
- The terminal prints each setting when the server starts.
envisdevelopmentby default.- Open Headers. There is no
X-Powered-Byheader, because you disabled it.
Simple lesson: Settings are named values on app. Set them before your routes.
The Two Meanings of app.get
app.get does two different jobs. The number of arguments decides which.
- app.get(name) with one argument = read a setting.
- app.get(path, handler) with two or more = add a GET route.
app.get("env")returns"development".app.get("/env", handler)answers requests to/env.- Paths start with
/. Setting names usually do not.
Easy way to remember: a path starts with /. app.get("env") reads, app.get("/env", ...) routes.
Simple lesson: One argument reads a setting. A path and a function make a route.
Sharing Data with app.locals
app.locals = an object for values the whole app shares.
- Set it once:
app.locals.school = "Green Valley". - Read it in any route:
req.app.locals.school. - Views (templates) can read it directly. See Views and Static Files.
- res.locals is different. It lives for one request only.
- Use
app.localsfor things that never change per request, like the school name.
- Send
/abouttwice.schoolstays the same. askedAtchanges each time, becauseres.localsis new for every request.
Simple lesson: app.locals is for the whole app. res.locals is for one request.
The Environment Setting
env = a setting that says where the app is running.
- Express copies it from the
NODE_ENVenvironment variable. - If
NODE_ENVis missing,envisdevelopment. - Real servers set
NODE_ENV=production. - In production, Express hides error details from visitors.
- In development, Express shows the full error to help you.
- Send
/broken. The visitor only sees "Internal Server Error". - The real message still prints in the terminal, for you.
- Change
.envtoNODE_ENV=developmentand run again. Now the visitor sees the message too.
Always set NODE_ENV=production on real servers. Error details can leak passwords and file paths.
Simple lesson: env changes how much Express tells visitors when things break.
Useful Built-In Settings
- x-powered-by: adds
X-Powered-By: Express. Turn it off to hide what you use. - json spaces: pretty-prints JSON, such as
app.set("json spaces", 2). - case sensitive routing: makes
/Menuand/menudifferent. - strict routing: makes
/menuand/menu/different. - query parser:
"simple"by default in Express 5."extended"allows nested objects. - trust proxy: for apps behind a proxy. See Redirects, Content Negotiation and Proxies.
- view engine and views: for HTML templates. See Views and Static Files.
- With curl or a browser, the JSON now comes on many lines. The lab panel always formats JSON, so look at
Content-Lengthunder Headers: it grew. /Menugives 404, because routing is now case sensitive.- Remove the
enableline and run again./Menuworks.
Simple lesson: A few settings change how every route behaves.
Mounting a Sub-Application
Sub-application = a second express() app used inside the main one.
- Create it like any app:
const admin = express(). - Mount it with
app.use("/admin", admin). - Its routes now live under
/admin. - admin.mountpath = the path it was mounted on.
- The mount event fires when it is mounted.
- The sub-app keeps its own settings.
- The terminal prints the mount message before the server starts.
admin.get("/")answers/admin, because of the mount path.- Most projects use Routing and Routers for this instead. It is lighter.
A sub-app is a full Express app with its own settings. If you only need to group routes, a router is lighter. See Routing and Routers.
Simple lesson: app.use(path, otherApp) plugs one app into another.
Request and Response Objects
Every route handler gets two objects: req and res.
- req = the request object. It holds everything the client sent.
- res = the response object. It has tools to send your answer.
- Express builds both from the Node.js request and response.
- Express adds many helpers on top, such as
req.queryandres.json. - You read from
req. You write withres.
Simple lesson: req is the question. res is how you answer.
A Second Example
A canteen order slip arrives at the kitchen.
- The slip says who ordered, what they want and how many.
- The cook reads the slip.
- The cook fills a plate and adds a label.
- The plate goes back to the counter.
The slip is req. The plate and its label are res.
Request URL Information
- req.method = the HTTP method, such as
GET. - req.url = the path and query, as seen by the current router.
- req.originalUrl = the full original path and query. It never changes.
- req.baseUrl = the path where the current router is mounted.
- req.path = the path without the query string.
- req.route = the route that matched, including its path pattern.
originalUrlkeeps the full text:/canteen/menu/7?veg=true.baseUrlis/canteen, where the router is mounted.urlandpathare what the router itself sees.
Easy way to remember: path for routing, originalUrl for logs, baseUrl for where the router lives.
Simple lesson: Use req.path to know where. Use req.originalUrl for logs.
Request Data
- req.params = values from the path, such as
:id. See Routing and Routers. - req.query = values after
?, such as?veg=true. - req.body = data sent in the body. It needs a body parser. See Body Parsers and Third-Party Middleware.
- req.headers = every header, with lowercase names.
- req.get(name) = one header, in any letter case.
- req.header(name) = the same as
req.get. It is just another name. - req.cookies = cookies, only after you add cookie-parser. See Cookies and Sessions.
- Every value from the URL is a string.
"7"is not the number7. req.getignores letter case.X-Student-Idandx-student-idare the same.- In Express 5,
req.bodyisundefinedwhen no body was parsed.
Treat everything in req as untrusted. Any client can send any params, query, body or headers. Check values before you use them.
Simple lesson: params come from the path, query from after the ?, body from the message.
Request Connection Information
- req.protocol =
httporhttps. - req.secure =
truewhen the protocol ishttps. - req.hostname = the host name without the port, such as
localhost. - req.ip = the client's IP address.
- req.ips = a list of IP addresses when the app is behind a proxy.
- req.subdomains = parts before the main domain, such as
["menu"]formenu.school.in. - req.xhr =
truewhen theX-Requested-Withheader isXMLHttpRequest.
Request Type Checks
- req.is(type) = checks the
Content-Typeof the body. req.is("json")returns"json"when the body is JSON, andfalseotherwise.- req.fresh and req.stale = whether the client's cached copy is still good.
- req.range() = reads the
Rangeheader, used for partial downloads.
ipis::1, the IPv6 address of your own computer.- Behind a proxy, these values need the
trust proxysetting.
Simple lesson: req also knows how the client connected.
Sending Content with res
- res.send(body) = sends text, HTML, an object or an array.
- res.json(data) = always sends JSON.
- res.end() = ends the response with no Express helpers. Rarely needed.
- res.sendStatus(code) = sends a status code and its standard text.
- res.jsonp(data) = old-style JSON for script tags. Rarely used today.
res.sendStatus(204)sends "No Content" with an empty body.res.sendStatus(404)would send the text "Not Found".res.end()sends nothing at all, with status 200.
Simple lesson: Use res.json for data and res.send for text and HTML.
Status and Headers
- res.status(code) = sets the status. Chain it:
res.status(201).json(order). - res.set(name, value) = sets a header.
res.headeris the same. - res.append(name, value) = adds another value to a header.
- res.get(name) = reads a header you already set.
- res.type(type) = sets
Content-Typefrom a short name like"json". - res.vary(header) = tells caches the answer depends on that header.
- res.links(links) = sets the
Linkheader, used for page links.
- Open Headers to see each one.
X-Noteholds both values:fresh, hot.- Set headers before you send. After sending, it is too late.
Simple lesson: Status and headers first, then the body.
Response Locals
res.locals = an object that lives for one request only.
- Middleware can put values in it.
- Later middleware and the route handler can read them.
- Views can read them too. See Views and Static Files.
- It is the safe place for per-request data, such as the logged-in user.
Simple lesson: Pass data down the chain with res.locals.
The One-Response Rule
Each request gets exactly one response.
- Send twice, and Node.js throws
ERR_HTTP_HEADERS_SENT. - This usually happens when code keeps running after an early
res.send. - Fix it with
return res.send(...). - res.headersSent =
trueonce the response has started.
- Send
/greetwith no name. The client gets 400, but the terminal shows an error. - Add
returnbeforeres.status(400)and run again. - Now the error is gone, because the function stops early.
Easy way to remember: return res.send(...) whenever there is code below it.
Simple lesson: One request, one response. Use return to stop early.
Caching and Partial Requests
Browsers try not to download the same thing twice.
- ETag = a short fingerprint of a response body. Express adds one to
res.sendanswers. - The browser keeps the copy and sends If-None-Match with that ETag next time.
- req.fresh =
truewhen the client's copy still matches. req.stale is the opposite. - When the copy is fresh,
res.sendanswers 304 Not Modified with no body. That saves data. - Range = a header asking for only part of a file, such as
bytes=0-99. Video players use it. - req.range(size) reads it. It returns a list of
{ start, end }, or-1when the range cannot be served.
- Send
/menu, open Headers and copy theETagvalue. - Type it into the request headers as
If-None-Match: <the ETag>and send again. You get 304 and an empty body. - The range request gets 206 Partial Content with only the first 20 characters.
- A range past the end gets 416 Range Not Satisfiable.
Simple lesson: ETags let browsers reuse copies. Ranges let them download just a part.
Common mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
app.get("env") to make a route | It adds a route called env | One argument reads a setting | No route is added |
Setting json spaces after routes run | Order does not matter | Set settings before routes | Some routes miss the setting |
Storing per-user data in app.locals | It is per request | It is shared by everyone | Users see each other's data |
No NODE_ENV on the real server | Express guesses production | It defaults to development | Visitors see error details |
Leaving x-powered-by on | It is harmless | It tells attackers what you use | Easier targeted attacks |
req.params.id + 1 | Params are numbers | Params are strings | "7" + 1 gives "71" |
Reading req.body without a parser | Express parses bodies by itself | Add express.json() first | req.body is undefined |
Sending without return | Sending stops the function | The function keeps running | ERR_HTTP_HEADERS_SENT |
| Setting a header after sending | Headers can change any time | Headers go out first | Error, or the header is lost |
Trusting req.query.role | Clients send only honest data | Anyone can type any URL | Users give themselves admin rights |
req.headers["X-Id"] | Header names keep their case | req.headers uses lowercase names | undefined. Use req.get("X-Id") |
Check Yourself
Exercises
What to Remember
express()returns the application object,app.app.set,app.get(name),app.enableandapp.disablemanage settings.app.get(name)reads a setting.app.get(path, handler)adds a route.app.localsis shared by the whole app.res.localsis per request.NODE_ENV=productionhides error details from visitors.reqholds the method, URL, params, query, body, headers and connection details.res.send,res.jsonandres.sendStatussend the answer.res.statusandres.setmust come before the body.- Send exactly one response, and
returnwhen you stop early.
Next: Routing and Routers. You will learn route paths, parameters, query strings and the Express 5 path syntax.