Halo, selamat datang di Ruang Developer. Kali ini kita akan belajar bagaiaman cara membuat REST API menggunakan Node.js, Express, Sequelize, dan MySQL.

Express adalah salah satu web framework Node.js yang banyak sekali digunakan untuk membuat API server. Express mendukung routing, middleware, dan view system. Sequelize adalah ORM berbasis promise di Node.js yang mendukung Postgres, MySQL, SQL Server. Sequelize menyediakan cara yang mudah untuk mengelola data yang ada dalam database.

Sebelum mulai:

  1. Pastikan kamu sudah menginstall dan menjalankan MySQL server di komputer kamu.
  2. Pastikan kamu sudah menginstall Node.js di komputer kamu.
  3. Pastikan kamu sudah mengerti atau setidaknya pernah belajar bagaimana cara menggunakan database MySQL
  4. Pastikan kamu sudah mengerti atau setidaknya pernah belajar pemrogramman menggunakan javascript dan Node.js.
  5. Pastikan kamu sudah mengerti atau setidaknya pernah belajar tentang REST API

Apa Yang Akan Kita Buat?

Pada tutorial ini kita akan membuat sebuah REST API server sederhana untuk mengelola data buku. Adapun beberapa endpoint yang akan kita buat adalah sebagai berikut:

Metode Endpoint Aksi
POST /api/books Menambah data buku
GET /api/books Mendapatkan semua data buku
GET /api/books/:id Mendapatkan data buku berdasarkan id
PUT /api/books/:id Memperbarui data buku berdasarkan id
DELETE /api/books/:id Menghapus data buku berdasrkan id

Membuat Project Node.js

Membuat folder project:

mkdir node-book-api
cd node-book-api

Inisialisasi project Node.js

npm init

package name: (book-api)
version: (1.0.0)
description: Node.js Book REST API with Express, Sequelize, and MySQL
entry point: (index.js) ./src/app.js
test command:
git repository:
keywords: Node.js, Express, Sequelize, MySQL, REST, API
author: www.ruangdeveloper.com
license: (ISC)

Is this ok? (yes) yes

Setelah inisialisasi project maka akan ada sebuah file package.json dalam folder project kamu yang terlihat kurang lebih seperti ini:

{
  "name": "book-api",
  "version": "1.0.0",
  "description": "Node.js Book REST API with Express, Sequelize, and MySQL",
  "main": "./src/app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "Node.js",
    "Express",
    "Sequelize",
    "MySQL",
    "REST",
    "API"
  ],
  "author": "www.ruangdeveloper.com",
  "license": "ISC"
}

Install modul yang diperlukan:

npm install express sequelize mysql2

Membuat Express Web Server

Langkah berikutnya kita akan membuat web server menggunakan Express. Pada root folder, buatlah sebuah folder bernama src dan di dalamnya buatlah file bernama app.js

Isi file app.js kurang lebih seperti ini:

const express = require("express")

const app = express()
const port = process.env.PORT || 3000

app.use(express.json())
app.use(express.urlencoded({ extended: true }))

app.get("/", (req, res) => {
    res.json({
        message: "Node.js Book REST API Server"
    })
})

app.listen(port, () => console.log(`Server up and running on port ${port}`))

Yang kita lakukan pada file tersebut adalah:

  • Import modul express yang akan kita gunakan untuk membuat web server
  • Membuat aplikasi express, menambahkan middleware json parser dan urlencoded menggunakan method app.use()
  • Membuat route untuk root url menggunakan method app.get() untuk uji coba
  • Listen port 3000 untuk request yang masuk

Mari kita coba jalankan aplikasi menggunakan perintah node /src/app.js di terminal, lalu buka browser kamu pada url berikut:

http://127.0.0.1:3000/

Berikut ini adalah hasilnya di browser:

Node.js REST API

Membuat Konfigurasi

Dalam folder src, buat sebuah folder baru bernama configs lalu di dalamnya buat file bernama database.config.js yang berisi kode seperti berikut ini:

module.exports = {
    HOST: "localhost",
    USER: "root",
    PASSWORD: "root",
    DB: "book_api",
    DIALECT: "mysql",
}

Sesuaikan HOST, USER, PASSWORD, dan DB dengan konfigurasi database kamu ya.

Membuat Koneksi Database

Dalam folder src buatlah sebuah folder baru bernama database kemudian didalamnya buatlah sebuah file bernama index.js yang berisi kode seperti berikut ini:

const { Sequelize } = require("sequelize")
const { DB, USER, PASSWORD, HOST, DIALECT } = require("../configs/database.config")

const database = new Sequelize(DB, USER, PASSWORD, {
    host: HOST,
    dialect: DIALECT
})

module.exports = database

Pada file tersebut kita membuat koneksi database menggunakan Sequelize berdasarkan konfigurasi database yang sebelumnya sudah kita buat.

Selanjutnya kita perbarui file app.js yang ada di dalam folder src. Tambahkan kode berikut:

// import model
const database = require("./database")

database.sync({ force: true }).then(() => {
    console.info("database synced")
}).catch(err => {
    console.error("failed to sync database: " + err.message)
})

Fungsi dari kode ini adalah melakukan sinkronisasi tabel yang ada dalam database kita agar sesuai dengan skema model yang nantinya kita buat.

Seluruh file app.js akan menjadi seperti berikut:

const express = require("express")
const database = require("./database")

const app = express()
const port = process.env.PORT || 3000

app.use(express.json())
app.use(express.urlencoded({ extended: true }))

database.sync({ force: true }).then(() => {
    console.info("database synced")
}).catch(err => {
    console.error("failed to sync database: " + err.message)
})

app.get("/", (req, res) => {
    res.json({
        message: "Node.js Book REST API Server"
    })
})

app.listen(port, () => console.log(`Server up and running on port ${port}`))

Perhatikan bahwa kode { force: true } akan membuat tabel yang sudah ada di drop dan dibuat ulang. Dalam production mode, kamu harus merubahnya menjadi false agar data yang ada di database tidak hilang.

Membuat Model

Dalam folder src buatlah sebuah folder baru bernama models kemudian di dalamnya buatlah sebuah file bernama book.model.js yang berisi kode seperti berikut ini:

const { DataTypes } = require("sequelize")
const database = require("../database")

const Book = database.define("book", {
    title: {
        type: DataTypes.STRING,
        allowNull: false,
    },
    author: {
        type: DataTypes.STRING,
        allowNull: false
    },
    summary: {
        type: DataTypes.TEXT,
        allowNull: false,
    },
    publisher: {
        type: DataTypes.STRING,
        allowNull: false
    }
})

module.exports = Book

Book model ini merepresentasikan tabel buku yang nanti dibuat secara otomatis di dalam database kita. Sequelize telah menyediakan operasi CRUD sehingga kita tidak perlu membuatnya secara manual lagi. Beberpaa operasi yang disediakan adalah sebagai berikut:

  • Membuat data buku: create(object)
  • Mendapatkan semua data buku: findAll()
  • Mendapatkan data buku berdasarkan id: findOne({where: {id:id}})
  • Memperbarui data buku berdasarkan id: update(data, where: {id:id})
  • Menghapus data buku berdasarkan id: destroy(where: {id:id})

Membuat Controller

Dalam folder src bualah sebuah folder baru bernama controllers dan di dalamnya buat file baru bernama book.controller.js yang berisi kode berikut:

const Book = require("../models/book.model")

exports.create = async (req, res) => {
    try {
        const { title, author, summary, publisher } = req.body

        const book = await Book.create({
            title,
            author,
            summary,
            publisher
        })

        return res.status(201).json({
            status: 201,
            success: true,
            message: "new book created",
            data: {
                book: book,
            },
            error: null
        })
    } catch (error) {
        console.error(error)
        return res.status(500).json({
            status: 500,
            success: false,
            message: "internal server error",
            data: null,
            error: "Internal Server Error"
        })
    }
}

exports.all = async (req, res) => {
    try {
        const books = await Book.findAll()
        return res.status(200).json({
            status: 200,
            success: true,
            message: "ok",
            data: {
                books,
            },
            error: null
        })
    } catch (error) {
        console.error(error)
        return res.status(500).json({
            status: 500,
            success: false,
            message: "internal server error",
            data: null,
            error: "Internal Server Error"
        })
    }
}

exports.find = async (req, res) => {
    try {
        const { id } = req.params
        const book = await Book.findOne({
            where: {
                id: id
            },
        })

        if (!book) {
            return res.status(404).json({
                status: 404,
                success: false,
                message: "book not found",
                data: null,
                error: "Book Not Found"
            })
        }

        return res.status(200).json({
            status: 200,
            success: true,
            message: "ok",
            data: {
                book: book,
            },
            error: null
        })
    } catch (error) {
        console.error(error)
        return res.status(500).json({
            status: 500,
            success: false,
            message: "internal server error",
            data: null,
            error: "Internal Server Error"
        })
    }
}

exports.update = async (req, res) => {
    try {
        const { id } = req.params

        const updated = await Book.update(req.body, {
            where: {
                id: id,
            }
        })

        if (!updated[0]) {
            return res.status(200).json({
                status: 200,
                success: false,
                message: "failed to update book",
                data: null,
                error: "Failed To Update Book"
            })
        }

        return res.status(200).json({
            status: 200,
            success: true,
            message: "book updated",
            data: null,
            error: null
        })

    } catch (error) {
        console.error(error)
        return res.status(500).json({
            status: 500,
            success: false,
            message: "internal server error",
            data: null,
            error: "Internal Server Error"
        })
    }
}

exports.destroy = async (req, res) => {
    try {
        const { id } = req.params

        const destroyed = await Book.destroy({
            where: {
                id: id,
            }
        })

        if (!destroyed) {
            return res.status(200).json({
                status: 200,
                success: false,
                message: "failed to delete book",
                data: null,
                error: "Failed To Delete Book"
            })
        }

        return res.status(200).json({
            status: 200,
            success: true,
            message: "book deleted",
            data: null,
            error: null
        })

    } catch (error) {
        console.error(error)
        return res.status(500).json({
            status: 500,
            success: false,
            message: "internal server error",
            data: null,
            error: "Internal Server Error"
        })
    }
}

Dalam file controller tersebut kita membuat beberapa fungsi yaitu sebagai berikut:

  • create: Membuat data buku baru
  • all: Mendapatkan semua data buku
  • find: Mendapatkan data buku berdasarkan id
  • update: Memperbarui data buku berdasarkan id
  • destroy: Menghapus data buku berdasarkan id

Mendefinisikan Route

Dalam folder src buatlah sebuah folder baru bernama routes kemudian di dalamnya buat sebuah file bernama book.route.js yang berisi kode seperti berikut ini:

const router = require("express").Router()

const { all, find, create, update, destroy } = require("../controllers/book.controller")

router.post("/", create)
router.get("/", all)
router.get("/:id", find)
router.put("/:id", update)
router.delete("/:id", destroy)

module.exports = router

Pada kode tersebut kita mendefinisikan beberapa endpoint yang sebelumnya ingin kita buat.

Menambahkan Route Ke Express Server

Buka kembali file app.js dalam folder src kemudian tambahkan kode berikut ini:

// import book route
const bookRoute = require("./routes/book.route")

// tambahkan book route ke dalam aplikasi
app.use("/api/books", bookRoute)

Sekarang file app.js kita akan terlihat seperti berikut ini:

const express = require("express")
const database = require("./database")
const bookRoute = require("./routes/book.route")

const app = express()
const port = process.env.PORT || 3000

app.use(express.json())
app.use(express.urlencoded({ extended: true }))

database.sync({ force: true }).then(() => {
    console.info("database synced")
}).catch(err => {
    console.error("failed to sync database: " + err.message)
})

app.get("/", (req, res) => {
    res.json({
        message: "Node.js Book REST API Server"
    })
})

app.use("/api/books", bookRoute)

app.listen(port, () => console.log(`Server up and running on port ${port}`))

Menguji REST API

Setelah semuanya selesai, saatnya kita menguji aplikasi kita. Untuk menguji rest api kamu tidak bisa hanya menggunakan browser ya. Kamu bisa menggunakan tool REST Client seperti Postman atau Insomnia. Kebetulan pada tutorial ini saya menggunakan aplikasi Insomnia.

Sebelum melakukan pengujian, pastikan server MySQL kamu sudah aktifkan dan aplikasi sudah dijalankan.

Berikut ini adalah hasil pengujian saya menambahkan data buku

Node.js REST API

Mendapatkan semua data buku

Node.js REST API

Mendapatkan data buku berdasarkan id

Node.js REST API

Memperbarui data buku berdasarkan id

Node.js REST API

Menghapus data buku berdasarkan id

Node.js REST API

(Tambahan) Menggunakan Middleware Untuk Validasi Data

REST API Server kita sebenarnya sudah berfungsi sesuai rencana awal. Namun masih banyak yang belum kita selesaikan, salah satunya adalah validasi data yang diterima. Pada bagian ini dicontohkan bagaimana caranya menggunakan middleware untuk validasai data.

Kembali ke project, dalam folder src buatlah satu buah folder baru bernama middlewares dan didalamnya buatlah sebuah file baru bernama validation.middleware.js yang isinya seperti berikut ini:

exports.createBookValidation = (req, res, next) => {
    const { title, author, summary, publisher } = req.body

    if (title === undefined || title == "") {
        return res.status(400).json({
            status: 400,
            success: false,
            message: "bad request",
            data: {
                original: req.body
            },
            error: "Title field is required"
        })
    }

    if (author === undefined || author == "") {
        return res.status(400).json({
            status: 400,
            success: false,
            message: "bad request",
            data: {
                original: req.body
            },
            error: "Author field is required"
        })
    }

    if (summary === undefined || summary == "") {
        return res.status(400).json({
            status: 400,
            success: false,
            message: "bad request",
            data: {
                original: req.body
            },
            error: "Summary field is required"
        })
    }

    if (publisher === undefined || publisher == "") {
        return res.status(400).json({
            status: 400,
            success: false,
            message: "bad request",
            data: {
                original: req.body
            },
            error: "Publisher field is required"
        })
    }

    next()
}

Dalam file tersebut kita membuat satu buah middleware untuk melakukan validasi sederhana pada request body ketika ingin menambahkan buku baru.

Membuat middleware di Express sangat mudah sekali, kita tinggal membuat sebuah fungsi yang memiliki tiga buah parameter yaitu req, res, dan next. req adalah request object yang diterima, res adalah response object yang akan dikirimkan, dan next adalah sebuah fungsi yang harus kita panggil jika ingin meneruskan request ke middleware atau handler berikutnya. Jika tidak memanggil fungsi next maka kamu harus mengirimkan response pada dari middleware tersebut agar server tidak hang.

Oke, langkah selanjutnya adalah menambahkan middleware ini pada route kita. Buka file book.route.js kemudian modifikasi route untuk create book menjadi seperti berikut ini:

router.post("/", createBookValidation , create)

Jangan lupa import middleware-nya.

const { createBookValidation } = require("../middlewares/validation.middleware")

File route kita sekarang menjadi seperti ini:

const router = require("express").Router()

const { all, find, create, update, destroy } = require("../controllers/book.controller")
const { createBookValidation } = require("../middlewares/validation.middleware")

router.post("/", createBookValidation , create)
router.get("/", all)
router.get("/:id", find)
router.put("/:id", update)
router.delete("/:id", destroy)

module.exports = router

Langkah selanjutnya, jalankan kembali aplikasi, dan cobalah untuk mengirimkan post request tanpa mengirim body apapun. Maka respoonse yang didapatkan akan seperti ini:

{
	"status": 400,
	"success": false,
	"message": "bad request",
	"data": {
		"original": {}
	},
	"error": "Title field is required"
}

Response tersebut dikirimkan oleh middleware kita karena validasi gagal.

Silahkan bereksperimen untuk membuat validasai lainnya sehingga semua endpoint memiliki validasai yang sesuai ya. Kamu juga bisa mencoba menggunakan library validasi yang banyak diemukan di npmjs.

Source Code: Source code untuk tutorial ini dapat kamu lihat di sini

comments powered by Disqus
Lightbox