Создание Rest Api С Помощью Node.js И Базы Данных Oracle. Часть 4

Часть 4. Создание REST API: обработка запросов POST, PUT и DELETE В предыдущая статья вы добавили в API логику для запросов GET, извлекающих данные из базы данных.

В этом посте вы завершите создание основных функций CRUD API, добавив логику для обработки запросов POST, PUT и DELETE. Добавление логики маршрутизации Чтобы упростить логику маршрутизации, вы перенаправите все методы HTTP через существующий маршрут (с необязательным параметром id).

Открыть файл услуги/router.js и замените текущую логику маршрутизации (строки 5-6) следующим кодом:

  
  
  
  
  
  
  
  
  
  
  
  
   

router.route('/employees/:id?') .

get(employees.get) .

post(employees.post) .

put(employees.put) .

delete(employees.delete);

Обновленная логика маршрутизации сопоставляет четыре наиболее распространенных метода HTTP, используемых для основных операций CRUD, с правильной логикой контроллера.

Обработка POST-запросов Запросы HTTP POST используются для создания новых ресурсов (в данном случае записей сотрудников).

Основная идея состоит в том, чтобы извлечь данные из тела HTTP-запроса и использовать их для создания новой строки в базе данных.

Чтобы добавить логику контроллера для POST-запросов, откройте файл контроллеры/employee.js и добавьте следующий код:

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;

Функция getEmployeeFromRec принимает объект запроса и возвращает объект со свойствами, необходимыми для создания записи о сотруднике.

Функция была объявлена вне функции post, чтобы ее можно было использовать позже и для запросов PUT. Функция post использует getEmployeeFromRec для инициализации переменной, которая затем передается в метод создания API базы данных сотрудников.

После операции создания код состояния «201 Created» отправляется клиенту вместе с JSON сотрудника (включая новое значение идентификатора сотрудника).

Теперь вы можете взглянуть на логику API базы данных.

Открыть файл db_apis/employee.js и добавьте следующий код ниже.



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;

Приведенная выше логика начинается с объявления константы createSql для хранения оператора вставки.

Обратите внимание, что он использует привязать переменные , а не конкатенацию строк, для ссылки на вставляемые значения.

Стоит повторить, насколько важны переменные связывания с точки зрения безопасности и производительности.

По возможности старайтесь избегать конкатенации строк.

Внутри функции create константа сотрудника определяется и инициализируется копией параметра emp с помощью Object.assign. Это предотвращает прямую модификацию объекта, переданного из контроллера.

Затем к объекту сотрудника (настроенному как «внешняя привязка») добавляется свойство сотрудника_id, чтобы оно содержало все переменные привязки, необходимые для выполнения оператора SQL. Затем функция simpleExecute используется для выполнения оператора вставки, а свойство outBinds используется для перезаписи свойства сотрудника.

employee_id перед возвратом объекта.

Поскольку имеется ссылка на модуль oracledb, вам необходимо добавить следующую строку в начало файла.



const oracledb = require('oracledb');

Обработка PUT-запросов Запросы PUT будут использоваться для обновления существующих ресурсов.

Важно отметить, что PUT используется для замены всего ресурса — он не выполняет частичные обновления (в будущем я покажу вам, как это сделать с помощью PATCH).

Вернуться в файл контроллеры/employee.js и добавьте следующий код ниже.



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;

Функция put использует getEmployeeFromRec для инициализации объекта с именем сотрудника, а затем добавляет свойство сотрудника_id из параметра id в URL-адрес.

Затем объект сотрудника передается функции обновления API базы данных, и на основе результата клиенту отправляется соответствующий ответ. Чтобы добавить логику обновления в API базы данных, добавьте в файл следующий код 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;

Логика обновления очень похожа на логику создания.

Объявляется переменная для хранения инструкции SQL, а затем используется simpleExecute для выполнения инструкции с переданными динамическими значениями (после копирования их в другой объект).

result.rowsAffected используется для определения успешности обновления и возврата правильного значения.

Обработка запросов DELETE Последний метод, который вам нужно реализовать, — это DELETE, который, что неудивительно, удалит ресурсы из базы данных.

Добавьте следующий код в конец файла контроллеры/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;

Механизм JavaScript выдаст исключение, если вы попытаетесь объявить функцию с именем «delete» с помощью оператора function. Чтобы обойти эту проблему, объявляется функция под названием «del», а затем экспортируется как «delete».

На этом этапе вы должны уметь читать и понимать логику.

В отличие от предыдущих примеров, этот HTTP-запрос не имеет тела, а только параметр id в пути маршрута.

Код состояния «204 No Content» часто используется с запросами DELETE, когда тело ответа не отправляется.

Чтобы завершить логику базы данных, вернитесь к файлу db_apis/employee.js и добавьте следующий код в конце.



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;

Поскольку таблица JOB_HISTORY имеет ограничение внешнего ключа, ссылающееся на таблицу EMPLOYEES, для удаления необходимых строк из обеих таблиц за один цикл используется простой блок PL/SQL. Разбор JSON-запросов Если вы посмотрите на функцию getEmployeeFromRec в файле Controllers/employee.js, вы заметите, что свойство body запроса является объектом JavaScript. Это обеспечивает простой способ получения значений из тела запроса, но это не происходит автоматически.

Созданный вами API ожидает, что клиенты будут отправлять данные в формате JSON в теле запросов POST и PUT. Кроме того, клиенты должны установить для заголовка Content-Type запроса значение application/json, чтобы веб-сервер знал, какой тип тела запроса отправляется.

Вы можете использовать встроенное промежуточное программное обеспечение express.json, чтобы позволить Express анализировать такие запросы.

Открыть файл услуги/web-server.js и добавьте следующие строки чуть ниже вызова app.use, который добавляет morgan в конвейер запросов.



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

Когда данные JSON анализируются в собственные объекты JavaScript, только типы данных, поддерживаемые в JSON, будут правильно сопоставлены с типами JavaScript. Даты не поддерживаются в JSON и обычно представляются в виде строк ISO 8601. Используя функцию reviver, переданную в промежуточное программное обеспечение express.json, вы можете выполнить преобразования вручную.

Добавьте следующий код в конец файла услуги/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; } }

API-тестирование Пришло время протестировать новую функциональность CRUD! До сих пор вы использовали браузер для тестирования API, но это не будет работать для запросов POST, PUT и DELETE. Я покажу вам, как протестировать API с помощью команд Curl, поскольку он легко доступен на виртуальной машине.

Но вы также можете использовать графический инструмент, такой как Почтальон , Инсомина (бесплатно).

Запустите приложение, а затем откройте другое окно терминала и выполните следующую команду, чтобы создать нового сотрудника.



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

Если запрос прошел успешно, ответ должен содержать объект сотрудника с атрибутом сотрудника_id. Вот пример:

Создание REST API с помощью Node.js и базы данных Oracle. Часть 4

В моем случае значение сотрудника_id было 227 — вам нужно будет изменить следующие команды на основе полученного значения сотрудника_id. Например, чтобы обновить новую запись, введите PUT для URL-адреса с этим значением идентификатора.



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

Триггер UPDATE_JOB_HISTORY в схеме HR обнаружит изменение должности и добавит строку в таблицу JOB_HISTORY. Если вы посмотрите в эту таблицу, вы увидите запись о новом сотруднике.

Выполните следующую команду, чтобы удалить историю заданий и записи о сотрудниках.



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

И вот она, полная функциональность CRUD! API развивается хорошо, но есть над чем поработать.

В последний пост Я покажу вам, как добавить возможности нумерации страниц, сортировки и фильтрации к GET-запросам.

Теги: #api #oracle #node.js

Вместе с данным постом часто просматривают: