Single All 20 Juni 2019 5 min

Tutorial ORM Objection.js di Node.js Fastify

Object-Relational Mapping di Fastify JS dengan Objection JS

Tutorial ORM Objection.js di Node.js Fastify

Object-Relational Mapping di Fastify JS dengan Objection JS

Image Halo devlopah, kali ini gue mau berbagi insight mengenai cara menggunakan ORM Objection.js di Node.js fastify. Tapi tentu hari gini pasti ada yang make doang tapi ngga tau ORM tuh apasih?

“Object-relationalmapping(ORM) is a programming technique in which a metadata descriptor is used to connectobjectcode to arelationaldatabase.”

— techopedia.com Jadi intinya, ORM ini adalah sebuah objek kode yang akan terhubung dengan database kita agar developer semakin mudah dalam membuat query. Seperti yang kita ketahui, ORM itu sangat mempermudah proses dalam melakukan query ke database, rather than writing “SELECT * FROM table_name”, sebagian developer lebih milih sesuatu yang singkat dengan menggunakan ORM. Tujuannya apasih? Tentu saja untuk mempermudah proses peng-query-an ke DB, karena memang cukup menyingkat dan enak dibaca. Namun ada beberapa developer yang concern terkait masalah performa. Bagi beberapa developer yang “masa bodoh” mungkin ngga akan peduli, tapi sebenernya ngaruh ngga sih ke performa? Jawabannya “Ngaruh”. Lah terus ngapain saya pake kalo ngaruh ke performa? Tunggu sebentar gan, ngaruh ini tergantung dari library yang agan gunakan, kalau agan menggunakan library yang sudah banyak digunakan dan di repositorynya belum ada issue banyak terkait performa saya kira library yang agan gunakan aman. Kalaupun agan ingin membuat library agan sendiri akan jauh lebih baik, karena agan bisa“men-tweak”performa sesuai kadar kebutuhan agan, tapi tentu itu akan memakan waktu kan? Selain itu isu performa juga banyak tidak hanya selalu dari code, bisa saja dari struktur DB (struktur tabel, indexing, length column), bandwidth, I/O, maupun RAM. Oke skip dulu pembahasan lengkapnya. Mungkin bagi agan-agan yang menggunakan Node.js ngga akan asing sama yang namanya “Sequelize”, yap itu adalah ORM yang kerap digunakan untuk Express dengan librarymysql2. Namun karena berhubung library yang saya gunakan adalahmysql, dan saya belum pernah (serta malas) untuk mencoba denganSequelizedan pengen sesuatu yang baru, maka saya cari-cari di internet ada library yang bagus bernamaObjection.js. Disini saya ngga akan compare antara dua library tersebut, jadi skip harapannya untuk melihat hasil komparasi. Oke lanjut, kita buat project baru dulu lalu jangan lupa

npm init -y

Install Fastify, Objection.js, MySQL, beserta kroninya yaitu Knex.

npm install objection knex fastify fastify-formbody dotenv mysql --save

buat file bernama server.js dan isi file tersebut dengan code dibawah ini

require('dotenv').config();const fastify = require('fastify')({logger: true});fastify.register(require('fastify-formbody'));fastify.register(require('./routes'), { prefix: '/v1' });const start = async () => {try {await fastify.listen(process.env.PORT || 3000);console.log(`Server listening on ${fastify.server.address().port}`)} catch (err) {console.log(err);process.exit(1)}};start();

lanjut, sekarang kita buat connection.js yang akan jadi file untuk koneksi ke database.

require('dotenv').config();var knex = require('knex')({client: 'mysql',connection: {host: process.env.DB_HOST,user: process.env.DB_USERNAME,password: process.env.DB_PASSWORD,database: process.env.DB_DATABASE},pool: { min: 0, max: 3 } //Menggunakan fungsi pool agar menjaga koneksi ke DB tetep tersambung});module.exports = knex;

Jangan lupa untuk membuat file .env dan isi dengan data dibawah

PORT=3000DB_HOST=127.0.0.1DB_DATABASE=[Masukkan nama DB]DB_USERNAME=homesteadDB_PASSWORD=secret

Kasus yang akan kita kerjakan adalah kita akan membuat dua table. Table users akan menyimpan nama pengguna dan table phone akan menyimpan nomor telfon dari pengguna kita yang bisa saja memiliki nomor telfon lebih dari satu.

CREATE TABLE `users` (`id` INT NOT NULL AUTO_INCREMENT,`name` VARCHAR(45) NULL,`email` VARCHAR(45) NULL,PRIMARY KEY (`id`));
CREATE TABLE `phone` (`id` INT NOT NULL AUTO_INCREMENT,`user_id` INT NOT NULL,`phone_number` VARCHAR(15) NOT NULL,`description` VARCHAR(50) NULL,PRIMARY KEY (`id`),INDEX `fk_phone_1_idx` (`user_id` ASC),CONSTRAINT `fk_phone_1`FOREIGN KEY (`user_id`)REFERENCES `users` (`id`)ON DELETE NO ACTIONON UPDATE NO ACTION);

Oke setelah berhasil membuat kedua table yuk kita lanjut. Kita akan membuat UserModel.js yang akan menjadi Model ORM ke database.

const { Model } = require('objection');const knex = require('./connection');const PhoneModel = require('./PhoneModel');Model.knex(knex);class UserModel extends Model {static gettableName() {return 'users';}static getrelationMappings() {return {phone: {relation: Model.HasManyRelation,modelClass: PhoneModel,join: {from: 'users.id',to: 'phone.user_id'}}};}}module.exports = UserModel;

padarelationMappings(),kita akan membuat relational yang berfungsi untuk memudahkan kita melihat relasi antar table. Ada beberapa tipe relation, tapi disini saya ngga jabarin satu-persatu ya bedanya many to many, one to many, dsbnya karena saya anggap ketika anda membaca tutorial ini anda sudah tingkat intermediate dan sudah paham dengan konsep dasar database. HasOneThroughRelation: Use this relation when the model is related to a single model through a join table ManyToManyRelation: Use this relation when the model is related to a list of other models through a join table HasOneRelation: Just likeHasManyRelationbut for one related row HasManyRelation: Use this relation when the related model has the foreign key BelongsToOneRelation: Use this relation when the source model has the foreign key Sekarang buat PhoneModel.js

const { Model } = require('objection');const knex = require('./connection');const UserModel = require('./UserModel');Model.knex(knex);class PhoneModel extends Model {static gettableName() {return 'phone';}static getrelationMappings() {return {users: {relation: Model.BelongsToOneRelation,modelClass: UserModel,join: {from: 'phone.user_id',to: 'users.id'}}}}}module.exports = PhoneModel;

Seperti biasa kita akan membuat dulu response controller yang dapat di “reusable”, buatlah ResponseController.js dan masukkan kode dibawah ini.

'use strict'function ok (values, message, reply) {return reply.code(200).header('Content-Type', 'application/json; charset=utf-8').send({code : 200,values : values,message : message,});}function notFound (values, message, reply) {return reply.code(200).header('Content-Type', 'application/json; charset=utf-8').send({code : 400,values : values,message : message,});}module.exports = {ok, notFound}

Lalu barulah kita buat UserController.js

'use strict';const res = require('./ResponseController')const userModel = require('./UserModel');async function get (request, reply) {const users = await userModel.query().eager('phone').orderBy('name', 'ASC');return res.ok(users, "", reply)}async function store (request, reply) {let name = request.body.name;let email = request.body.email;const users = await userModel.query().insert({ name: name, email: email});return res.ok(users, "Successfully add users", reply)}async function show (request, reply) {let id = request.params.id;const users = await userModel.query().findById(id);return res.ok(users, "", reply)}async function update (request, reply) {let name = request.body.name;let email = request.body.email;let id = request.body.id;const users = await userModel.query().findById(id).patch({name: name, email: email});return res.ok(users, "Successfully update users", reply)}async function destroy (request, reply) {const users = await userModel.query().deleteById(request.body.id);return res.ok(users, "Successfully delete users", reply)}module.exports = {get, show, destroy, store, update};

Kita lihat pada method get, kita menggunakan query.eageryang berfungsi untuk menampilkan data dari model yang berelasi dari table users yaitu model phone. Lanjut, kita buat PhoneController.js

'use strict'const res = require('./ResponseController')const phoneModel = require('./PhoneModel');async function get (request, reply) {const phone = await phoneModel.query().orderBy('user_id', 'ASC');return res.ok(phone, "", reply)}async function store (request, reply) {let userId = request.body.user_id;let phoneNum = request.body.phone;let description = request.body.description;const phone = await phoneModel.query().insert({ user_id: userId, phone_number: phoneNum, description: description });return res.ok(phone, "Successfully add phone number", reply)}async function show (request, reply) {let id = request.params.user_id;const phone = await phoneModel.query().where('user_id', '=', id);return res.ok(phone, "", reply)}async function update (request, reply) {let phoneNum = request.body.phone;let id = request.body.id;let description = request.body.description;const person = await phoneModel.query().findById(id).patch({phone_number: phoneNum, description: description});return res.ok(person, "Successfully update phone number", reply)}async function destroy (request, reply) {const phone = await phoneModel.query().deleteById(request.body.id);return res.ok(phone, "Successfully delete phone number", reply)}module.exports = {get, show, destroy, store, update};

Terakhir, kita buat routes.js tempat menaruh routingnya

let users = require('./UserController');let phone = require('./PhoneController');async function routes (fastify, options) {fastify.get('/users', users.get);fastify.get('/users/:id', users.show);fastify.post('/users', users.store);fastify.put('/users', users.update);fastify.delete('/users', users.destroy);fastify.get('/phone', phone.get);fastify.get('/phone/:user_id', phone.show);fastify.post('/phone', phone.store);fastify.put('/phone', phone.update);fastify.delete('/phone', phone.destroy);}module.exports = routes;

Sekarang silahkan jalankan dan coba dengan Postman

node server.js

Jangan lupa untuk menggunakanx-www-form-urlencodeduntuk melakukanPOST/PUT/DELETE.

Image

Image Karena kita menggunakan fungsieagerpada select all user maka kita akan melihat relasi antara table users dan phone seperti pada gambar dibawah ini.

Image Untuk route yang lain silahkan dicoba sendiri ya ^^ Semoga membantu dan happy coding! ^^

Artikel ini merupakan konten legacy dari blog Medium (Tahun 2019). Beberapa konsep atau sintaks mungkin sudah mengalami perubahan pada versi terbaru.