Создаем свою CRUD API на Express и MySQL: часть первая

от автора

Всем привет. В преддверии старта курса «Fullstack разработчик JavaScript», хотим поделиться небольшим материалом, который был написан нашим внештатным автором.

Express один из самых популярных веб-фреймворков, который поддерживает роутинг, миддлвейрс и систему шаблонов. Делать бэкенд на Node.js без Express в 2020 году — довольно странное занятие, ведь Express де-факто — каркас для создания веб-приложения на Node.js.
Сегодня мы попробуем создать несложное CRUD API используя базу данных MySQL. Опытный в Node.js читатель спросит, а где же MongoDB, с которым Node.js обычно применятся в паре но, скажу сразу, это статья больше для PHP разработчиков, которые хотят немного потрогать Node.js, и чтобы смягчить переход в новую экосистему мы воспользуемся MySQL. API мы будем создавать для несложного Todo приложения, на тот случай, если кто-то захочет к своей todo (и даже неважно, написанной с помощью React или нет), присоединить немного бэка и поиграть с ним.

«Архитектура» и суть нашего приложения

В нашем приложении можно будет создавать, получать, обновлять и удалять Todo. В общем, у нас будет минимальный набор функций CRUD (create read update delete).

В конце мы совместим приложение c приложением на React и все протестируем.

Для начала приведу структуру файлов приложения:

Дальше я приведу таблицу действий и методов, которые есть в нашем приложении:

Методы Url Действия
GET /deals получение всех дел
GET /deals/2 Получение id c номером 2
POST /deals добавление нового дела
PUT /deals/3 Обновить пользователя с id=3
DELETE /deals/3 удалить пользователя с id=3
DELETE /deals удалить всех пользователей
Создание своего Node.js приложения

Переходим в вашу любимую директорию, запускаем терминал и создаем ваше приложение. Кстати, из заголовка, наверное, понятно, что Node.js у вас уже должна быть установлена. Если вы еще этого не сделали, то этого просто не может быть скачайте по ссылке отсюда.

    $ mkdir CRUD_API     $ cd CRUD_API 

Дальше необходимо инициализировать наше приложение с помощью npm init. Т.к. приложение у нас скорее тестовое и обучающее, я воспользуюсь командной, которая заполнит все данные по дефолту, чтобы не тратить время на мелкие детали:

 npm init -y  

Если что, потом руками в package.json вы сможете поменять данные на те, которые вам нужны: репозиторий github, тэги, автора, и т.д.
Потом нам нужно поставить все необходимые для работы приложения пакеты:

  npm i express mysql body-parser --save 

Если вы собираетесь отправлять потом вашу разработку на github, вам стоит создать скрытый файл .gitignore, чтобы не таскать с собой тяжелейшие node_modules и не позориться. Пишем:

    touch .gitignore      code .gitignore  

Там вписываем node_modules, в дальнейшем в этот файл вы сможете вписать наименования папок и файлов, которые хотите увидеть потом на удаленном сервере.

Базовая настройка Express

В корневой папке проекта создаем файл server.js:

    const express = require("express");     const bodyParser = require("body-parser");          const app = express();          //делаем наш парсинг в формате json     app.use(bodyParser.json());          // парсит запросы по типу: application/x-www-form-urlencoded     app.use(bodyParser.urlencoded({ extended: true }));          //  простой response - request     app.get("/", (req, res) => {       res.json({ message: "Это стартовая страница нашего приложения" });     });          // установить порт, и слушать запросы     app.listen(3001, () => {       console.log("Сервер запущен на 3001 порту");     }); 

Теперь мы можем запустить сервер с помощью:

node server.js 

Express нам нужен для создания своего api, а пакет body-parser помогает нам парсить request и создавать req.body, который пригодится для работы роутинга.

Сейчас наш сервер умеет следующее:

  • Создаем Express app, который отдает body-parser миддлевеир используя app.use()
  • у нас есть простой get, просто для тестирования работы приложения
  • Слушаем 3001 порт на все входящие изменения

Первично наше приложение работает, дальше можно заняться базой данных.

Создаем свою таблицу данных MySQL

Я очень надеюсь, что у читателя данной статьи нет проблемы с тем, чтобы самостоятельно скачать и установить MySQL и MySQLWorkBranch. Дальше вы самостоятельно создаете scheme(БД) с названием, которое вам больше нравится (в моем случае TODO), и потом выбрать молнию-запрос и скопировать/набрать следующую команду:

    CREATE TABLE IF NOT EXISTS `todo` (         id int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,         text varchar(255) NOT NULL       ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

В нашей базе данных будет все по минимуму: только id и сам текст дел. Однако добавить ещё колоночку, в которой может описана, к примеру, срочность вашего дела, надеюсь, проблем не вызовет.

Конфигурация & коннект с нашей базой данных

Давайте установим и сконфигурируем соединение с базой данных. Мы создадим новую папку app прямо в нашей корневой папке, и там создадим файл db.config.js в папке config, вот примерно с таким содержанием, которое зависит от ваших настроек в MySQLWorkBranch. В моем случае файл будет выглядеть вот так:

  module.exports = {     HOST: "localhost",     USER: "pavel",     PASSWORD: "",     DB: "TODO"   }; 

После этого создаем папку для описания наших моделей app/mode, в которой мы потом создадим модель:

  const mysql = require("mysql");   const dbConfig = require("../config/db.config.js");      // создаем соединение с нашей базой данных   const connection = mysql.createConnection({     host: dbConfig.HOST,     user: dbConfig.USER,     password: dbConfig.PASSWORD,     database: dbConfig.DB   });      // открываем наше соединение с базой данных   connection.connect(err => {     if (err) throw error;     console.log("успешно соединено с базой данных");   });    module.exports = connection;    //экспортируем наше соединение 
Создаем Модель

В папке model, мы создаем файл, который называется deal.model.js. Если у вас возникает вопрос, что же такое вообще модель, вам стоит прочитать статью вроде этой и ознакомиться с паттерном проектирования MVC. Я собираюсь создать конструктор для Deal объекта, и использовать connection для следующих CRUD функций:

  • создание нового дела
  • нахождение дела по id
  • получение всех дел
  • возможность обновлять наше дело по id
  • Удаление одного дела по id
  • полное удаление всех дел

Итого, нам придется заняться следующими делами:

  // конструктор нашего дела   const Deal = function(deal) {     this.text = deal.text;   };   //у нашей модели будут функции, с помощью которых можно осуществлять все операции CRUD, которые были озвучены в начале статьи:   Deal.create = (newDeal, result) => {     sql.query("INSERT INTO TODO SET ?", newDeal, (err, res) => {       //операция вставки из SQL       if (err) {         console.log("error: ", err);         result(err, null);         //немного бедная обработка ошибок, но на первое время хватит         return;       }          console.log("Дело сделано", { id: res.insertId, ...newDeal });       result(null, { id: res.insertId, ...newDeal });     });   };  

Остальную часть кода я размещу в spoiler, потому, что не вижу смысла приводить его весь, ведь там по сути повторяется паттерн кода, меняются только sql — команды и аргументы:

остальная часть кода

Deal.findById = (dealId, result) => {
sql.query(`SELECT * FROM TODO WHERE id = ${dealId}`, (err, res) => {
if (err) {
console.log(«error: », err);
result(err, null);
return;
}

if (res.length) {
console.log(«найдено дело: », res[0]);
result(null, res[0]);
return;
}

// когда ничего не удалось найти
result({ kind: «not_found» }, null);
});
};

Deal.getAll = result => {
sql.query(«SELECT * FROM TODO», (err, res) => {
if (err) {
console.log(«error: », err);
result(null, err);
return;
}

console.log(«deals: », res);
result(null, res);
});
};

Deal.updateById = (id, deal, result) => {
sql.query(
«UPDATE TODO SET text =? WHERE id = ?»,
[deal.text, id],
(err, res) => {
if (err) {
console.log(«error: », err);
result(null, err);
return;
}

if (res.affectedRows == 0) {
result({ kind: «not_found» }, null);
return;
}

console.log(«Обновлено дело », { id: id, …deal });
result(null, { id: id, …deal });
}
);
};

Deal.remove = (id, result) => {
sql.query(«DELETE FROM TODO WHERE id = ?», id, (err, res) => {
if (err) {
console.log(«error: », err);
result(null, err);
return;
}

if (res.affectedRows == 0) {
// если дело не удалось получить по id
result({ kind: «not_found» }, null);
return;
}
console.log(«Удален пользователь с », id);
result(null, res);
});
};

Deal.removeAll = result => {
sql.query(«DELETE FROM TODO», (err, res) => {
if (err) {
console.log(«error: », err);
result(null, err);
return;
}

console.log(`deleted ${res.affectedRows} deals`);
result(null, res);
});
};

На этом пока все. На подходе следующая часть этой статьи, в которой мы закончим написание бэка и примемся за его тестирование. И по традиции, несколько полезных ссылок:

ссылка на оригинал статьи https://habr.com/ru/company/otus/blog/491408/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *