Skip to main content

Express

Framework Javascript NodeJS

Slide PPT : https://docs.google.com/presentation/d/1-NFflg1VVr75sQH_qDpaD59ksE5ENddJ

Pengenalan Express

  • ExpressJS adalah salah satu Web Framework OpenSource paling populer di NodeJS
  • ExpressJS pertama kali dibuat tahun 2010, dan karena sangat populer, ExpressJS sekarang sudah menjadi hal yang wajib dikuasai ketika kita akan membuat Web menggunakan NodeJS
  • ExpressJS sangat minimalist, tidak memiliki banyak fitur seperti Web Framework di bahasa pemrograman lain seperti Laravel, Ruby on Rails atau Django
  • Karena sangat minimalist, biasanya ExpressJS akan diintegrasikan dengan banyak library NodeJS lainnya
  • Oleh karena itu, programmer bisa bebas memilih Library NodeJS yang ingin dia integrasikan dengan ExpressJS

Explore Express:

  1. Website Resmi Express : https://expressjs.com/
  2. Package : https://www.npmjs.com/package/express
  3. Github : https://github.com/expressjs/express

Install Express

npm install express

Menjalankan Aplication Express

index.js
import express from "express";

const app = express();

app.listen(3000, () => {
console.log("server running in port 3000");
});

Basic Routing

  • Saat kita membuat web, biasanya kita akan membuat banyak sekali URL Path
  • Routing merupakan teknik yang digunakan untuk meneruskan request dari URL Path ke callback yang kita tuju
  • Routing di ExpressJS bisa menggunakan object Application, dan menggunakan method sesuai dengan nama HTTP Method nya

Routing Method

MethodDetail
app.connect(path, callback)HTTP Method CONNECT
app.get(path, callback)HTTP Method GET
app.post(path, callback)HTTP Method POST
app.put(path, callback)HTTP Method PUT
app.delete(path, callback)HTTP Method DELETE
app.options(path, callback)HTTP Method OPTIONS
app.trace(path, callback)HTTP Method TRACE
app.head(path, callback)HTTP Method HEAD
app.patch(path, callback)HTTP Method PATCH
app.all(path, callback)Semua HTTP Method
import express from "express";

const app = express();

app.get("/", (req, res) => {
res.send("hello world");
});

app.listen(3000, () => {
console.log("server running in port 3000");
});

Request

  • Saat kita membuat callback di router, parameter pertama adalah object Request, yang secara otomatis diisi oleh ExpressJS
  • Object Request akan berisikan informasi tentang HTTP Request yang masuk ke callback tersebut
  • Ada banyak sekali informasi HTTP Request yang bisa kita ambil dari object Request, seperti Query Param, Header, Body dan lain-lain

Detail : https://expressjs.com/en/4x/api.html#req

Request URL

  • Untuk mendapatkan URL saat ini, kita bisa menggunakan object Request untuk mendapatkan informasinya
  • req.originalUrl, untuk mendapat url secara full beserta query param nya
  • req.path, untuk mendapatkan path url tanpa query param
  • req.hostname, untuk mendapatkan nama host atau domain dari web kita
  • req.protocol, untuk mendapatkan protocol dari url web
  • req.secure, untuk mengecek apakah url web nya https atau bukan
  • req.subdomains, untuk mendapatkan array subdomain dari url web kita

Request Query Params

  • Request juga bisa digunakan untuk mengambil data query parameter
  • Secara otomatis, semua query parameter akan disimpan dalam bentuk object di req.query

Detail : https://expressjs.com/en/4x/api.html#req.query

request-query.test.js
test("test request query", async () => {
app.get("/query", (req, res) => {
res.send(`hello ${req.query.firstName} ${req.query.lastName}`);
});

const response = await supertest(app).get("/query").query({ firstName: "joko", lastName: "santoso" });
expect(response.text).toBe("hello joko santoso");
});

Requets Header

  • Object Request juga bisa kita gunakan untuk mendapatkan informasi dari HTTP Header dari Request
  • Kita bisa menggunakan method req.get(name) atau req.header(name) untuk mendapatkan header berdasarkan name, khusus untuk HTTP Header, name nya adalah case insensitive

Detail : https://expressjs.com/en/4x/api.html#req.get

request-header.test.js
test("test request header", async () => {
app.get("/", (req, res) => {
const type = req.get("auth");
res.send(`auth is ${type}`);
});

const response = await supertest(app).get("/").set("auth", "123");
expect(response.text).toBe("auth is 123");
});

Request Body

  • Sebelumnya kita belum membahas tentang HTTP Request Body
  • Di ExpressJS, Secara default HTTP Request Body tidak bisa diambil datanya oleh Router Callback, hal ini dikarenakan, jenis data Request Body bisa berbeda-beda, tergantung tipe data yang dikirim
  • Oleh karena itu, di dalam ExpressJS, terdapat Built-in Middleware, yang digunakan untuk membaca Request Body, lalu melakukan konversi ke tipe data yang diinginkan
request-body.test.js
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(expressFileUpload());

// request json
app.post("/json", (req, res) => {
const name = req.body.name;
res.json({ sayHello: `hello ${name}` });
});

// request form
app.post("/form", (req, res) => {
const name = req.body.name;
res.json({ sayHello: `hello ${name}` });
});

// request file
app.post("/file", async (req, res) => {
const textFile = req.files.article;
await textFile.mv(__dirname + "/upload/" + textFile.name);

res.send(`hello ${req.body.name}, file uploaded ${textFile.name}`);
});

test("test request body json", async () => {
const response = await supertest(app)
.post("/json")
.set("Content-Type", "application/json")
.send({ name: "joko" });
expect(response.body).toEqual({ sayHello: "hello joko" });
});

test("test request body form", async () => {
const response = await supertest(app)
.post("/form")
.set("Content-Type", "application/x-www-form-urlencoded")
.send("name=joko");
expect(response.body).toEqual({ sayHello: "hello joko" });
});

test("test request body file", async () => {
const response = await supertest(app)
.post("/file")
.set("Content-Type", "multipart/form-data")
.field("name", "joko")
.attach("article", __dirname + "/contoh.txt");

expect(response.text).toBe("hello joko, file uploaded contoh.txt");
});

Response

  • Pada Callback Routing ExpressJS, terdapat parameter kedua yaitu response
  • Response merupakan object representasi dari HTTP Response
  • Kita bisa mengubah data HTTP Response melalui object Response tersebut

Detail : https://expressjs.com/en/4x/api.html#res

response.test.js
test("test response", async () => {
app.get("/", (req, res) => {
res.send("hello response");
});

const response = await supertest(app).get("/");
expect(response.text).toBe("hello response");
});

Response Status

Saat kita ingin mengubah HTTP Status dari HTTP Response yang kita buat, kita bisa menggunakan method res.status(code)

Detail : https://expressjs.com/en/4x/api.html#res.status

response-status.test.js
test("test response status", async () => {
app.get("/", (req, res) => {
if (req.query.name) {
res.status(200).send("status sucess");
} else {
res.status(400).end();
}
});

let response = await supertest(app).get("/").query({ name: "joko" });
expect(response.status).toBe(200);
expect(response.text).toBe("status sucess");

response = await supertest(app).get("/");
expect(response.status).toBe(400);
});

Response Header

  • Kita juga bisa mengubah HTTP Response Header dengan menggunakan method res.set(name, value) atau res.header(name, value)
  • Atau jika ingin langsung beberapa name, kita bisa masukkan dalam bentuk object ke dalam parameter name nya

Detail : https://expressjs.com/en/4x/api.html#res.set

response-header.test.js
test("test response header", async () => {
app.get("/", (req, res) => {
res
.set({
"X-Author": "Joko Santoso",
"X-Auth": "123",
})
.end();
});

const response = await supertest(app).get("/");
expect(response.get("x-author")).toBe("Joko Santoso");
expect(response.get("x-auth")).toBe("123");
});

Response Body

  • Untuk mengubah Response Body, kita bisa menggunakan method res.send(body)
  • Dimana parameter body bisa kita kirim dalam bentuk buffer atau string, baik itu text, html, json dan lain-lain

Detail : https://expressjs.com/en/4x/api.html#res.send

response-body.test.js
test("test response", async () => {
app.get("/", (req, res) => {
res.set("Content-Type", "application/json");
res.json({ messages: "hello world" });
});

const response = await supertest(app).get("/");
expect(response.get("content-type")).toContain("application/json");
expect(response.body).toEqual({ messages: "hello world" });
});

Redirect

  • Seperti yang pernah dijelaskan di kelas HTTP, untuk melakukan Redirect dari sebuah web ke halaman lain, kita hanya cukup menggunakan HTTP Header Location
  • Di ExpressJS, kita bisa lakukan manual dengan menggunakan HTTP Header Location, atau bisa dengan bantuan method res.redirect(to)

Detail : https://expressjs.com/en/4x/api.html#res.redirect

redirect.test.js
test("test response", async () => {
app.get("/", (req, res) => {
res.redirect("/to-next-page");
});

const response = await supertest(app).get("/");
expect(response.get("Location")).toBe("/to-next-page");
});

Middleware

  • Middleware adalah function yang bisa digunakan untuk mengakses request object, response object dan next function dalam alur hidup aplikasi ExpressJS
  • Jika Middleware memanggil next function, artinya function Middleware selanjutnya atau Router akan dieksekusi

Fungsi Middleware

Ada banyak sekali kegunaan dari Middleware, seperti :

  • Eksekusi kode sebelum sebelum router di eksekusi
  • Mengubah Request atau Response object sebelum router di eksekusi
  • Mengakhiri response tanpa harus mengeksekusi router
  • Dan lain-lain

Spesifikasi Middleware

  • Untuk membuat middleware, kita cukup membuat function dengan 3 parameter, request, response dan next
  • request adalah request object
  • response adalah response object
  • next adalah next function, bisa middleware selanjutnya atau router
middleware.js
export const apiKeyMiddleware = (req, res, next) => {
if (req.query.apikey) {
next();
} else {
res.status(401).end();
}
};

Next, di index.js

index.js
app.use(apiKeyMiddleware);

Manipulasi Request

  • Karena Request itu adalah JavaScript Object
  • Jadi jika kita mau, kita juga bisa memanipulasi Request Object di Middleware
  • Misal mengubah attribute atau menambah attribute baru, agar bisa digunakan di Middleware selanjutnya, atau di Router
middleware.js
export const requestTimeMiddleware = (req, res, next) => {
const res.requestTime = Date.now();
next()
};

Next, di index.js

index.js
app.use(requestTimeMiddleware);

Type of Middleware

Di ExpressJS, terdapat beberapa jenis Middleware

  • Application-level middleware
  • Router-level middleware
  • Error-handling middleware
  • Built-in middleware
  • Third-party middleware

Application-Level Middleware

  • Yaitu middleware yang digunakan di object Application, sebelumnya kita sudah menggunakan Application-Level Middleware, dengan cara menggunakan function app.use(middleware)
  • Saat kita menggunakan Application-Level Middleware, maka secara otomatis Middleware tersebut akan dipanggil di semua route
  • Jika kita mau menggunakan Middleware hanya untuk di route path tertentu, kita bisa tambahkan route pattern ketika menggunakan app.use(), misal app.use(“/products/\*”, middleware)

Detail : https://expressjs.com/en/4x/api.html#app.use

index.js
const app = express();

app.use(middleware);
app.use("/product", middleware);

Router-Level Middleware

  • Yaitu middleware yang ditambahkan pada object Router yang kita buat menggunakan express.Router()
  • Middleware ini secara otomatis akan dipanggil ketika request masuk ke router ini
  • Sama seperti dengan Application-Level Middleware, jika kita ingin middleware nya hanya dipanggil para route path tertentu, kita bisa juga tambahkan route pattern ketika menggunakan middleware nya menggunakan router.use(path, middleware)

Detail : https://expressjs.com/en/4x/api.html#router.use

router.js
const router = espress.Router();

router.use(middleware);
router.use("/product", middleware);

Error-Handling Middleware

  • Yaitu middleware yang akan dipanggil ketika terjadi error di aplikasi kita (throw Error)
  • Cara penggunaannya mirip dengan Application-Level Middleware, yang membedakan adalah function callback nya memiliki empat parameter, yaitu error, request, response dan next
  • Object error akan secara otomatis terisi oleh data Error yang terjadi di aplikasi kita
  • Middleware ini, sangat cocok ketika kita ingin menampilkan tampilan yang berbeda ketika terjadi error di aplikasi kita
index.js
const app = express();

app.use(errorMiddleware);

Built-in Middleware

  • ExpressJS banyak sekali menggunakan Middleware untuk melakukan pemrosesan request dan response, termasuk terdapat Built-in Middleware, yaitu middleware yang sudah terdapat secara otomatis di ExpressJS
  • express.json(), yaitu middleware yang melakukan parsing request body menjadi JavaScript object
  • express.text(), yaitu middleware yang melakukan parsing request body menjadi string
  • express.raw(), yaitu middleware yang melakukan parsing request body menjadi Buffer
  • express.urlencoded(), yaitu middleware yang melakukan parsing request body form menjadi object
  • express.static(), yaitu middleware yang digunakan untuk melayani file static

Third-party middleware

  • Yaitu middleware buatan orang lain yang kita gunakan
  • Untuk menggunakannya, kita perlu menambah dependency middleware nya terlebih dahulu

Route Path

  • Sebelumnya pada materi Basic Routing, kita belajar bagaimana cara melakukan routing dengan HTTP Method sesuai yang kita mau
  • Sekarang kita akan bahas lebih detail tentang Route Path nya.
  • Sebelumnya, route path yang kita gunakan tidak dinamis. ExpressJS mendukung route path yang dinamis, dengan cara menggunakan route path string patterns atau regex
// * -> all
app.get("/all/*", (req, res) => {
res.send(req.originalUrl);
});

// (\\d+) -> decimal
app.get("/decimal/*(\\d+)", (req, res) => {
res.send(req.originalUrl);
});

Route Parameter

  • Saat kita membuat aplikasi Web API atau RESTful API, kadang kita sering menyimpan parameter dalam URL Path, misal /products/{idProduct}, atau /categories/{idCategory}, dan lain-lain
  • ExpressJS mendukung penambahan parameter dalam route path, dengan menggunakan prefix : titik dua
  • Semua data parameter itu bisa kita tambahkan regex jika kita mau, misal /products/:id(\\d+), artinya kita menambah parameter id, dimana id tersebut harus digit
  • Data route parameter secara otomatis bisa kita ambil sebagai attribute di req.params

Detail : https://expressjs.com/en/4x/api.html#req.params

app.get("/product/:id", (req, res) => {
const id = req.params.id;
res.send(id);
});

Route Function

  • Kadang ada kasus ketika kita membuat route path yang sama untuk beberapa tipe HTTP Method
  • Pada kasus ini, kita bisa memanfaatkan route(path) function sehingga tidak perlu mendeklarasikan nama path sama untuk beberapa route

Detail : https://expressjs.com/en/4x/api.html#app.route

app
.route("/product")
.get((req, res) => {
res.send("get product");
})
.post((req, res) => {
res.send("create product");
})
.put((req, res) => {
res.send("update product");
});

Router

  • Saat kita membuat Application ExpressJS, secara default sudah terdapat object Router nya
  • Namun, kita bisa membuat object Router sendiri jika kita mau, hal ini sangat cocok jika kita ingin melakukan grouping Router, lalu misal kita bisa menambahkan Router tersebut ke Application seperti Middleware
  • Ini sangat cocok ketika kita ingin membuat fitur modular yang bisa mengaktifkan atau menonaktifkan router secara dinamis misalnya
  • Dengan object Router, kita bisa memiliki Middleware dan Routing secara independen

express router : https://expressjs.com/en/4x/api.html#express.router

router : https://expressjs.com/en/4x/api.html#router

const router = express.Router();

// midleware
router.use(middleware);

// path router
router.get("/", () => {});
  • Dalam HTTP, salah satu fitur yang biasa digunakan untuk pertukaran data dari Server dan Client adalah Cookie
  • Banyak yang menggunakan Cookie sebagai Session misalnya
  • Sayangnya, secara default, ExpressJS tidak mendukung Cookie, tapi jangan khawatir, kita bisa menggunakan Third-Party Middleware untuk mendukung Cookie ini yaitu Cookie Parser

Cookie Parser adalah salah satu Third-Party Middleware yang bisa kita gunakan untuk mendukung fitur Cookie, dimana dengan Cookie Parser, kita secara otomatis menyimpan data ke Cookie, atau mengambil data ke Cookie

Detail : https://www.npmjs.com/package/cookie-parser

npm install cookie-parser

Setelah kita memasang Cookie Parser Middleware, kita bisa secara otomatis membaca Cookie yang dikirim dari Client melalui req.cookies

Detail : https://expressjs.com/en/4x/api.html#req.cookies

import cookieParser from "cookie-parser";

app.use(cookieParser());

app.get("/", (req, res) => {
const name = req.cookies["name"]; // or req.cookies.name
});

Sedangkan untuk menulis Cookie, kita bisa tambahkan di response, dengan method res.cookie(key, value, setting)

Detail: https://expressjs.com/en/4x/api.html#res.cookie

app.post("/login", (req, res) => {
const name = req.body.name;
res.cookie("login", name, { path: "/" });
res.json({ sayHello: `hello ${name}` });
});

Dan untuk menghapus Cookie, kita bisa gunakan res.clearCookie(key, setting)

Detail : https://expressjs.com/en/4x/api.html#res.clearCookie

  • Salah satu kelemahan ketika kita menyimpan data di Cookie adalah, Cookie bisa dimodifikasi oleh Client, misal kita bisa modifikasi Cookie di Browser kita
  • Salah satu cara untuk menjaga agar Cookie tidak dimodifikasi adalah, kita menambahkan Signature pada Cookie kita
  • Setiap nilai Cookie akan ada Signature, dimana ketika nilai Cookie diubah, otomatis Signature tidak akan sama lagi, dan secara otomatis value Cookie tidak dianggap valid lagi
  • Fitur ini sudah ada di Cookie Parser dengan nama Signed Cookie
  • Kita wajib menyebutkan Cookie mana yang ingin di Signed, ketika kita membuat Cookie di response
  • Selain itu, kita juga perlu memasukkan Secret Key untuk digunakan ketika proses pembuatan Signature, pastikan Secret Key nya aman dan tidak mudah ditebak
app.use(cookieParser("RAHASIA"));

app.get("/", (req, res) => {
const name = req.signedCookies["login"];
res.json({ sayHello: `hello ${name}` });
});

app.post("/login", (req, res) => {
const name = req.body.name;
res.cookie("login", name, { path: "/", signed: true });
res.json({ sayHello: `hello ${name}` });
});

// Cookie -> "login=s%3Ajoko.5JIi4V1qI408khb6hyfNhvt46b9aBHFisyi6QcSrD8E; Path=/"

Response Body Lainya

Response Body MethodKeterangan
res.send(data)Response berupa raw data
res.download(path, filename, option)Response berupa file download
res.json(body)Response berupa JSON
res.redirect(url)Response redirect url
res.sendFile(path, option)Response berupa file

Error Handling

  • Apa yang terjadi jika misal terjadi Error di aplikasi kita? Secara otomatis Error tersebut akan ditangkap oleh ExpressJS
  • Lalu detail error nya akan ditampilkan di response-nya secara otomatis
  • Kadang, ada kasus kita ingin mengubah cara menampilkan error, atau bahkan kita memang berharap terjadi error, misal Validation Error
  • Pada kasus seperti ini, untungnya ExpressJS memiliki fitur Error-Handling Middleware, dimana kita bisa membuat Middleware dan akan dieksekusi ketika terjadi error
  • Berbeda dengan Middleware biasanya, pada Error-Handling Middleware, diperlukan empat parameter, dimana diawali dengan parameter error nya
index.js
const errorHandler = (err, req, res, next) => {
res.status(500).send("Terjadi error : " + err.message);
};

app.use(errorHandler); // tempatkan di paling bawah

Static File

  • Saat membuat Web, kadang kita ingin menampilkan static file seperti html, css, javascript, gambar, atau file lainnya
  • Jika kita harus membuat route untuk setiap file, maka akan menyulitkan.
  • Untungnya, terdapat middleware yang bisa kita gunakan untuk menyediakan static file.
  • Middleware ini secara otomatis akan mencari file, jika file ada, maka akan dikembalikan file tersebut, jika tidak ada, maka akan dilanjutkan ke middleware atau route selanjutnya
  • Kita bisa menggunakan Middleware express.static()

Detail : http://expressjs.com/en/4x/api.html#express.static

app.use(express.static(__dirname + "/static")); // /static/*
app.use("/static", express.static(__dirname + "/static")); // /static/static/*

Template Engine

  • Saat membuat web menggunakan ExpressJS, maka jika kita membuat string HTML lalu kita kirim menggunakan response, maka hal itu sangat menyulitkan
  • Biasanya, untuk mempermudah itu, kita bisa menggunakan Template Engine
  • Template Engine adalah library yang digunakan untuk membuat template lalu mempermudah kita ketika ingin menampilkan data di template nya
  • Biasanya template nya dalam bentuk HTML, dan data nya bisa kita ubah sesuai dengan data yang ingin kita tampilkan di HTML tersebut

Template Engine Library

ExpressJS Sendiri tidak memiliki fitur Template Engine, oleh karena itu kita perlu menggunakan library lain untuk menggunakan Template Engine Ada banyak sekali library Template Engine di NodeJS, misal :

  1. Mustache : https://github.com/janl/mustache.js/
  2. Pug : https://github.com/pugjs/pug
  3. EJS : https://github.com/mde/ejs
  4. Marko : https://github.com/marko-js/marko
  5. Dan lain-lain

Disini saya menggunakan Mustache

Hal ini dikarenakan Mustache merupakan template engine yang sangat mudah digunakan, kita tidak akan menginstall Mustache secara manual, kita akan menggunakan bantuan library Mustache Express

Detail : https://www.npmjs.com/package/mustache-express

Install Mustache

npm install mustache-express

Setup Mustche

index.js
import mustacheExpress from "mustache-express";

app.engine("html", mustacheExpress());
app.set("view engine", "html");
app.set("views", __dirname + "/views");

app.get("/", (req, res) => {
res.render("index", {
title: "mustache page",
say: "hello world",
});
});

Buat file index.html di views/index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{title}}</title>
</head>
<body>
<p>{{say}}</p>
</body>
</html>

File Upload

  • Sebelumnya kita belum membahas bagaimana jika Request Body yang dikirim adalah File Upload atau Multipart Form Data?
  • Sayangnya, secara default di ExpressJS, tidak ada fitur untuk membaca File Upload
  • Tapi kita bisa menggunakan Third-Party Middleware lain untuk membaca File Upload

Install

npm install express-fileupload

Next

import expressFileUpload from "express-fileupload";

app.use(expressFileUpload());

app.post("/file", async (req, res) => {
const textFile = req.files.article;
await textFile.mv(__dirname + "/upload/" + textFile.name);

res.send(`hello ${req.body.name}, file uploaded ${textFile.name}`);
});

Not Found Error

  • Saat user melakukan request ke URL yang tidak tersedia, maka secara default ExpressJS akan mengembalikan halaman 404
  • Kadang ada kasus dimana kita ingin membuat halaman 404 sendiri
  • Pada kasus ini, kita bisa menambahkan middleware di posisi paling akhir
  • Middleware tersebut akan dipanggil jika memang tidak terdapat route yang tersedia untuk route path yang diakses
index.js
const notFoundMiddleware = (req, res, next) => {
res.status(404).send("404 Not Found Euy");
};

app.use(notFoundMiddleware);