В этом руководстве мы узнаем, как создать Rest API в Node.js и Express.js, создав простой API приложения todo. В этом руководстве предполагается наличие среднего уровня знаний JavaScript и опыта работы с командной строкой. Исходный код финального проекта можно найти здесь.
Начало работы
Для начала создайте новую папку и назовите ее todo.
$ mkdir todo $ cd todo
В папке с задачами создайте новый файл с именем app.js
$ touch app.js
Следующее, что нам нужно сделать, это установить Node. вы можете установить узел здесь. После установки узла мы установим экспресс с помощью npm. Node поставляется с npm, поэтому нам не нужно устанавливать npm.
Инициализировать приложение
Перейдите в командной строке к корню вашего приложения и запустите.
npm init
Повторно нажимайте клавишу возврата для каждого вопроса, который вам задают в командной строке.
Это создаст для вас файл package.json.
Установите зависимости и настройте Babel
$ npm install express —-save
Нам также потребуется установить babel, потому что мы будем писать синтаксис ES6, Babel помогает превратить наши коды с ES6 в ES5. почему мы должны компилировать наш код до ES5? Что ж, есть некоторые функции ES6, которые наши браузеры и узел еще не понимают, а старые браузеры не понимают коды ES6, поэтому мы используем babel для компиляции нашего кода в ES5, чтобы его могли понять как старые браузеры, так и новые браузеры. Наша цель использования babel здесь состоит в том, чтобы функции ES6, которые еще не являются частью узла, могли быть скомпилированы до ES5, который понимает узел.
$ npm install babel-cli --save
Мы также будем устанавливать babel-preset-es2015, пресеты содержат набор плагинов, эти плагины предназначены для функций ES6, установив и настроив babel-preset-es2015, мы сообщаем babel, что нужно преобразовать любые функции ES6, которые мы используем, которые содержатся в предустановки к их эквиваленту ES5.
$ npm install babel-preset-es2015 --save
Теперь нам нужно создать файл .babelrc, в файле babelrc мы настроим babel на использование предустановки es2015, которую мы установили в качестве предустановки при компиляции в ES5.
В корне нашего приложения мы создадим файл .babelrc.
$ touch .babelrc
В файле babelrc введите следующее, чтобы настроить предустановку.
{ "presets": ["es2015"] }
Это говорит babel использовать es2015 в качестве предустановки, обратите внимание, что ES2015 - это другое имя для ES6.
Создать фиктивную базу данных
Последнее, что нам нужно сделать, прежде чем мы начнем создавать наш Apis, - это создать фиктивную базу данных, которую мы будем использовать.
Создайте папку и назовите ее db.
$ mkdir db
В папке создайте файл и назовите его db.js
$ cd db $ touch db.js
В db.js создайте объект javascript для создания фиктивной базы данных
const todos = [ { id: 1, title: "lunch", description: "Go for lunc by 2pm" } ]; export default todos;
Настройте приложение и создайте нашу первую конечную точку
А теперь приступим к созданию нашего приложения.
import express from 'express';
import db from './db/db';
// Set up the express app
const app = express();
// get all todos
app.get('/api/v1/todos', (req, res) => {
res.status(200).send({
success: 'true',
message: 'todos retrieved successfully',
todos: db
})
});
const PORT = 5000;
app.listen(PORT, () => {
console.log(`server running on port ${PORT}`)
});
Мы импортировали экспресс, который мы установили в начале курса, app.get делает запрос на получение на сервер с маршрутом / конечной точкой, предоставленной в качестве первого параметра, конечная точка предназначена для возврата всех задач в базе данных. Второй параметр - это функция, которая запускается каждый раз, когда мы достигаем этой конечной точки. функция принимает два параметра: req и res. Объект req содержит информацию о нашем запросе, а объект ответа содержит информацию об ответе и методах, которые мы можем использовать для отправки информации обратно клиенту.
res.status (200) используется для отправки статуса запроса, 200 означает ОК и указывает на успешный запрос. Коды состояния - это способы, с помощью которых клиент, например веб-приложение или мобильное приложение, может проверить, пошло ли что-то не так. действительно заинтересованы. Если возвращается 200, мы можем проверить полезную нагрузку, потому что знаем, что чего-то ожидаем. Подробнее о кодах статуса HTTP можно узнать здесь.
res.send () используется для отправки ответа клиенту, ресурс, переданный в send в качестве параметра, - это то, что отправляется обратно клиенту. в этом случае мы отправляем обратно объект, который содержит некоторую информацию, свойство todos объекта содержит данные, которые мы импортировали в верхней части app.js из нашей фиктивной базы данных.
app.listen создает для нас веб-сервер, он принимает два параметра, первый параметр - это порт, который мы хотим, чтобы наше приложение прослушивало t, независимо от того, какой порт мы предоставляем, в нашем случае 5000 будет порт, на котором будет работать наш сервер в нашей системе. второй параметр является необязательным, это функция обратного вызова того, что должно произойти при создании сервера, в нашем случае мы записываем сообщение в консоль. когда сервер будет создан, мы сможем получить доступ к нашей конечной точке ’/ api / v1 / todos’ оттуда. сервер будет работать на порту 5000 на локальном хосте на нашей машине. так что у нас будет наш маршрут localhost: port / api. Созданная нами конечная точка будет доступна следующим образом: localhost: 5000 / api / v1 / todos.
Теперь, чтобы запустить этот код, перейдем к командной строке. Обычно мы запускаем наше приложение узла из командной строки, как это.
$ node app.js
Но это вызовет ошибку, потому что наш код находится на ES6, и для успешного выполнения нашего кода нам нужно будет запустить его с помощью babel-node, который скомпилирует его в ES5. babel-node поставляется с babel-cli, которое мы установили в начале курса.
$ node_modules/.bin/babel-node app.js
Теперь мы можем пойти к почтальону и протестировать нашу конечную точку, почтальон - это приложение, которое мы используем для тестирования наших конечных точек. скачать почтальона можно здесь.
Чтобы протестировать конечную точку, мы перейдем на localhost: 5000 / api / v1 / todos.
Взгляните на «GET» перед localhost: 5000 / api / v1 / todos, помните, что наша конечная точка - это запрос на получение, поэтому мы установили этот раскрывающийся список на «GET», если наша конечная точка была почтовым запросом, то есть у нас было приложение. post, тогда мы бы установили для него POST.
Запускать наш сервер, запуская это каждый раз, сложно, чтобы упростить этот процесс, мы собираемся сделать две вещи: во-первых, мы собираемся установить nodemon, во-вторых, мы создадим скрипт в нашем пакете, json, чтобы запустить наш сервер.
Давайте установим nodemon, запустите в своем терминале следующее.
$ npm install nodemon --save-dev
Nodemon следит за вашим приложением на предмет изменений файлов и перезапускает сервер каждый раз, когда файл изменяется в вашем приложении. Это упрощает вашу работу, потому что вам не нужно запускать и перезапускать сервер вручную каждый раз, когда вы меняете файлы в приложении.
Давайте создадим скрипт в вашем package.json внутри части скрипта, включая это
"start": "node_modules/.bin/nodemon app.js --exec babel-node --"
Вы знаете, что делает babel-node.
Ваши скрипты package.json должны выглядеть так
{ "name": "todo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "nodemon app.js --exec babel-node --" }, "author": "", "license": "ISC", "dependencies": { "babel-cli": "^6.26.0", "babel-preset-es2015": "^6.24.1" "express": "^4.16.3" } }
Теперь каждый раз, когда мы хотим запустить наше приложение, мы просто запускаем следующий скрипт на терминале.
npm run start
Это запустит стартовый скрипт в нашем файле package.json.
Давайте создадим конечную точку для добавления задач, но перед этим давайте установим пакет под названием body-parser, body-parser анализирует тела входящих запросов в промежуточном программном обеспечении перед вашими обработчиками, доступными в req.bodyproperty.
Когда вы отправляете данные на сервер, данные могут поступать из формы или это может быть json, парсер тела анализирует эти данные, поступающие от клиента, в объекте с именем req.body, поэтому для Например, если у меня есть данные JSON, поступающие от клиента на сервер.
{ "name": "Ola", "school": "unilag" }
Что делает парсер тела, так это то, что он анализирует эти данные JSON и делает их доступными в req.body как свойство. помните, что req - это первое свойство, которое мы предоставляем для нашего обратного вызова, когда мы делаем запрос API, и помните, что я сказал, что req содержит информацию о запросе, исходящем от клиента, поэтому парсер тела делает данные, поступающие из формы, или любые данные JSON, поступающие от клиента, доступного как свойство в req.body, поэтому мы можем получить доступ к данным JSON из req.body как.
req.body.name req.body.school
Итак, давайте установим body-parser
$ npm install body-parser --save
Теперь давайте импортируем его в app.js
import bodyParser from 'body-parser';
Теперь мы настроим парсер тела для нашего приложения вот так.
const app = express(); // Parse incoming requests data app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false }));
Создать Todo
Теперь перейдем к созданию конечной точки для создания задачи.
app.post('/api/v1/todos', (req, res) => { if(!req.body.title) { return res.status(400).send({ success: 'false', message: 'title is required' }); } else if(!req.body.description) { return res.status(400).send({ success: 'false', message: 'description is required' }); } const todo = { id: db.length + 1, title: req.body.title, description: req.body.description } db.push(todo); return res.status(201).send({ success: 'true', message: 'todo added successfully', todo }) });
В этой конечной точке мы не делаем запрос к серверу для получения данных, а скорее отправляем данные. как мы объяснили, входящие данные анализируются в req.body как свойства, поэтому у нас есть req. body.title и т. д.
Мы создаем объект todo с информацией, которую мы получили от клиента через body-parser, а затем помещаем его в фиктивный массив db в качестве нового todo.
Давайте проверим это в почтальоне, нам нужно будет передать некоторые данные и отправить их на сервер, чтобы проверить это, на почтальоне, когда вы выбираете POST, щелкните тело n перед заголовками, которые находятся перед авторизацией, и передайте свои значения в поле.
localhost: 5000 / api / v1 / todos, убедитесь, что вы установили HTTP-метод в почтальоне на POST.
Взгляните на 'POST' перед localhost: 5000 / api / v1 / todos, помните, что наша конечная точка - это почтовый запрос, поэтому мы установили этот раскрывающийся список на POST. Убедитесь, что переключатель x-www-form-urlencoded установлен или используйте raw, где вы передаете данные JSON, как это.
{ "title": "breakfast", "description": "get breakfast" }
Получите одно задание
Теперь давайте создадим конечную точку, чтобы получить одно задание из базы данных. Введите следующее:
app.get('/api/v1/todos/:id', (req, res) => { const id = parseInt(req.params.id, 10); db.map((todo) => { if (todo.id === id) { return res.status(200).send({ success: 'true', message: 'todo retrieved successfully', todo, }); } }); return res.status(404).send({ success: 'false', message: 'todo does not exist', }); });
Как обычно, эта конечная точка принимает два параметра: маршрут и функцию обратного вызова. Другое дело, что маршрут в этой конечной точке имеет: id, иногда мы хотим передать параметры нашим конечным точкам, потому что они потребуются нам в нашем приложении, чтобы передать те параметры, которые мы используем: param.
Конечная точка, созданная выше, предназначена для получения одного задания, для получения одного задания нам понадобится уникальный способ идентифицировать это задание в базе данных, поэтому, если мы знаем идентификатор задания, которое мы хотим получить, мы можем затем его получить. из базы данных, поэтому каждый раз, когда мы делаем запрос к этой конечной точке, мы передаем идентификатор задачи, которую хотим получить, функция обратного вызова затем запросит базу данных для задачи с этим приложением.
Что происходит в конечной точке выше, так это то, что мы передаем идентификатор задачи, которую хотим получить в качестве параметра для маршрута, чтобы получить значение идентификатора, переданное в маршрут, который мы используем req.params.id, req.params - это объект, который содержит все параметры, переданные маршрутам, мы преобразуем идентификатор в int, а затем мы перебираем нашу фиктивную базу данных db, чтобы найти задачу, идентификатор которой будет равен тому, который мы получили из URL-адреса, тогда соответствующая задача будет вернулся как единственное задание.
Давайте проверим это, возьмем общее количество задач в базе данных, чтобы увидеть, что у нас есть на данный момент.
Теперь давайте добавим новую задачу в базу данных.
Давайте снова получим все задачи из базы данных
Теперь у нас есть новое задание, которое мы только что добавили в базу данных.
Давайте теперь протестируем нашу конечную точку, перейдите по адресу localhost: 5000 / api / v1 / todos /: id, замените: id на идентификатор задачи, которую вы хотите получить. в нашем случае задача с идентификатором 2, установите для метода http значение GET.
Удалить Todo
Теперь давайте создадим конечную точку для удаления задач из базы данных.
app.delete('/api/v1/todos/:id', (req, res) => { const id = parseInt(req.params.id, 10); db.map((todo, index) => { if (todo.id === id) { db.splice(index, 1); return res.status(200).send({ success: 'true', message: 'Todo deleted successfuly', }); } }); return res.status(404).send({ success: 'false', message: 'todo not found', }); });
Так что мы здесь делаем? ну, в основном мы передаем id задачи, которую хотим удалить, в качестве параметра route / api / v1 / todos /: id. мы получаем этот идентификатор с помощью req.params.id, поэтому, чтобы удалить элемент с этим идентификатором, мы должны сначала найти его в базе данных, мы сделали это, сопоставив массив db и проверив идентификатор текущего дела в итерация по идентификатору, полученному из маршрута, пока мы не найдем совпадение, затем мы используем метод массива splice (), чтобы удалить этот элемент из базы данных. Вы можете узнать больше о array.splice и о том, как он работает здесь. В случае, если мы ничего не находим, мы возвращаем пользователю сообщение todo not found.
Теперь давайте проверим это, сначала давайте извлечем задачи из нашей базы данных, чтобы увидеть, что у нас есть.
Теперь давайте добавим новую задачу
давай снова принесем все наши задачи
Как вы можете видеть, теперь у нас есть два задачи в нашей базе данных, предыдущая, которая была там изначально (мы жестко запрограммировали это в приложении), - это задача с идентификатором 1, а новая, которую мы добавили, - это задача с идентификатором. из 2.
Теперь давайте удалим задачу с идентификатором 1, перейдя к только что созданной конечной точке. Перейдите к localhost: 5000 / api / v1 / todos /: id, id в этом случае 1, просто замените: id на 1 в конечной точке.
Теперь давайте возьмем всю конечную точку, чтобы увидеть, действительно ли мы удалили задачу.
Теперь у нас есть только задача с идентификатором 2.
Давайте попробуем удалить Todo с несуществующим идентификатором.
Мы получаем сообщение, что задача не найдена.
Обновить Todo
Теперь давайте создадим конечную точку для обновления задач.
app.put('/api/v1/todos/:id', (req, res) => { const id = parseInt(req.params.id, 10); let todoFound; let itemIndex; db.map((todo, index) => { if (todo.id === id) { todoFound = todo; itemIndex = index; } }); if (!todoFound) { return res.status(404).send({ success: 'false', message: 'todo not found', }); } if (!req.body.title) { return res.status(400).send({ success: 'false', message: 'title is required', }); } else if (!req.body.description) { return res.status(400).send({ success: 'false', message: 'description is required', }); } const updatedTodo = { id: todoFound.id, title: req.body.title || todoFound.title, description: req.body.description || todoFound.description, }; db.splice(itemIndex, 1, updatedTodo); return res.status(201).send({ success: 'true', message: 'todo added successfully', updatedTodo, }); });
Как обычно, мы получаем идентификатор задачи, которую хотим обновить, из URL-адреса, мы перебираем нашу фиктивную базу данных, чтобы найти задачу с этим идентификатором, если мы не находим задачу, мы возвращаем сообщение пользователю с указанием задачи не найден. Если мы находим задачу, мы получаем новый ввод, предоставленный пользователем, новый ввод анализируется парсером тела в req.body, мы получаем обновленные записи из req.body и создаем с ним обновленный объект задачи. Затем мы используем db.splice, чтобы удалить старый todo, который соответствует нашей итерации, когда мы перебирали фиктивный db, и заменяем его на updatedTodo, который мы создали.
Давай проверим это.
Давайте возьмем все задачи, которые есть в нашей базе данных в настоящее время. Обратите внимание, что каждый раз, когда ваш сервер перезагружается, вы теряете записи, которые у вас есть в памяти, поэтому мы теряем задачу, которую мы добавили через почтальона, когда наш сервер перезагружается, за исключением того, который мы жестко запрограммировали в приложении. .
Теперь давайте обновим задачу с идентификатором 1.
Мы подошли к концу этого урока, есть вторая часть этого урока, и вы можете найти ее здесь. Спасибо за ваше время и терпение, чтобы пройти через это, и я очень надеюсь, что вы узнали одну или две вещи.