Как настроить обработку маршрута, при которой используется строка запроса?

Как можно улучшить код для обработки запросов /api/users с учетом добавления функциональности пагинации, чтобы обеспечить более четкую структуру и лучшую организацию зон ответственности?
  • 21 января 2024 г. 13:28
Ответы на вопрос 2
Чтобы настроить обработку маршрута с использованием строки запроса, вы можете использовать различные фреймворки и библиотеки, в зависимости от используемой технологии. В качестве примера, предположим, что мы используем Node.js с Express.js для создания REST API.

Во-первых, вы должны определить маршрут в вашем приложении Express, который сопоставляется с `/api/users`. В этом маршруте вы будете анализировать параметры строки запроса для пагинации, например, `page` и `limit`.

```javascript
const express = require('express');
const app = express();
const port = 3000;

app.get('/api/users', (req, res) => {
    // Получение параметров пагинации из строки запроса
    let { page, limit } = req.query;

    // Установка значений по умолчанию, если параметры не предоставлены
    page = page ? parseInt(page, 10) : 1;
    limit = limit ? parseInt(limit, 10) : 10;

    // Расчет offset для запроса в базу данных
    const offset = (page - 1) * limit;

    // Здесь вы должны получить данные из базы данных с учетом пагинации
    // Это просто пример, данные и логика обращения к базе данных сюда не включены
    // ...

    // Отправка ответа с данными
    res.json({
        success: true,
        data: [], // здесь будут данные пользователей для текущей страницы
        page,
        limit
        // дополнительные поля, такие как total_pages, если необходимо
    });
});

app.listen(port, () => {
    console.log(`Server running on port ${port}`);
});
```

Чтобы улучшить структуру кода, вы можете разделить ваше приложение на модули. Каждый модуль будет отвечать за свою зону ответственности: контроллеры для обработки запросов, сервисы для бизнес-логики, и репозитории для общения с базой данных.

```javascript
// userController.js
const userService = require('./userService');

exports.getUsers = async (req, res) => {
    let { page, limit } = req.query;
    page = page ? parseInt(page, 10) : 1;
    limit = limit ? parseInt(limit, 10) : 10;

    try {
        const users = await userService.findPaginatedUsers(page, limit);
        res.json({
            success: true,
            ...users
        });
    } catch (error) {
        res.status(500).json({
            success: false,
            message: "Ошибка сервера"
        });
    }
};

// userService.js
const userRepository = require('./userRepository');

exports.findPaginatedUsers = async (page, limit) => {
    const offset = (page - 1) * limit;
    // Получение данных из репозитория
    const { users, totalCount } = await userRepository.getPaginatedUsers(offset, limit);

    // Дополнительная логика, если нужно

    return {
        data: users,
        page,
        limit,
        total_pages: Math.ceil(totalCount / limit)
    };
};

// userRepository.js
// Здесь код для общения с базой данных...

// В app.js
const userController = require('./userController');
app.get('/api/users', userController.getUsers);
```

Таким образом, вы можете разделить ваше приложение на контроллеры, сервисы и репозитории. Это улучшит читаемость, тестируемость и поддержку кода.
Если завтра вы захотите сделать получение пользователей по какому-либо принципу (роль, фамилия, дата регистрации), то метод readAll разрастётся ещё сильнее и вы будете передавать в него очень много параметров. Это неправильно. 

Так же у вас ошибка - в методе readAll не может быть и получения всех пользователей, и получения их количества (count). Подсчёт строк - это отдельный метод, который отдельно должен дёргаться в роуте. Метод readAll только получает пользователей.

Относительно вашей проблемы - проще всего использовать готовую ORM, а не пытаться самому её написать. Но по каким-то причинам ORM не хочется, достаточно сделать вместо нескольких параметров один объект - запрос и передавать его.

Важно, что передав объект, вы должны его правильно преобразовать в SELECT. Этим может заниматься сам объект, например. А можно написать ещё один, который будет преобразовывать объекты запросов в SQL-строку, которую вы уже будете использовать в readAll.
Похожие вопросы