Создание api на javascript
Используя Express и Node.js, мы можем реализовать полноценный API в стиле REST для взаимодействия с пользователем. Архитектура REST предполагает применение следующих методов или типов запросов HTTP для взаимодействия с сервером:
Зачастую REST-стиль особенно удобен при создании всякого рода Single Page Application, которые нередко используют специальные javascript-фреймворки типа Angular, React или Knockout.
Рассмотрим, как создать свой API. Для нового проекта создадим новую папку, которая пусть будет называться webapp . Сразу определим в проекте файл package.json :
В проекте нам понадобятся express для обработки запроса. Далее перейдем к этому каталогу в командной строке/терминале и для добавления пакета выполним команду:
В данном случае мы создадим экспериментальный проект, который будет хранить данные в файле json и который призван просто показать создание API в Node.js в стиле REST. А пока добавим в папку проекта новый файл users.json со следующим содержанием:
Для чтения и записи в этот файл мы будем использовать встроенный модуль fs. Для обработки запросов определим в проекте следующий файл app.js :
const express = require("express"); const fs = require("fs"); const app = express(); const jsonParser = express.json(); app.use(express.static(__dirname + "/public")); const filePath = "users.json"; app.get("/api/users", function(req, res)< const content = fs.readFileSync(filePath,"utf8"); const users = JSON.parse(content); res.send(users); >); // получение одного пользователя по id app.get("/api/users/:id", function(req, res) < const // получаем id const content = fs.readFileSync(filePath, "utf8"); const users = JSON.parse(content); let user = null; // находим в массиве пользователя по id for(var i=0; i> // отправляем пользователя if(user) < res.send(user); >else < res.status(404).send(); >>); // получение отправленных данных app.post("/api/users", jsonParser, function (req, res) < if(!req.body) return res.sendStatus(400); const userName = req.body.name; const userAge = req.body.age; let user = ; let data = fs.readFileSync(filePath, "utf8"); let users = JSON.parse(data); // находим максимальный id const o.id;>)) // увеличиваем его на единицу user.id = id+1; // добавляем пользователя в массив users.push(user); data = JSON.stringify(users); // перезаписываем файл с новыми данными fs.writeFileSync("users.json", data); res.send(user); >); // удаление пользователя по id app.delete("/api/users/:id", function(req, res) < const let data = fs.readFileSync(filePath, "utf8"); let users = JSON.parse(data); let index = -1; // находим индекс пользователя в массиве for(var i=0; i < users.length; i++)< if(users[i].id==id)< index=i; break; >> if(index > -1) < // удаляем пользователя из массива по индексу const user = users.splice(index, 1)[0]; data = JSON.stringify(users); fs.writeFileSync("users.json", data); // отправляем удаленного пользователя res.send(user); >else < res.status(404).send(); >>); // изменение пользователя app.put("/api/users", jsonParser, function(req, res) < if(!req.body) return res.sendStatus(400); const userId = req.body.id; const userName = req.body.name; const userAge = req.body.age; let data = fs.readFileSync(filePath, "utf8"); const users = JSON.parse(data); let user; for(var i=0; i> // изменяем данные у пользователя if(user) < user.age = userAge; user.name = userName; data = JSON.stringify(users); fs.writeFileSync("users.json", data); res.send(user); >else < res.status(404).send(user); >>); app.listen(3000, function()< console.log("Сервер ожидает подключения. "); >);
Для обработки запросов определено пять методов для каждого типа запросов: app.get()/app.post()/app.delete()/app.put()
Когда приложение получает запрос типа GET по адресу «api/users», то срабатывает следующий метод:
app.get("/api/users", function(req, res)< const content = fs.readFileSync(filePath,"utf8"); const users = JSON.parse(content); res.send(users); >);
В качестве результата обработки мы должны отправить массив пользователей, которые считываем из файла. Для упрощения кода приложения в рамкаха данного экспериментального проекта для чтения/записи файла применяются синхронные методы fs.readFileSync()/fs.writeFileSync() . Но в реальности, как правило, работа с данными будет идти через базу данных, а далее мы все это рассмотрим на примере MongoDB.
И чтобы получить данные из файла с помощью метода fs.readFileSync() считываем данные в строку, которую парсим в массив объектов с помощью функции JSON.parse() . И в конце полученные данные отправляем клиенту методом res.send() .
Аналогично работает другой метод app.get() , который срабатывает, когда в адресе указан id пользователя:
app.get("/api/users/:id", function(req, res) < const // получаем id const content = fs.readFileSync(filePath, "utf8"); const users = JSON.parse(content); let user = null; // находим в массиве пользователя по id for(var i=0; i> // отправляем пользователя if(user) < res.send(user); >else < res.status(404).send(); >>);
Единственное, что в этом случае нам надо найти нужного пользователя по id в массиве, а если он не был найден, возвратить статусный код 404: res.status(404).send() .
При получении запроса методом POST нам надо применить парсер jsonParser для извлечения данных из запроса:
// получение отправленных данных app.post("/api/users", jsonParser, function (req, res) < if(!req.body) return res.sendStatus(400); const userName = req.body.name; const userAge = req.body.age; let user = ; let data = fs.readFileSync(filePath, "utf8"); let users = JSON.parse(data); // находим максимальный id const o.id;>)) // увеличиваем его на единицу user.id = id+1; // добавляем пользователя в массив users.push(user); data = JSON.stringify(users); // перезаписываем файл с новыми данными fs.writeFileSync("users.json", data); res.send(user); >);
После получения данных нам надо создать новый объект и добавить его в массив объектов. Для этого считываем данные из файла, добавляем в массив новый объект и перезаписываем файл с обновленными данными.
При удалении производим похожие действия, только теперь извлекаем из массива удаляемый объект и опять же перезаписываем файл:
// удаление пользователя по id app.delete("/api/users/:id", function(req, res) < const let data = fs.readFileSync(filePath, "utf8"); let users = JSON.parse(data); let index = -1; // находим индекс пользователя в массиве for(var i=0; i < users.length; i++)< if(users[i].id==id)< index=i; break; >> if(index > -1) < // удаляем пользователя из массива по индексу const user = users.splice(index, 1)[0]; data = JSON.stringify(users); fs.writeFileSync("users.json", data); // отправляем удаленного пользователя res.send(user); >else < res.status(404).send(); >>);
Если объект не найден, возвращаем статусный код 404.
Если приложению приходит PUT-запрос, то он обрабатывается методом app.put() , в котором с помощью jsonParser получаем измененные данные:
app.put("/api/users", jsonParser, function(req, res) < if(!req.body) return res.sendStatus(400); const userId = req.body.id; const userName = req.body.name; const userAge = req.body.age; let data = fs.readFileSync(filePath, "utf8"); const users = JSON.parse(data); let user; for(var i=0; i> // изменяем данные у пользователя if(user) < user.age = userAge; user.name = userName; data = JSON.stringify(users); fs.writeFileSync("users.json", data); res.send(user); >else < res.status(404).send(user); >>);
Здесь также для поиска изменяемого объекта считываем данные из файла, находим изменяемого пользователя по id, изменяем у него свойства и сохраняем обновленные данные в файл.
Таким образом, мы определили простейший API. Теперь добавим код клиента. Итак, как установлено в коде, Express для хранения статических файлов использует папку public , поэтому создадим в проекте подобную папку. В этой папке определим новый файл index.html , который будет выполнять роль клиента. В итоге весь проект будет выглядеть следующим образом:
Далее определим в файле index.html следующий код:
Список пользователей
Id | Имя | возраст |
---|
Основная логика здесь заключена в коде javascript. При загрузке страницы в браузере получаем все объекты из БД с помощью функции GetUsers:
async function GetUsers() < // отправляет запрос и получаем ответ const response = await fetch("/api/users", < method: "GET", headers: < "Accept": "application/json" >>); // если запрос прошел нормально if (response.ok === true) < // получаем данные const users = await response.json(); let rows = document.querySelector("tbody"); users.forEach(user =>< // добавляем полученные элементы в таблицу rows.append(row(user)); >); > >
Для добавления строк в таблицу используется функция row() , которая возвращает строку. В этой строке будут определены ссылки для изменения и удаления пользователя.
Ссылка для изменения пользователя с помощью функции GetUser() получает с сервера выделенного пользователя:
async function GetUser(id) < const response = await fetch("/api/users/" + id, < method: "GET", headers: < "Accept": "application/json" >>); if (response.ok === true) < const user = await response.json(); const form = document.forms["userForm"]; form.elements["id"].value = user.id; form.elements["name"].value = user.name; form.elements["age"].value = user.age; >>
И выделенный пользователь добавляется в форму над таблицей. Эта же форма применяется и для добавления объекта. С помощью скрытого поля, которое хранит id пользователя, мы можем узнать, какое действие выполняется — добавление или редактирование. Если id равен 0, то выполняется функция CreateUser, которая отправляет данные в POST-запросе:
async function CreateUser(userName, userAge) < const response = await fetch("api/users", < method: "POST", headers: < "Accept": "application/json", "Content-Type": "application/json" >, body: JSON.stringify(< name: userName, age: parseInt(userAge, 10) >) >); if (response.ok === true) < const user = await response.json(); reset(); document.querySelector("tbody").append(row(user)); >>
Если же ранее пользователь был загружен на форму, и в скрытом поле сохранился его id, то выполняется функция EditUser, которая отправляет PUT-запрос:
async function EditUser(userId, userName, userAge) < const response = await fetch("api/users", < method: "PUT", headers: < "Accept": "application/json", "Content-Type": "application/json" >, body: JSON.stringify(< id: userId, name: userName, age: parseInt(userAge, 10) >) >); if (response.ok === true) < const user = await response.json(); reset(); document.querySelector("tr[data-rowid='" + user.id + "']").replaceWith(row(user)); >>