Создание простого REST API для базы данных SQL-сервера

Это вторая версия статьи на тему создания REST API с дополнительными комментариями по исходной статье для перевода.

При работе с проектами по интеграции, для получения данных на сайт клиента, в CRM или мобильное приложение из базы данных под управлением MS SQL — реализуем стандартный REST API.

Проще всего создать такую интеграцию используя Node.js и два популярных npm-модуля Express (оснастка веб-сервера) и mssql (MS SQL Server клиент для Node.js).

Сначала создаем таблицы sales и invoices в базе данных SQL-сервера, процедуру для добавления записей в таблицу invoices и заполняем таблицу sales несколькими тестовыми записями:

create table sales( id int primary key identity(1,1), title varchar(255) null, amount dec(12,2) not null, clientId int not null, date_create datetime DEFAULT (getdate()) ); go create table invoices( id int primary key identity(1,1), idSale int not null REFERENCES sales(id), date_create datetime DEFAULT (getdate()) ); go create procedure addInvoices ( @idSales int ) as begin insert into invoices (idSale) output inserted.* select id from sales where id = @idSales end go insert into sales (title, amount, clientId) values ('Заказ 1', 100.80, 1), ('Заказ 2', 120.30, 2), ('Заказ 3', 78.11, 1); go

Проверяем на SQL-сервере созданную таблицу и добавленные тестовые данные:

select * from sales

Переходим к созданию приложения в файле server.js добавляем код.

var express = require('express'); // оснастка веб сервера var app = express(); var sql = require('mssql'); // клиент для MS SQL Server // строка для подключения к базе данных. var sqlConfig = { user: 'UserName', password: 'mot de passe', server: 'localhost', database: 'DatabaseName' } // сервер для http://localhost:8081/ var server = app.listen(8081, function () { var host = server.address().address var port = server.address().port console.log("сервер доступен по url http://%s:%s", host, port) });

После сохранения файла server.js проверим работоспособность сервера и выполнения файла скрипта:

node server.js

сервер должен вернуть сообщение о доступности для выполнения запросов, например:

сервер доступен по url http://localhost:8081

Добавим в файл server.js код обработки запроса к web-серверу для получения всех данных из таблицы SQL сервера sales.

app.get('/sales', function (req, res) { sql.connect(sqlConfig, function() { var request = new sql.Request(); request.query('select * from sales', function(err, resp) { if(err) console.log(err); res.json(resp.recordset); // результат в формате JSON sql.close(); // закрываем соединение с базой данных }); }); });

Сохраним файл, перезапустим сервер и проверим запрос в Postman, вернется JSON-объект с данными из таблицы SQL-сервера:

Усложняем запрос, добавим в обработчик параметр из URL для выборки по таблице invoices только запись с id = 2.

Передачу значения параметра из URL-запроса реализуем специальным отдельным методом — для исключения проблемы SQL-инъекций.

app.get('/sales/:id', function (req, res) { sql.connect(sqlConfig, function() { var request = new sql.Request(); request.input('input_parameter', sql.Int, Number(req.params.id)) // защита от SQL-инъекций и преобразование к числовому типу .query('select * from sales where id = @input_parameter', function(err, resp) { if(err) console.log(err); res.json(resp.recordset); // результат в формате JSON sql.close(); // закрываем соединение с базой данных }); }); });

Результат выполнения запроса, возврат отдельной записи из таблицы в формате JSON:

В следующем обработчике запроса добавим в таблицу “invoices” запись с новым заказом, для REST это должен быть метод HTTP, тип запроса POST :

app.post('/sales/:id/invoices', function (req, res) { sql.connect(sqlConfig, function() { var request = new sql.Request(); request.input('idSales', sql.Int, Number(req.params.id)) // защита от SQL-инъекций .execute('addInvoices', function(err, resp, returnValue, affected) { if(err) console.log(err); res.json(resp.recordset); // результат в формате JSON sql.close(); // закрываем соединение с базой данных }); }); });

Для тестирования запросов типа POST требуется установка в браузер дополнения, использования отдельного приложения, например Postman, или же запрос возможно выполнить при помощи curl, используя командную строку:

В результате выполнения запроса получаем json с данными о добавленной записи в таблице invoices. При повторном выполнении новый ID и дата добавления записи.

В результате скрипт приложения server.js следующего содержания:

var express = require('express'); // оснастка веб сервера var app = express(); var sql = require('mssql'); // клиент для MS SQL Server // строка для подключения к базе данных. var sqlConfig = { user: 'UserName', password: 'mot de passe', server: 'localhost', database: 'DatabaseName' } // сервер для http://localhost:8081/ var server = app.listen(8081, function () { var host = server.address().address var port = server.address().port console.log("сервер доступен по url http://%s:%s", host, port) }); app.get('/sales', function (req, res) { sql.connect(sqlConfig, function() { var request = new sql.Request(); request.query('select * from sales', function(err, resp) { if(err) console.log(err); res.json(resp.recordset); // результат в формате JSON sql.close(); // закрываем соединение с базой данных }); }); }); app.get('/sales/:id', function (req, res) { sql.connect(sqlConfig, function() { var request = new sql.Request(); request.input('input_parameter', sql.Int, Number(req.params.id)) // защита от SQL-инъекций и преобразование к числовому типу .query('select * from sales where id = @input_parameter', function(err, resp) { if(err) console.log(err); res.json(resp.recordset); // результат в формате JSON sql.close(); // закрываем соединение с базой данных }); }); }); app.post('/sales/:id/invoices', function (req, res) { sql.connect(sqlConfig, function() { var request = new sql.Request(); request.input('idSales', sql.Int, Number(req.params.id)) // защита от SQL-инъекций .execute('addInvoices', function(err, resp, returnValue, affected) { if(err) console.log(err); res.json(resp.recordset); // результат в формате JSON sql.close(); // закрываем соединение с базой данных }); }); });

Дальнейшее дополнение скрипта приложения server.js это — включение в код обработчика ошибок, подключение к SQL через организацию пула соединений, обработка JSON встроенными функциями SQL-сервера.

Ссылка на источник для перевода и корректировки исходного кода статьи. Дополнительная информация по технологиям интеграции систем с использованием MS SQL-сервер — на сайте voInfo.ru.

0
16 комментариев
Написать комментарий...

Комментарий удален модератором

Развернуть ветку

Комментарий удален модератором

Развернуть ветку
Александр Коротков

Хранимка вам зачем?

Ответить
Развернуть ветку
Сергей Железняков
Автор

показан пример вызова процедуры, далее планировал рассмотреть варианты с передачей параметрами структуры json, использование out параметров, здесь возврат таблицы из процедуры

Ответить
Развернуть ветку
R1250GSA

MSSQL? Нода? "Проще всего"?
1. Большинство проектов от интернет-магазинов до персональных блогов использует MySQL, MongoDB, PostgreSQL, а не MSSQL.
2. REST само собой пишется на уже существующий стек, а не наоборот. И если проект написан на PHP, Java или GoLang - какой смысл тянуть ноду?
3. Компании, использующие не коробочные решения, работающие с MSSQL уже имеют специалистов, способных написать RESTful API с авторизацией, ограничениями и валидацией данных.

Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
R1250GSA

Вот это я понимаю - образец объективных и обоснованных ответов.

Ответить
Развернуть ветку
ManManage Live

Автор, спасибо за проделанную работу!
Применимо в своём проекте ! Ещё раз благодарю 👍🏼

Ответить
Развернуть ветку
Виталий Подольский

Читаем и пишем без авторизации? =)

Ответить
Развернуть ветку
Сергей Железняков
Автор

актуальна авторизация на клиента в http запросе или на сессию подключения к sql серверу? При подключении к sql пул запросов под общей УЗ, в базе сессионные хэши на пользователей http.

Ответить
Развернуть ветку
Виталий Подольский

Да для клиента конечно. Или любой желающий сможет запросить информацию. А так, материал полезный. Немного ностальгии сразу свалилось, как раньше нужно было по быстрому апи накидать.

Еще как идея для статьи. Завернуть базу и сервис в докер-композ.

Ответить
Развернуть ветку
Виталий Подольский

Кстати, а нет информации, как эта БД нагрузку при большом количестве запросов держит? Скажем, при 100к запросов?

Ответить
Развернуть ветку
Сергей Железняков
Автор

использовал технологию In-Memory tables, достаточно эффективна при большой нагрузке

Ответить
Развернуть ветку
Nikolay Schamberg

Спасибо за статью, думая она пригодится многим начинающим программистам. Тем не менее, не однозначны пара моментов в данной статье.

Первое, указание данных для подключения напрямую в server.js. Для этих целей лучше использовать модуль dotenv и настройки хранить в отдельном файле, так как это упрощает развёртывание на дополнительных машинах, а также спасёт от компрометации данных о БД в репозитории в гитхабе.

Второе, кажется излишним повторять несколько раз похожие запросы к БД в коде. Более удобным представляется написать собственный модуль-обёртку поверх mssql. Данный модуль мог бы заниматься однотипными запросами с БД, и который можно многократно использовать в server.js. В server.js можно оставить только callback' и с требуемой логикой. С ростом объёма кода, это должно сильно упростить обслуживание кода. В принципе, вместе с пулом соединений, обозначенном в конце статьи, мне кажется это первое, с чего вообще стоило начинать. Чтобы делать правильно сразу ;)

Ответить
Развернуть ветку
Nikolay Schamberg

Ну и отсутствие авторизации на сервере, конечно, но об этом писали и другие

Ответить
Развернуть ветку
Arturs Jansons

На дворе 2020, а где тогда GraphQL, ProtoBuff, http2, socket, схемы API, тесты, распределоенность, модульность, монолит/микросервис, параллелизм и прочие хештеги? ;)

(сарказм)

Спасибо за статью, многим будет полезна.

Ответить
Развернуть ветку
Сергей Железняков
Автор

up

Ответить
Развернуть ветку
borodutch

Только почему на дворе 2020, а автор все ещё использует Express, а не гораздо более лаконичный Koa?

Ответить
Развернуть ветку
Читать все 16 комментариев
null