Магазин на JavaScript, часть 2 из 20. Обрабатываем HTTP запросы, добавляем маршруты

12.11.2021

Теги: BackendExpress.jsFrontendJavaScriptNode.jsORMReact.jsWeb-разработкаБазаДанныхИнтернетМагазинКаталогТоваровКорзинаФреймворк

Обрабатываем GET-запрос

Сервер работает, но если мы попробуем открыть в браузере страницу localhost:7000, то получим ошибку «Cannot GET /». Нужно указать серверу, какие endpoint обрабатывать и что делать при поступлении GET, POST, PUT и DELETE запросов. Так что открываем на редактирование файл index.js — при GET-запросе на URL «/» — отправляем в ответ «Hello, world!».

/* .......... */
const app = express()

app.get('/', (req, res) => {
    res.status(200).send('Hello, world!')
})

const start = async () => {
    /* .......... */
}

start()

Чтобы работать с данными в формате json — добавляем middleware:

/* .......... */
const app = express()
app.use(express.json())

app.get('/', (req, res) => {
    res.status(200).json({message: 'Hello, world!'})
})

const start = async () => {
    /* .......... */
}

start()

Когда мы создадим клиента, который будет работать с нашим сервером — то столкнемся с ошибкой «blocked by CORS policy». Допустим, наш клиент размещен на localhost:3000, и на клиенте есть следующий код:

fetch('http://localhost:7000/')
    .then(response => response.text())
    .then((result) => {
        document.body.textContent = result
    })

Браузеры не позволяют через javascript обращаться с одного домена (localhost:3000) на другой (localhost:7000) без разрешения со стороны запрашиваемого домена (то есть localhost:7000). Чтобы разрешить клиентам с других доменов обращаться к нашему серверу, наш сервер должен отправить заголовки:

Access-Control-Allow-Origin: откуда можно отправлять запросы
Access-Control-Allow-Methods: какие методы HTTP разрешены
Access-Control-Allow-Origin: * (разрешено с любого домена)
Access-Control-Allow-Methods: GET, PUT, POST, DELETE, HEAD

Поэтому добавляем еще middleware, который эти заголовки отправит:

import config from 'dotenv/config'
import express from 'express'
import sequelize from './sequelize.js'
import * as mapping from './models/mapping.js'
import cors from 'cors'

const PORT = process.env.PORT || 5000

const app = express()
app.use(cors())
app.use(express.json())

app.get('/', (req, res) => {
    res.status(200).json({message: 'Hello, world!'})
})

const start = async () => {
    try {
        await sequelize.authenticate()
        await sequelize.sync()
        app.listen(PORT, () => console.log('Сервер запущен на порту', PORT))
    } catch(e) {
        console.log(e)
    }
}

start()

Обрабатываем POST-запрос

Хорошо, теперь нам нужно расширение REST Client для VS Code для отправки POST-запроса — создаем файл test.http (см. здесь):

GET / HTTP/1.1
Host: localhost:7000

###

POST / HTTP/1.1
Host: localhost:7000
Content-type: application/json; charset=utf-8

{
    "name": "Сергей",
    "age": 30
}

А наш сервер в ответ на POST-запрос будет возвращать тело запроса:

// обрабатываем GET-запрос
app.get('/', (req, res) => {
    res.status(200).json({message: 'Hello, world!'})
})

// обрабатываем POST-запрос
app.post('/', (req, res) => {
    res.status(200).json(req.body)
})

Добавляем маршруты

Описывать все конечные точки в файле index.js — плохая идея. Создадим для этой цели отдельную директорию routes и внутри нее — файлы index.js, product.js, category.js, brand.js и user.js.

import express from 'express'

import product from './product.js'
import category from './category.js'
import brand from './brand.js'
import user from './user.js'

const router = new express.Router()

router.use('/product', product)
router.use('/category', category)
router.use('/brand', brand)
router.use('/user', user)

export default router
import express from 'express'

const router = new express.Router()

router.get('/getall', (req, res) => res.status(200).send('Список всех товаров'))
router.get('/getone/:id([0-9]+)', (req, res) => res.status(200).send('Получение одного товара'))
router.post('/create', (req, res) => res.status(200).send('Создание нового товара'))
router.put('/update/:id([0-9]+)', (req, res) => res.status(200).send('Обновление товара'))
router.delete('/delete/:id([0-9]+)', (req, res) => res.status(200).send('Удаление товара'))

export default router
import express from 'express'

const router = new express.Router()

router.get('/getall', (req, res) => res.status(200).send('Список всех категорий'))
router.get('/getone/:id([0-9]+)', (req, res) => res.status(200).send('Получение одной категории'))
router.post('/create', (req, res) => res.status(200).send('Создание новой категории'))
router.put('/update/:id([0-9]+)', (req, res) => res.status(200).send('Обновление категории'))
router.delete('/delete/:id([0-9]+)', (req, res) => res.status(200).send('Удаление категории'))

export default router
import express from 'express'

const router = new express.Router()

router.get('/getall', (req, res) => res.status(200).send('Список всех брендов'))
router.get('/getone/:id([0-9]+)', (req, res) => res.status(200).send('Получение одного бренда'))
router.post('/create', (req, res) => res.status(200).send('Создание нового бренда'))
router.put('/update/:id([0-9]+)', (req, res) => res.status(200).send('Обновление бренда'))
router.delete('/delete/:id([0-9]+)', (req, res) => res.status(200).send('Удаление бренда'))

export default router
import express from 'express'

const router = new express.Router()

router.post('/signup', (req, res) => res.status(200).send('Регистрация пользователя'))
router.post('/login', (req, res) => res.status(200).send('Вход в личный кабинет'))
router.get('/check', (req, res) => res.status(200).send('Проверка авторизации'))

router.get('/getall', (req, res) => res.status(200).send('Список всех пользователй'))
router.get('/getone/:id([0-9]+)', (req, res) => res.status(200).send('Получение одного пользователя'))
router.post('/create', (req, res) => res.status(200).send('Создание нового пользователя'))
router.put('/update/:id([0-9]+)', (req, res) => res.status(200).send('Обновление пользователя'))
router.delete('/delete/:id([0-9]+)', (req, res) => res.status(200).send('Удаление пользователя'))

export default router

Теперь сообщим приложению, какие маршруты у нас имеются — для этого редактируем index.js:

import config from 'dotenv/config'
import express from 'express'
import sequelize from './sequelize.js'
import * as mapping from './models/mapping.js'
import cors from 'cors'
import router from './routes/index.js'

const PORT = process.env.PORT || 5000

const app = express()
app.use(cors())
app.use(express.json())
app.use('/api', router)

const start = async () => {
    try {
        await sequelize.authenticate()
        await sequelize.sync()
        app.listen(PORT, () => console.log('Сервер запущен на порту', PORT))
    } catch(e) {
        console.log(e)
    }
}

start()

Для проверки, что все работает правильно — редактируем файл test.http:

### Список всех товаров
GET /api/product/getall HTTP/1.1
Host: localhost:7000

### Получить один товар
GET /api/product/getone/12345 HTTP/1.1
Host: localhost:7000

### Создать новый товар
POST /api/product/create HTTP/1.1
Host: localhost:7000

### Обновить товар
PUT /api/product/update/12345 HTTP/1.1
Host: localhost:7000

### Удалить товар
DELETE /api/product/delete/12345 HTTP/1.1
Host: localhost:7000

Поиск: Backend • Express.js • Frontend • JavaScript • Node.js • ORM • React.js • Web-разработка • База данных • Интернет магазин • Каталог товаров • Корзина • Фреймворк

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.