REST представляет собой один из самых популярных подходов к построению архитектуры API с передачей данных по протоколу HTTP и означает "передача состояния представления".
Основная идеи REST API заключается в разделении разных операций (чаще всего CRUD) при обращении к одному и тому же URL с помощью HTTP методов, основные из которых:
GET - используется для получения данных;
POST - используется для создания новой записи(ей);
PUT - используется для обновления уже существующей записи(ей);
PATCH - используется для обновления, но только тогда, когда изменяется идентификатор записи(ей);
process.env.NODE_ENV='development';constexpress=require('express'),app=express(),fs=require('fs');consthost='127.0.0.1';constport=7000;app.use(express.json());app.use(express.urlencoded({extended:true}));letfile='data.json';if((process.env.NODE_ENV='test'))file='data-test.json';app.use((req,res,next)=>{fs.readFile(file,(err,data)=>{if(err)returnres.status(500).send({message:'Error while getting users',});req.users=JSON.parse(data);next();});});app.route('/api/users').get((req,res)=>{if(req.query.id){if(req.users.hasOwnProperty(req.query.id))returnres.status(200).send({data:req.users[req.query.id],});elsereturnres.status(404).send({message:'User not found.'});}elseif(!req.users)returnres.status(404).send({message:'Users not found.'});returnres.status(200).send({data:req.users});}).post((req,res)=>{if(req.body.user&&req.body.user.id){if(req.users.hasOwnProperty(req.body.user.id))returnres.status(409).send({message:'User already exists.',});req.users[req.body.user.id]=req.body.user;fs.writeFile(file,JSON.stringify(req.users),(err,response)=>{if(err)returnres.status(500).send({message:'Unable create user.',});returnres.status(200).send({message:'User created.'});});}elsereturnres.status(400).send({message:'Bad request.'});}).put((req,res)=>{if(req.body.user&&req.body.user.id){if(!req.users.hasOwnProperty(req.body.user.id))returnres.status(404).send({message:'User not found.'});req.users[req.body.user.id]=req.body.user;fs.writeFile(file,JSON.stringify(req.users),(err,response)=>{if(err)returnres.status(500).send({message:'Unable update user.',});returnres.status(200).send({message:'User updated.'});});}elsereturnres.status(400).send({message:'Bad request.'});}).delete((req,res)=>{if(req.query.id){if(req.users.hasOwnProperty(req.query.id)){deletereq.users[req.query.id];fs.writeFile(file,JSON.stringify(req.users),(err,response)=>{if(err)returnres.status(500).send({message:'Unable delete user.',});returnres.status(200).send({message:'User deleted.',});});}elsereturnres.status(404).send({message:'User not found.'});}elsereturnres.status(400).send({message:'Bad request.'});});app.listen(port,host,()=>console.log(`Server listens http://${host}:${port}`));
!!! note "" Использование глаголов в названии маршрута при создании REST API считается плохой практикой и будет концептуально неправильным.
Здесь сразу предусмотрено наличие файла для тестирования приложения. Использование того или иного файла зависит от заданного переменной process.env.NODE_ENV окружения. Тестирование API рассмотрено отдельно.
В приведенном примере для одного маршрута /api/users определяются разные обработчики, каждый из которых вызывается в зависимости от используемого при запросе HTTP-метода.
Для приведенного примера подразумевается, что в файле data.json по умолчанию находится пустой объект.
При внесении изменений в логику работы вашего REST API, если оно является публичным, рекомендуется оставлять работоспособной предыдущую версию, чтобы предотвратить возникновение критических ошибок у пользователей прошлой версии. Версионность можно указывать прямо в URL.
1
app.route('/api/v1/users');
Если изначально дальнейшее развитие API не планировалось и версионность не предусматривалась, но потом все же пришлось вносить изменения, то номер версии можно добавить в уже новые маршруты. Главное - оставить стабильной предыдущий вариант.