Search by

    Terakhir diperbaharui: Oct 24, 2020

    Design REST API

    Tabel CRUD

    Kita buat sebuah tabel untuk menjelaskan detail operasi CRUD yang ada di REST API:

    OperasiHTTP MethodURLURL Params
    CreatePOST/note
    Read (satu note)GET/note:id
    Read (semua note)GET/notes
    UpdatePUT/note/:id
    DeleteDELETEnote/:id

    Project Setup

    Step by step

    1. Buka terminal kemudian clone Repository Front End dari DinoTes
    1$ git clone https://github.com/devsaurus-class/dinotes-app.git
    1. Pindah ke dalam direktori dinotes-app dan install dependencies
    1$ cd dinotes-app
    2$ yarn install
    1. Di dalam folder dinotes-app buat sebuah folder dengan nama api.

    Struktur folder:

    1(dinotes - app) | --api | --node_modules | --public | --src;
    1. Tambahkan package express ke dalam project
    1$ yarn add express
    1. Buat sebuah Express app

    Buat sebuah file bernama server.js di dalam folder api dan salin code berikut:

    1const express = require('express');
    2const app = express();
    3const port = 3001;
    4
    5app.listen(port, () => {
    6 console.log(`REST API listening at http://localhost:${port}`);
    7});

    Pada code di atas kita membuat sebuah aplikasi express yang aktif di port 3001. Perlu diingat bahwa front end dari dinotes menggunakan port 3000, oleh karena itu kita gunakan port lain selain port 3000, tidak harus 3001.

    Untuk menjalankan aplikasi express di atas eksekusi perintah node ./api/server.js

    Development

    Untuk melihat hasil dari setiap perubahan yang kita buat pada aplikasi express kita harus me-restart aplikasi secara manual. Hal ini sedikit merepotkan.

    Kita bisa gunakan package bernama nodemon untuk membantu kita me-restart aplikasi secara otomatis setiap kali ada perubahan.

    Tambahkan package nodemon ke dalam project.

    1$ yarn add global nodemon

    Dengan perintah di atas package nodemon akan ditambahkan secara global, sehingga nodemon akan tersedia di system path dan kita bisa memanggilnya di terminal. Perintah ini sama dengan npm install -g nodemon.

    Selanjutnya untuk menjalankan aplikasi express kita bisa gunakan perintah:

    1$ nodemon ./api/server.js

    Atau kamu bisa navigasi ke folder api kemudian eksekusi perintah

    1$ nodemon server.js

    REST API

    Untuk permulaan setiap HTTP method yang dipanggil hanya akan menampilkan sebuah pesan bukan data.

    Contoh:

    request GET yang diterima server akan direspon dengan pesan Received a GET request.

    POST

    • Menambahkan note

    Sekarang kita tambahkan sebuah route untuk menghandle POST request yang diarahkan ke url /note.

    1const express = require('express');
    2const app = express();
    3const port = 3001;
    4
    5app.post('/note', (req, res) => {
    6 res.send('Received a POST request');
    7});
    8
    9app.listen(port, () => {
    10 console.log(`Server listening at http://localhost:${port}`);
    11});

    Untuk menguji route yang sudah dibuat, kita bisa menggunakan sebuah aplikasi sederhana bernama curl, yang umumnya sudah terinstall pada Operating System.

    curl adalah command-line tool yang digunakan untuk mengirim data via URL dan support puluhan protokol termasuk protokol HTTP.

    Jika kamu menggunakan windows mungkin kamu harus menginstallnya secara manual. Kamu bisa download di sini.

    Buka terminal dan jalankan perintah berikut ini:

    1$ curl -X POST http://localhost:3001/note

    Hasilnya:

    post curl

    Selanjutnya kita tambahkan route method yang lain:

    GET

    • Mendapatkan semua notes
    1app.get('/notes', (req, res) => {
    2 res.send('Receive GET request');
    3});
    • Mendapatkan satu note
    1app.get('/note/:id', (req, res) => {
    2 res.send('Received GET request with parameter');
    3});

    PUT

    • Update note
    1app.put('/note/:id', (req, res) => {
    2 res.send('Received PUT request');
    3});

    DELETE

    • Hapus note
    1app.delete('/note/:id', (req, res) => {
    2 res.send('Received DELETE request');
    3});

    Code server.js:

    1const express = require('express');
    2
    3const app = express();
    4const port = 3001;
    5
    6app.post('/note', (req, res) => {
    7 res.send('Receive POST request');
    8});
    9
    10app.get('/notes', (req, res) => {
    11 res.send('Receive GET request');
    12});
    13
    14app.get('/note/:id', (req, res) => {
    15 res.send('Received GET request with parameter');
    16});
    17
    18app.put('/note/:id', (req, res) => {
    19 res.send('Received PUT request');
    20});
    21
    22app.delete('/note/:id', (req, res) => {
    23 res.send('Received DELETE request');
    24});
    25
    26app.listen(port, () => {
    27 console.log(`Server listening at http://localhost:${port}`);
    28});

    Output yang didapatkan menggunakan curl:

    curl

    Meskipun curl dapat digunakan untuk menguji REST API, curl memiliki beberapa keterbatasan. Salah satunya adalah menguji metode POST dengan data berjumlah banyak dan bersifat kompleks menggunakan curl bukanlah sesuatu yang mudah.

    Oleh karena itu kita akan menggunakan API testing tools. Salah satu API testing tool yang sering digunakan oleh developer adalah Postman.

    Testing menggunakan Postman

    Postman adalah salah satu tool yang banyak digunakan developer dalam mengembangkan sebuah API.

    Dengan postman kita bisa membuat, menguji dan memodifikasi API dengan mudah.

    Pada bagian ini kita akan menggunakan Postman untuk menguji API yang sudah kita buat.

    Install

    Download Postman disini kemudian install.

    Tampilan Postman setelah install (bisa berbeda tergantung versi).

    postman

    Penggunaan

    Menggunakan postman untuk test REST API:

    Step by step

    1. Buat sebuah collection baru

    Klik tombol New -> Pilih Collection -> Beri nama collection dinotes-api (atau pilih nama sesuai keinginan) -> Klik Create

    Atau kamu bisa pilih menu Create Collection dari Launchpad

    1. Buat sebuah request baru

    Klik tombol New -> Pilih Request -> Beri nama request get notes -> Simpan di collection dinotes-api -> Klik Create

    Jenis request yang kita buat adalah GET, pastikan memilih GET pada menu drop down yang tersedia.

    postman get request

    1. Masukan url endpoint http://localhost:3000/notes kemudian klik Send

    Hasilnya

    postman get response

    Kita bisa ulangi langkah di atas untuk menguji url endpoint dengan HTTP method yang lain (POST, PUT, DELETE).

    Postman menyediakan banyak opsi yang bisa digunakan untuk mempermudah kita melakukan testing API, seperti menambahkan Query Params, Authorization, Headers atau Body pada sebuah request.

    Koneksi Database

    Saatnya menambahkan database untuk mengelola data yang ditransfer via API.

    Database yang kita gunakan adalah NoSQL database MongoDB.

    Persiapan

    1. Install MongoDB, instruksinya bisa dilihat disini
    2. Install Database Management Tool MongoDB Compass

    Buat Database & Collection

    Kita perlu membuat sebuah Database dan satu Collection untuk menyimpan data yang dikirim ke server via API.

    Kita bisa memanfaatkan MongoDB compass untuk membuatnya dengan mudah.

    Step by step

    1. Jalankan MongoDB compass
    2. Pada bagian New Connection, klik button CONNECT

    MongoDB compass akan menyediakan informasi koneksi ke MongoDB yang sudah terinstall di komputer/localhost, sehingga kita tinggal klik button CONNECT

    connect mongodb

    1. Setelah terhubung, klik button CREATE DATABASE untuk membuat database baru

    create db mongodb

    1. Beri Nama database dinotesDB dan nama Collection notes, kemudian klik CREATE DATABASE

    create db mongodb 2

    Hasilnya:

    result

    Membuat Koneksi

    Untuk dapat menggunakan MongoDB di Node.js kita butuh menambahkan package MongoDB driver.

    Step by step

    1. Install MongoDB driver
    1$ yarn add mongodb
    1. Buat koneksi ke MongoDB database

    Update code api/server.js

    1const express = require('express');
    2const { MongoClient } = require('mongodb');
    3
    4const app = express();
    5const port = 3001;
    6
    7// Database
    8
    9// Connection URL
    10const url = 'mongodb://localhost:27017';
    11
    12// Database Name
    13const dbName = 'dinotesDB';
    14
    15// Connect to database
    16MongoClient.connect(url, (err, client) => {
    17 console.log('Connected successfully to server');
    18
    19 const db = client.db(dbName);
    20
    21 client.close();
    22});
    23
    24// Routes
    25
    26app.post('/note', (req, res) => {
    27 res.send('Receive POST request');
    28});
    29
    30app.get('/notes', (req, res) => {
    31 res.send('Receive GET request');
    32});
    33
    34app.get('/note/:id', (req, res) => {
    35 res.send('Received GET request with parameter');
    36});
    37
    38app.put('/note/:id', (req, res) => {
    39 res.send('Received PUT request');
    40});
    41
    42app.delete('/note/:id', (req, res) => {
    43 res.send('Received DELETE request');
    44});
    45
    46app.listen(port, () => {
    47 console.log(`Server listening at http://localhost:${port}`);
    48});

    Penjelasan:

    • mongodb://localhost:27017 adalah alamat MongoDB server yang terinstall di komputer, by default MongoDB server menggunakan port 27017
    • const dbName='dinotesDB', dinotesDB adalah nama dari database
    • MongoClient.connect(...) adalah method yang digunakan untuk membuat koneksi ke MongoDB server

    Jika muncul pesan Connected successfully to server pada console maka server sudah berhasil connect ke MongoDB.

    Menambahkan Route Handler

    Selanjutnya kita akan membuat handler untuk masing-masing route.

    Agar server dapat mengakses data yang ada di dalam body sebuah request kita perlu menambahkan middleware body-parser.

    Step by step

    1. Install package body-parser:
    1$ yarn add body-parser
    1. Tambahkan middleware sebelum routes
    1const express = require('express');
    2const { MongoClient } = require('mongodb');
    3const bodyParser = require('body-parser');
    4
    5const app = express();
    6const port = 3001;
    7
    8// Connection URL
    9const url = 'mongodb://localhost:27017';
    10// Database Name
    11const dbName = 'dinotesDB';
    12
    13app.use(bodyParser.urlencoded({ extended: true }))
    14
    15// Routes
    16...

    Create

    1. Tambahkan code berikut ke file api/server.js.
    1const express = require('express');
    2const { MongoClient } = require('mongodb');
    3const bodyParser = require('body-parser');
    4
    5const app = express();
    6const port = 3001;
    7
    8// Connection URL
    9const url = 'mongodb://localhost:27017';
    10// Database Name
    11const dbName = 'dinotesDB';
    12
    13app.use(bodyParser.urlencoded({ extended: true }));
    14
    15// Routes
    16
    17app.post('/note', (req, res) => {
    18 // Buat koneksi ke server
    19 MongoClient.connect(url, (err, client) => {
    20 const db = client.db(dbName);
    21 const notesCollection = db.collection('notes');
    22
    23 // Simpan data ke collection notes
    24 notesCollection.insertOne(req.body).then((result) => {
    25 // tampilkan hasilnya di console
    26 console.log(result);
    27 });
    28
    29 // tutup koneksi ke database
    30 client.close();
    31 });
    32
    33 // kirim status dan pesan dalam format json ke client
    34 res.status(200).json('Data successfully saved');
    35});
    36
    37app.get('/notes', (req, res) => {
    38 res.send('Receive GET request');
    39});
    40
    41app.get('/note/:id', (req, res) => {
    42 res.send('Received GET request with parameter');
    43});
    44
    45app.put('/note/:id', (req, res) => {
    46 res.send('Received PUT request');
    47});
    48
    49app.delete('/note/:id', (req, res) => {
    50 res.send('Received DELETE request');
    51});
    52
    53app.listen(port, () => {
    54 console.log(`Server listening at http://localhost:${port}`);
    55});

    Penjelasan

    Ketika sebuah POST request diterima oleh server, handler akan membuat koneksi ke MongoDB kemudian data yang ada di dalam req.body akan dimasukan ke dalam collection.

    Testing

    Mari kita lakukan testing menggunakan Postman.

    1. Buka Postman
    2. Buat Request baru
    3. Pilih POST kemudian masukan url http://localhost:3001
    4. Pada tab Body isikan data berikut sebagai simulasi data yang berasal dari front-end DinoTes
    titlenote
    What is dinosaur ?Dinosaurs are a class of extinct reptiles and modern birds of the clade Dinosauria

    test post request

    1. Klik Send

    Jika berhasil dan tidak ada error hasilnya akan seperti ini:

    • Postman

    test post result

    • MongoDB Compass

    mongodb compass result

    Kita akan lanjutkan untuk menambah handler untuk route yang lain.

    Tambahkan lebih banyak data ke dalam colection.

    Kita bisa gunakan Mock Data Generator seperti Mockaroo untuk mendapatkan sample data yang akan ditambahkan ke collection lewat MongoDB Compass.

    1. Generate Data menggunakan Mockaroo
    2. Download data dalam bentuk CSV
    3. Pada MongoDB Compass, klik ADD DATA -> Import File -> Pilih file CSV yang sudah kita download sebelumnya

    import file compass

    import data completed

    Read

    Update /api/server.js dengan code berikut untuk menghandle GET request

    • Cari semua notes
    1...
    2
    3app.get('/notes', (req, res) => {
    4 MongoClient.connect(url, (err, client) => {
    5 const db = client.db(dbName);
    6 const notesCollection = db.collection('notes');
    7
    8 // Read all data
    9 notesCollection
    10 .find()
    11 .toArray()
    12 .then((result) => {
    13 res.status(200).json(result);
    14 });
    15
    16 client.close();
    17 });
    18});
    19
    20...

    Mencari semua notes dilakukan dengan menggunakan metode notesCollection.find(), namun hasil pencarian dari method ini adalah sebuah cursor yang sulit dibaca.

    Oleh karena itu kita perlu menggunakan method toArray() untuk mengubahnya menjadi document sehingga lebih mudah untuk dibaca.

    • Cari satu note sesuai id
    1const { MongoClient, ObjectId } = require('mongodb');
    2
    3...
    4
    5app.get('/note/:id', (req, res) => {
    6 MongoClient.connect(url, (err, client) => {
    7 const db = client.db(dbName);
    8 const notesCollection = db.collection('notes');
    9
    10 // cari note sesuai id
    11 notesCollection
    12 .findOne({ '_id': ObjectId(req.params.id) })
    13 .then((result) => {
    14 res.status(200).json(result);
    15 });
    16
    17 client.close();
    18 });
    19});
    20
    21...

    Gunakan req.params untuk mendapatkan parameter yang ada di url.

    Update

    Update /api/server.js dengan code berikut untuk menghandle PUT request

    1...
    2
    3app.put('/note/:id', (req, res) => {
    4 MongoClient.connect(url, (err, client) => {
    5 const db = client.db(dbName);
    6 const notesCollection = db.collection('notes');
    7
    8 // update data collection
    9 notesCollection
    10 .updateOne(
    11 { _id: ObjectId(req.params.id) },
    12 { $set: { title: req.body.title, note: req.body.note }}
    13 ).then((result) => {
    14 console.log(result);
    15 });
    16
    17 client.close();
    18 });
    19
    20 res.status(200).json('Data successfully updated');
    21});
    22
    23...

    Selain method updateOne() kita juga bisa menggunakan method findOneAndUpdate().

    Letak perbedaannya ada pada output yang dihasilkan(return). findOneAndUpdate() akan return document yang baru saja diupdate sedangkan updateOne() tidak.

    Delete

    Update /api/server.js dengan code berikut untuk menghandle DELETE request

    1...
    2
    3app.delete('/note/:id', (req, res) => {
    4 MongoClient.connect(url, (err, client) => {
    5 const db = client.db(dbName);
    6 const notesCollection = db.collection('notes');
    7
    8 // update data collection
    9 notesCollection
    10 .deleteOne({ _id: ObjectId(req.params.id) })
    11 .then((result) => {
    12 console.log(result);
    13 });
    14
    15 client.close();
    16 });
    17
    18 res.status(200).json('Data successfully deleted');
    19});
    20
    21...

    Final Code

    1/* eslint-disable no-console */
    2const express = require('express');
    3const { MongoClient, ObjectId } = require('mongodb');
    4const bodyParser = require('body-parser');
    5
    6const app = express();
    7const port = 3001;
    8
    9// Connection URL
    10const url = 'mongodb://localhost:27017';
    11// Database Name
    12const dbName = 'dinotesDB';
    13
    14app.use(bodyParser.urlencoded({ extended: true }));
    15
    16// Routes
    17
    18app.post('/note', (req, res) => {
    19 MongoClient.connect(url, (err, client) => {
    20 const db = client.db(dbName);
    21 const notesCollection = db.collection('notes');
    22
    23 // Insert data to collection
    24 notesCollection.insertOne(req.body).then((result) => {
    25 console.log(result);
    26 });
    27
    28 client.close();
    29 });
    30
    31 res.status(200).json('Data successfully saved');
    32});
    33
    34app.get('/notes', (req, res) => {
    35 MongoClient.connect(url, (err, client) => {
    36 const db = client.db(dbName);
    37 const notesCollection = db.collection('notes');
    38
    39 // Insert data to collection
    40 notesCollection
    41 .find()
    42 .toArray()
    43 .then((result) => {
    44 res.status(200).json(result);
    45 });
    46
    47 client.close();
    48 });
    49});
    50
    51app.get('/note/:id', (req, res) => {
    52 MongoClient.connect(url, (err, client) => {
    53 const db = client.db(dbName);
    54 const notesCollection = db.collection('notes');
    55
    56 // cari note sesuai id
    57 notesCollection.findOne({ _id: ObjectId(req.params.id) }).then((result) => {
    58 res.status(200).json(result);
    59 });
    60
    61 client.close();
    62 });
    63});
    64
    65app.put('/note/:id', (req, res) => {
    66 MongoClient.connect(url, (err, client) => {
    67 const db = client.db(dbName);
    68 const notesCollection = db.collection('notes');
    69
    70 // update data collection
    71 notesCollection
    72 .updateOne({ _id: ObjectId(req.params.id) }, { $set: { title: req.body.title, note: req.body.note } })
    73 .then((result) => {
    74 console.log(result);
    75 });
    76
    77 client.close();
    78 });
    79
    80 res.status(200).json('Data successfully updated');
    81});
    82
    83app.delete('/note/:id', (req, res) => {
    84 MongoClient.connect(url, (err, client) => {
    85 const db = client.db(dbName);
    86 const notesCollection = db.collection('notes');
    87
    88 // update data collection
    89 notesCollection.deleteOne({ _id: ObjectId(req.params.id) }).then((result) => {
    90 console.log(result);
    91 });
    92
    93 client.close();
    94 });
    95
    96 res.status(200).json('Data successfully deleted');
    97});
    98
    99app.listen(port, () => {
    100 console.log(`Server listening at http://localhost:${port}`);
    101});

    Tapi sekarang code menjadi sangat panjang.

    Waktunya Refactoring...