Membuat API REST dengan Node.js dan Oracle Database. Bagian 4

Bagian 4. Membuat API REST: Menangani Permintaan POST, PUT, dan DELETE

Di artikel sebelumnya, Anda menambahkan logika ke API untuk MENDAPATKAN permintaan yang mengambil data dari database. Dalam posting ini, Anda akan menyelesaikan fungsionalitas dasar dari CRUD API dengan menambahkan logika untuk menangani permintaan POST, PUT, dan DELETE.

Menambahkan Logika Perutean

Untuk menyederhanakan logika perutean, Anda akan mengarahkan semua metode HTTP melalui rute yang ada (dengan parameter id opsional). Buka file services / router.js dan ganti logika routing saat ini (baris 5-6) dengan kode berikut:

router.route('/employees/:id?') .get(employees.get) .post(employees.post) .put(employees.put) .delete(employees.delete); 

Logika perutean yang diperbarui memetakan empat metode HTTP paling umum yang digunakan untuk operasi CRUD dasar ke logika pengontrol yang benar.

Pemrosesan permintaan POST

Permintaan HTTP POST digunakan untuk membuat sumber daya baru (dalam hal ini, catatan karyawan). Gagasan utamanya adalah untuk mengekstrak data dari badan permintaan HTTP dan menggunakannya untuk membuat baris baru dalam database. Untuk menambahkan logika pengontrol untuk permintaan POST, buka file controllers / employee.js dan tambahkan kode berikut:

 function getEmployeeFromRec(req) { const employee = { first_name: req.body.first_name, last_name: req.body.last_name, email: req.body.email, phone_number: req.body.phone_number, hire_date: req.body.hire_date, job_id: req.body.job_id, salary: req.body.salary, commission_pct: req.body.commission_pct, manager_id: req.body.manager_id, department_id: req.body.department_id }; return employee; } async function post(req, res, next) { try { let employee = getEmployeeFromRec(req); employee = await employees.create(employee); res.status(201).json(employee); } catch (err) { next(err); } } module.exports.post = post; 

Fungsi getEmployeeFromRec mengambil objek permintaan dan mengembalikan objek dengan properti yang diperlukan untuk membuat catatan karyawan. Fungsi tersebut dideklarasikan di luar fungsi pos sehingga dapat digunakan nanti untuk permintaan PUT.

Fungsi posting menggunakan getEmployeeFromRec untuk menginisialisasi variabel, yang kemudian diteruskan ke metode create API database karyawan. Setelah operasi pembuatan, kode status "201 Created" dikirim ke klien bersama dengan JSON karyawan (termasuk nilai baru dari pengidentifikasi karyawan).

Sekarang Anda dapat memperhatikan logika di API basis data. Buka file db_apis / employee.js dan tambahkan kode berikut di bawah ini.

 const createSql = `insert into employees ( first_name, last_name, email, phone_number, hire_date, job_id, salary, commission_pct, manager_id, department_id ) values ( :first_name, :last_name, :email, :phone_number, :hire_date, :job_id, :salary, :commission_pct, :manager_id, :department_id ) returning employee_id into :employee_id`; async function create(emp) { const employee = Object.assign({}, emp); employee.employee_id = { dir: oracledb.BIND_OUT, type: oracledb.NUMBER } const result = await database.simpleExecute(createSql, employee); employee.employee_id = result.outBinds.employee_id[0]; return employee; } module.exports.create = create; 

Logika di atas dimulai dengan mendeklarasikan konstanta createSql untuk menyimpan pernyataan insert. Perhatikan bahwa ia menggunakan variabel bind , bukan rangkaian string, untuk merujuk ke nilai yang akan disisipkan. Perlu diulangi betapa pentingnya variabel pengikat untuk alasan keamanan dan kinerja. Cobalah untuk menghindari penggabungan string bila memungkinkan.

Di dalam fungsi create, konstanta karyawan didefinisikan dan diinisialisasi untuk salinan parameter emp menggunakan Object.assign. Ini mencegah modifikasi langsung dari objek yang ditransfer dari controller.

Kemudian, properti employee_id ditambahkan ke objek karyawan (dikonfigurasi sebagai "out bind") sehingga berisi semua variabel mengikat yang diperlukan untuk menjalankan pernyataan SQL. Kemudian, fungsi simpleExecute digunakan untuk menjalankan pernyataan penyisipan, dan properti outBinds digunakan untuk menimpa properti employee.employee_id sebelum mengembalikan objek.

Karena ada tautan ke modul oracledb, Anda perlu menambahkan baris berikut ke bagian atas file.
 const oracledb = require('oracledb'); 


PUT Memproses Permintaan

Permintaan PUT akan digunakan untuk memperbarui sumber daya yang ada. Penting untuk dicatat bahwa PUT digunakan untuk mengganti seluruh sumber daya - PUT tidak melakukan pembaruan parsial (saya akan menunjukkan kepada Anda bagaimana melakukan ini dengan PATCH di masa mendatang). Kembali ke file controllers / employee.js dan tambahkan kode berikut di bawah ini.

 async function put(req, res, next) { try { let employee = getEmployeeFromRec(req); employee.employee_id = parseInt(req.params.id, 10); employee = await employees.update(employee); if (employee !== null) { res.status(200).json(employee); } else { res.status(404).end(); } } catch (err) { next(err); } } module.exports.put = put; 

Fungsi put menggunakan getEmployeeFromRec untuk menginisialisasi objek bernama karyawan, dan kemudian menambahkan properti employee_id dari parameter id ke URL. Kemudian objek karyawan diteruskan ke fungsi pembaruan API basis data, dan respons yang sesuai dikirim ke klien berdasarkan hasilnya.

Untuk menambahkan logika pembaruan ke API basis data, tambahkan kode berikut ke file db_apis / employee.js .

 const updateSql = `update employees set first_name = :first_name, last_name = :last_name, email = :email, phone_number = :phone_number, hire_date = :hire_date, job_id = :job_id, salary = :salary, commission_pct = :commission_pct, manager_id = :manager_id, department_id = :department_id where employee_id = :employee_id`; async function update(emp) { const employee = Object.assign({}, emp); const result = await database.simpleExecute(updateSql, employee); if (result.rowsAffected && result.rowsAffected === 1) { return employee; } else { return null; } } module.exports.update = update; 

Logika pembaruan sangat mirip dengan logika pembuatan. Variabel dideklarasikan untuk menyimpan pernyataan SQL, dan kemudian simpleExecute digunakan untuk mengeksekusi pernyataan dengan nilai dinamis yang ditransfer (setelah menyalinnya ke objek lain). result.rowsAffected digunakan untuk menentukan apakah pembaruan berhasil dan mengembalikan nilai yang benar.

HAPUS Pemrosesan Permintaan

Metode terakhir yang perlu Anda terapkan adalah DELETE, yang, tidak mengejutkan, akan menghapus sumber daya dari database. Tambahkan kode berikut di akhir file controllers / employee.js.

 async function del(req, res, next) { try { const id = parseInt(req.params.id, 10); const success = await employees.delete(id); if (success) { res.status(204).end(); } else { res.status(404).end(); } } catch (err) { next(err); } } module.exports.delete = del; 

Mesin JavaScript akan mengeluarkan pengecualian jika Anda mencoba mendeklarasikan fungsi yang disebut "hapus" menggunakan operator fungsi. Untuk menyiasatinya, fungsi bernama "del" dideklarasikan, dan kemudian diekspor sebagai "hapus".

Pada titik ini Anda harus dapat membaca dan memahami logika. Berbeda dengan contoh sebelumnya, permintaan HTTP ini tidak memiliki isi, hanya parameter id yang digunakan di jalur rute. Kode status "204 Tidak Ada Konten" sering digunakan dengan permintaan DELETE ketika badan respons tidak dikirim.

Untuk menyelesaikan logika basis data, kembali ke file db_apis / employee.js dan tambahkan kode berikut sampai akhir.

 const deleteSql = `begin delete from job_history where employee_id = :employee_id; delete from employees where employee_id = :employee_id; :rowcount := sql%rowcount; end;` async function del(id) { const binds = { employee_id: id, rowcount: { dir: oracledb.BIND_OUT, type: oracledb.NUMBER } } const result = await database.simpleExecute(deleteSql, binds); return result.outBinds.rowcount === 1; } module.exports.delete = del; 

Karena tabel JOB_HISTORY memiliki batasan kunci asing yang merujuk ke tabel EMPLOYEES, blok PL / SQL sederhana digunakan untuk menghapus baris yang diperlukan dari kedua tabel dalam satu siklus.

Parsing permintaan JSON

Jika Anda melihat fungsi getEmployeeFromRec di controllers / employee.js, Anda akan melihat bahwa properti body permintaan adalah objek JavaScript. Ini memberikan cara mudah untuk mendapatkan nilai dari badan permintaan, tetapi ini tidak terjadi secara otomatis.

API yang Anda buat mengharapkan klien untuk mengirim data dalam format JSON di badan permintaan POST dan PUT. Selain itu, klien harus mengatur header Tipe Konten dari permintaan ke aplikasi / json sehingga server web tahu jenis permintaan yang dikirim. Anda dapat menggunakan middleware bawaan express.json sehingga Express dapat menguraikan permintaan tersebut.

Buka file layanan / web-server.js dan tambahkan baris berikut tepat di bawah panggilan app.use, yang menambahkan morgan ke pipa permintaan.

 // Parse incoming JSON requests and revive JSON. app.use(express.json({ reviver: reviveJson })); 

Ketika data JSON diurai menjadi objek JavaScript asli, maka hanya tipe data yang didukung di JSON yang akan dipetakan dengan benar ke tipe JavaScript. Tanggal tidak didukung dalam JSON dan biasanya direpresentasikan sebagai string ISO 8601. Menggunakan fungsi reviver yang dilewatkan ke express.json middleware, Anda dapat melakukan konversi secara manual. Tambahkan kode berikut ke akhir file services / web-server.js .

 const iso8601RegExp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/; function reviveJson(key, value) { // revive ISO 8601 date strings to instances of Date if (typeof value === 'string' && iso8601RegExp.test(value)) { return new Date(value); } else { return value; } } 

Pengujian API

Sudah waktunya untuk menguji fungsionalitas CRUD baru! Sejauh ini, Anda telah menggunakan browser untuk menguji API, tetapi ini tidak akan berfungsi untuk permintaan POST, PUT, dan DELETE. Saya akan menunjukkan kepada Anda cara menguji API menggunakan perintah curl karena mudah diakses di mesin virtual. Tetapi Anda dapat menggunakan alat grafis seperti Postman , Insomina (gratis).

Buka aplikasi, lalu buka jendela terminal lain dan jalankan perintah berikut untuk membuat karyawan baru.

 curl -X "POST" "http://localhost:3000/api/employees" \ -i \ -H 'Content-Type: application/json' \ -d $'{ "first_name": "Dan", "last_name": "McGhan", "email": "dan@fakemail.com", "job_id": "IT_PROG", "hire_date": "2014-12-14T00:00:00.000Z", "phone_number": "123-321-1234" }' 

Jika permintaan berhasil, respons harus berisi objek karyawan dengan atribut employee_id. Berikut ini sebuah contoh:

gambar

Dalam kasus saya, nilai employee_id adalah 227 - Anda harus mengubah perintah berikut berdasarkan nilai employee_id yang diterima.

Misalnya, untuk memperbarui entri baru, masukkan PUT untuk URL dengan nilai pengenal ini.

 curl -X "PUT" "http://localhost:3000/api/employees/227" \ -i \ -H 'Content-Type: application/json' \ -d $'{ "first_name": "Dan", "last_name": "McGhan", "email": "dan@fakemail.com", "job_id": "AD_PRES", "hire_date": "2014-12-14T00:00:00.000Z", "phone_number": "123-321-1234" }' 

Pemicu UPDATE_JOB_HISTORY dalam skema SDM akan mendeteksi perubahan pekerjaan dan menambahkan baris ke tabel JOB_HISTORY. Jika Anda melihat tabel ini, Anda akan melihat catatan untuk karyawan baru. Jalankan perintah berikut untuk menghapus riwayat pekerjaan dan catatan karyawan.

 curl -i -X "DELETE" "http://localhost:3000/api/employees/227" 


Dan sekarang, Anda memiliki segalanya, fungsionalitas CRUD penuh!

API berjalan dengan baik, tetapi ada pekerjaan yang harus dilakukan. Dalam posting terakhir, saya akan menunjukkan kepada Anda bagaimana cara menambahkan kemampuan pagination, sorting, dan filtering dalam GET request.

Source: https://habr.com/ru/post/id473560/


All Articles