Часть 4. Создание REST API: обработка запросов POST, PUT и DELETE В предыдущая статья вы добавили в API логику для запросов GET, извлекающих данные из базы данных.
В этом посте вы завершите создание основных функций CRUD API, добавив логику для обработки запросов POST, PUT и DELETE. Добавление логики маршрутизации Чтобы упростить логику маршрутизации, вы перенаправите все методы HTTP через существующий маршрут (с необязательным параметром id).
Открыть файл услуги/router.js и замените текущую логику маршрутизации (строки 5-6) следующим кодом:
Обновленная логика маршрутизации сопоставляет четыре наиболее распространенных метода HTTP, используемых для основных операций CRUD, с правильной логикой контроллера.router.route('/employees/:id?') .
get(employees.get) .
post(employees.post) .
put(employees.put) .
delete(employees.delete);
Обработка 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. Вот пример:
В моем случае значение сотрудника_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
-
За Бесконечностью
19 Oct, 24 -
Сохранено В .Wwf – Спасено Дерево!
19 Oct, 24