Install Express
Install
Basic Setup
Starting the server, keep restarting everytimes codes changed with nodemon
Middleware
Middleware is the nature of express.
pass req object through middle with app.use use next to continue to next middleware you can’t change req, res, next middleware app.use(’/path/’, (req, res, next) => {}) will apply for path start with / Body Parser
Express add new req.body and res.redirect
In order to use req.body , we need to install bodyParser
this is used as a middleware for ALL request also, we need to separate post or get request app.get, app.post just like app.use , but for GET and POST app.use(’/’) — will run on any path start with / app.get(’/’) — will run only on path / (exact path) app.use for all middleware app.get OR app.post for routes & logic So far
res.send (thay cho res.write and res.end ) res.redirect (thay cho res.setHeader and res.location ) req.body , and bodyParses app.use, app.get, app.post Summary of app.use('/') vs app.get('/') Confusion
app.use('/') or app.use(): If all above matches all routes starting with the specified path (e.g., / matches /, /random, /about, etc.)... If no path is specified, it defaults to '/' and applies to all routes. Typically used for middleware or catch-all handlers. Matches only the exact path for GET requests (e.g., / matches only /). Use this for specific routes like the homepage. Why /random404 Reaches the Homepage: app.use('/', ...) matches all routes starting with /, so /random is included. To fix this, use app.get('/') for the homepage. Use app.get('/') for the homepage to ensure it matches only /. Use app.use for middleware or a 404 handler to catch all unmatched routes. Router
Why using both app.use and router.use
In Express.js, app.use and router.use serve similar purposes but are used in different contexts. Here's the breakdown:
app.use
Context: Used at the application level. Purpose: Mounts middleware or routes at the application level. It applies to all requests that match the specified path. router.use
Context: Used at the router level (when using express.Router()). Purpose: Mounts middleware or sub-routes on a specific router instance. It allows you to modularize your routes. Why use express.Router()?
express.Router() is used to create modular, mountable route handlers. It helps organize your application by separating routes into smaller, manageable pieces. This is especially useful for large applications.
Benefits of express.Router():
Modularity: You can define routes in separate files and import them into your main app. Reusability: You can reuse the same router in different parts of your app. Readability: Keeps your code clean and organized. Example of express.Router() in a modular app:
Key Difference
app.use is for the entire application, while router.use is for a specific router instance. Use express.Router() to create modular route handlers for better organization and scalability. Helper or Utils
Constructing a helper to define a root dir for res.sendFile(’page.html’)
Static Public Folder
Next hay Không Next
1. next() là gì và khi nào thì “đi tiếp”?
Trong Express, mỗi request sẽ đi qua một chuỗi middleware/route handler.
Mỗi “chặng” trong chuỗi đó là một function kiểu:
Nếu gọi next() → Express chuyển control sang middleware/route kế tiếp trong stack. Nếu gửi response (như res.send(), res.json(), res.sendFile(), res.end()) và không gọi next() → request thường kết thúc tại đây, Express sẽ không tự đi tiếp nữa (trừ khi bạn cố ý gọi next() sau đó – thường là không nên). Nếu không gửi response, cũng không gọi next() → request sẽ bị treo (timeout). Nói ngắn gọn:
next() dùng khi bạn chưa muốn kết thúc request, mà chỉ làm một bước xử lý rồi chuyển tiếp cho thằng kế tiếp.
2. Vì sao bodyParser.urlencoded(...) và express.static(...) không thấy
next() mà vẫn đi tiếp?
Thực ra là có next(), chỉ là nó nằm bên trong function mà những dòng đó trả về.
Ví dụ:
Hai cái này không phải middleware trực tiếp.
Chúng là factory function – gọi xong thì trả về một middleware dạng:
Bạn có thể tưởng tượng:
urlencodedMiddleware bên trong có next():
Nó parse body xong, gắn req.body = {...} Rồi nó gọi next() để chuyển sang middleware/route tiếp theo. Tương tự với:
staticMiddleware sẽ:
Nếu tìm được file tương ứng URL → nó gửi file luôn (dùng res.sendFile/stream) và không gọi next() nữa (kết thúc luôn request). Nếu không tìm được file → nó gọi next() để cho request đi tiếp tới route khác. Nên lý do bạn không thấy next() là vì:
next() ở bên trong middleware mà những hàm đó trả về, chứ không nằm ở chỗ bạn viết.
3. res.send() và res.sendFile() có “tự động stop code” không?
Có 2 ý phải tách ra:
3.1. Về phía HTTP response
Khi bạn gọi:
hoặc
thì Express sẽ:
Set status code (nếu chưa set) Set header (Content-Type, Content-Length, v.v.) Gọi res.end() → response coi như đã kết thúc. Sau đó:
Bạn không được gọi thêm res.send(), res.json(), res.redirect() nữa. Nếu cố làm, sẽ bị lỗi: Error: Can't set headers after they are sent to the client. 3.2. Về phía JavaScript code trong handler
res.send() không phải là return. Nó không tự động dừng function của bạn.
Code phía sau vẫn chạy bình thường:
Muốn “stop code” trong handler tại chỗ res.send(), bạn nên return luôn:
Pattern thực tế hay dùng là:
route handler: thường return res.send(...) để: vừa kết thúc luôn function Nếu chỉ chuẩn bị dữ liệu (log, parse, auth,…) → không gửi response, chỉ next(). Nếu quyết định từ chối hoặc trả về luôn (403, 401, 500, …) → return res.status(...).send(...) và không gọi next() nữa. 4. Tóm lại cho dễ nhớ
Dùng trong middleware để cho request đi tiếp. Nếu không send response, cũng không next() → request bị treo. bodyParser.urlencoded(...) và express.static(...): Là hàm trả về middleware. Middleware bên trong có next(), nên request vẫn đi tiếp khi cần. res.send() / res.sendFile(): Về HTTP: kết thúc response → không gửi gì thêm được nữa. Về code: không tự kết thúc function → code phía sau vẫn chạy nếu bạn không return. Sending Response
HTML
JSON (for RestAPI)
Response will be auto convert to JSON.stringlify() You can use an array of objects Serve an entire directory (website with JS, CSS)
Popular file structure
public (for public assets) src (for starting JS file) templates (for handlebars files - just like views and includes) partials (includes like headers, footer, navigation)
Path Management to link to different folders & files
We could use these default var to manage paths, but we need a more absolute way to manage path.... When we serve a public static folder, we don’t need according routes. the idea of a public static folder is to serve static assets, static HTML we need a solution to serve dynamic pages Serve dynamic pages
Use template engine ‘handlebars’
Actually, we should use handlebar for express, which is here:
Install into local application
Set default template engine in express
To use template engine, we need to use:
templates / partials / views folders files has to be put in right folders no need to declare file ext .hbs Be careful because res.render use index.hbs, but express will show public/index.html if available
The hbs files are basically the same with html files, except for placeholders in this format:
Partials are just like includes (for menu, header...)
To use hbs template without partials, there is no need to require hbs.
BUT to use partials, you HAVE TO require hbs module.
When you change the handble bars partials, nodemon will not auto restart, so you have to extend its scope
To include partials in view files
Serve Error Pages
Handler page for “No page found”
Place this route at the end of the file, below all other routes
You can’s send response twice
to stop after the first response, use return
Dynamic Params
Query String
localhost:1234/weather?location=Hanoi
Use req.query
4. Integrate with back-end JS
File Structure
Back-end code in src
export JSON via HTTP end-point Front-end code in public
app.js is the starting point (but in src, act as router as well)
Back-end code modules:
Front-end code modules:
fetch (this fetch is only for client side, surprise!!!! not accessiable in Node.js) Steps to Integration
Build back-end code
Use app.js and route to build HTTP endpoint Return JSON via HTTP endpoint (query string or POST) Build front-end templates
Get JSON and parse into DOM Tham khảo node-fetch
hàm core fetch chỉ xài được ở browser client hàm node-fetch giống y chang, xài được ở back-end Bài viết Tham khảo