Skip to content

Latest commit

History

History
195 lines (144 loc) 路 5.43 KB

Express.md

File metadata and controls

195 lines (144 loc) 路 5.43 KB
alias
Express.js

Introduction

  • a [[Node]] framework.
  • abstracts away a lot of Node.js functionality.

Note

Express is all about middleware. Incoming requests are automatically funneled thru functions and processed on the way.

To be able to use multiple middleware functions, the next() function needs to be called at the end of each one.

const express = require("express");

const app = express()

// Middleware
app.use("/", (req, res, next) => {
聽 聽 console.log("Always Runs!");
聽 聽 next();
});

app.use("/express", (req, res, next) => {
聽 聽 console.log("Middleware!");
聽 聽 res.send("<h1>Hello, Express!</h1>");
});

app.use("/", (req, res, next) => {
聽 聽 console.log("Another Middleware!");
聽 聽 res.send("<h1>Hello, World!</h1>");
});

app.listen(3000);
// OR
// http.createServer(app).listen(3000);
  • Express doesn't parse request body (req.body) by default. We can use parser packages like body-parser to achieve that.
const bodyParser = require("body-parser");

// Parses form data
app.use(bodyParser.urlencoded({ extended: false }));

// We can now work with 'req.body'.

Note

To work with specific request methods, we can use get(), post(), patch(), put() and delete() instead of use() (which processes all types of request).

  • To serve static files and folders in our code, we need to define them in a middleware using Express' static() method. For instance, to import external stylesheets from ~/public/styles/main.css into our HTML, we can do this:
// ~/app.js
app.use(express.static(path.join(__dirname, "public")))
<!-- ~/views/Home.html -->
...
<link rel="stylesheet" href="/styles/main.css" />
...

Routing

  • It's considered good practice to make code modular.
  • Using routers in Express, we can define routes in separate route files and import them into our main file; as a convention a ~/routes/ directory is used to organize route logic.
// ~/routes/admin.js
const express = require("express");

const router = express.Router();

// matches '/admin/add'
router.get("/add", (req, res, next) => {
聽 聽 res.send(`
聽 聽 聽 <form action="/added" method="POST">
聽 聽 聽 聽 <input type="text" name="user" >
聽 聽 聽 聽 <button type="submit">submit</button>
聽 聽 聽 </form>
聽 聽 `);
});

// matches '/admin/added'
router.post("/added", (req, res, next) => {
聽 聽 console.log(req.body);
聽 聽 res.redirect("/");
});

module.exports = router;
// ~/app.js
const adminRoutes = require("./routes/admin");

// matches '/add' (GET) & '/added' (POST)
// app.use("/admin", adminRoutes)

// matches '/admin/add' (GET) & '/admin/added' (POST)
app.use("/admin", adminRoutes)

Important

The first argument of app.use() is an optional path value. By default, it's value is / which acts as a catch-all route. If another route middleware is needed it needs to precede the default catch-all route (/), and it shouldn't invoke the next() function.

We can also avoid this by matching exact paths using request-specific methods like app.get() & app.post().

// Should come first
app.use("/admin", adminRoutes);

// Exact match '/' route
app.get("/", (req, res, next) => {
聽 聽 console.log("Middleware!");
});

// Catch-all route ('/*') for unhandled routes 
// Comes after all route handlers
// Can be used to render 404 pages
app.use("/", (req, res, next) => {
聽 聽 res.status(404).send("<h1>Page Not Found!</h1>");
});

Note

res methods like setHeader() & status() can be chained together and must come before the send() method.

  • sendFile() can be used to send [[HTML]] files as a response.
app.use("/", (req, res) => {
    res.status(404).sendFile(path.join(__dirname, "pages", "404.html"))
})

MVC

![[MVC]]

Models

  • How data is represented in the code.

Views

  • What the user sees and interacts with.
  • Templates and [[HTML]] files to be rendered can be stored separately; as a convention a ~/views/ directory is used to organize such files.
// ~/routes/home.js
const path = require("path");

router.get("/", (req, res, next) => {
聽 聽 res.sendFile(path.join(__dirname, "..", "views", "index.html"));
});
  • Alternatively, we can create a utility function to return the root directory of an application:
// ~/utils/path.js
const path = require("path");

module.exports =path.dirname(require.main.filename);
// ~/routes/home.js
const rootDir = require("../utils/path");

router.get("/", (req, res, next) => {
聽 聽 res.sendFile(path.join(rootDir, "views", "index.html"));
});

Important

path.join() constructs an absolute path to the specified route that works on all operating systems. However, the path arguments passed are relative to the current file (~/routes/home.js above).

Note

Content that can be accessed publicly is stored in the ~/public directory. It can be used to store static content like [[CSS]] files and static web files like [[robots.txt]].

e.g. If our stylesheet path is ~/public/css/style.css, there needs to be extra configuration in Express to expose that file to the public: app.use(express.static(path.join(rootDir, "public"))). From HTML files, our stylesheet file can be accessed with /css/style.css.

Controllers

  • The in-between logic connecting the models and views.
  • Routes belong to this category.
  • In the context of a Node/Express project, controllers might be split into different middleware functions.