Найти тему
Nuances of programming

Как создать сетевой API с помощью Express.js, Bun и MongoDB

Оглавление

Источник: Nuances of Programming

Веб-API служат центральными компонентами современного ПО, обеспечивая беспрепятственную связь между приложениями в обширном пространстве интернета.

Если вы работаете с Node.js, то наверняка знакомы со стеком MER(A)N:

  1. MongoDB;
  2. Express;
  3. React/Angular;
  4. Node.

Но с появлением Bun создавать высокопроизводительные API стало гораздо проще. В этой статье будет описан процесс разработки API Express.js с использованием MongoDB на базе Bun.

Представление инструментов

Рассмотрим каждый из вышеупомянутых инструментов, чтобы было понятно, с чем предстоит работать.

  • Express.js. Изящный и простой веб-фреймворк, легко интегрируемый с Node.js и позволяющий пользователям с легкостью создавать API.
  • MongoDB. NoSQL-система управления базами данных, которая отличается универсальностью и легко справляется с большими объемами данных.
  • Bun. Среда выполнения JavaScript, которая служит заменой Node.js.

Настройка приложения и создание API

1. Установка Bun

Прежде всего установим Bun. Для этого надо выполнить команду:

curl https://bun.sh/install | bash

Проверьте корректность установки, выполнив команду bun --version.

2. Создание проекта Bun

Инициализируем проект Bun:

bun create blog-api

Вы можете использовать структуру папок, показанную ниже:

/blog-api

├── src
│ ├── models
│ ├── controllers
│ ├── routes
│ └── index.ts

├── dist

├── node_modules

├── .bunrc
├── .env
├── package.json
└── tsconfig.json

3. Установка библиотек: Express.js, MongoDB и Typescript

После инициирования Bun можно установить все необходимые пакеты с помощью менеджера пакетов Bun, используя команды:

bun install express mongoose
bun install @types/express @types/mongoose typescript bun-types -d

Эти скрипты установят Express.js для сервера, MongoDB с помощью Mongoose для базы данных и Typescript для обеспечения чистоты и безопасности кода.

4. Создание базовой серверной среды

Внутри src/app.ts создайте сервер Express.js:

import express from 'express';

const app = express();

app.use(express.json());

app.get("/ping", (_, res) => {
res.send("🏓 pong!");
});

app.listen(3000, () => {
console.log('The magic happens on port 3000!');
});

Это базовое определение приложения Express.js.

Теперь убедимся в том, что API развертывается с помощью Bun. Для этого изменим скрипт npm start в файле package.json:

"scripts": {
"start": "bun run src/app.ts,"
"dev": "bun run src/app.ts --watch"
}

Запустить приложение можно с помощью простой команды:

bun dev

Режим --watch в Bun обеспечивает сверхбыстрый, нативный просмотр файлов, что резко контрастирует с Node.js, где для достижения аналогичной функциональности и удобства разработки требуются внешние инструменты вроде Nodemon.

Можете проверить, работает ли сервер, сделав GET-запрос к маршруту /ping, который ответит игривым “🏓 pong!”.

5. Проектирование схемы Mongoose

В папке src/models создадим Post.ts:

import { Schema, InferSchemaType, model } from 'mongoose';

const postSchema = new Schema(
{
title: { type: String, required: true },
content: { type: String, required: true },
author: String,
createdAt: { type: Date, default: Date. now },
}
);

export type Post = InferSchemaType<typeof postSchema>;
export const Post = model('Post', postSchema);

6. Контроллеры: определение бизнес-логики

Каждому маршруту нужна соответствующая функция контроллера.

Например, в папке controllers может быть файл postController.ts:

import { Request, Response} from 'express';

export const createPost = async (req: Request, res: Response) => {
try {
const {author, title, content} = req.body;
const post = new Post({author, title, content});
await post.save();
res.status(201).send(post);
} catch (error) {
res.status(400).send(error);
}
};

export const readPost = async (req: Request, res: Response) => {
try {
const posts = await Post.find({});
res.status(200).send(posts);
} catch (error) {
res.status(500).send(error);
}
};

export const readPosts = async (req: Request, res: Response) => {
try {
const { id } = req.params;
const post = await Post.findById(id);
if (!post) {
res.status(404).send();
}
res.status(200).send(post);
} catch (error) {
res.status(500).send(error);
}
};

export const updatePost = async (req: Request, res: Response) => {
try {
const { id } = req.params;
const post = await Post.findByIdAndUpdate(id,
req.body,
{
new: true,
runValidators: true
});
if (!post) {
res.status(404).send();
}
res.status(200).send(post);
} catch (error) {
res.status(400).send(error);
}
};

export const deletePost = async (req: Request, res: Response) => {
try {
const { id } = req.params;
const post = await Post.findByIdAndDelete(id);
if (!post) {
res.status(404).send("Post wasn't found");
}
res.status(200).send(post);
} catch (error) {
res.status(500).send(error);
}
};

Не забывайте об ответственной обработке ошибок. Заключите контроллеры в блоки try-catch и отправляйте клиенту информативные ответы. Впоследствии импортируйте эти функции в свои маршруты и включайте их по мере необходимости.

7. Добавление маршрутов к бизнес-функциям

Для API блога понадобятся следующие CRUD-маршруты.

  • Create a post (создать пост).
  • Read a post (прочитать пост).
  • Update a post (обновить пост).
  • Delete a post (удалить пост).

В каталоге src/routes создайте файл blogRoutes.ts со следующими параметрами:

import express from 'express';

const router = express.Router();

import { createPost, readPost, readPosts, updatePost, deletePost } from '../controllers/postController';

router.post('/post', createPost);
router.get('/posts', readPosts);
router.get('/post/:id', readPost);
router.put('/post/:id', updatePost);
router.delete('/post/:id', deletePost);

export default router;

8. Настройка MongoDB

Настало время реализовать подключение к базе данных. Добавьте следующее в src/config/db.ts:

import mongoose from 'mongoose';

export default function connectDB() {

const mongoURI = process.env.MONGODB_URI ?? 'mongodb://localhost:27017/mydatabase';

try {
mongoose.connect(mongoURI);
} catch (error) {
const castedError = error as Error;
console.error(castedError.message);
process.exit(1);
}

mongoose.connection.once("open", (_) => {
console.log(`Database connected`);
});

mongoose.connection.on("error", (err) => {
console.error(`Database connection error: ${err}`);
});

}

Теперь создайте файл .env в корне проекта и добавьте туда свои настройки, например MONGODB_URI.

Такая конфигурация обеспечивает доступ к переменным среды напрямую, без помощи утилит вроде dotenv, которые часто используются в проектах Node.js. Это достижимо, поскольку Bun по умолчанию поддерживает доступ к переменным среды через файлы .env.

9. Собираем все вместе

После подготовки моделей, маршрутов и контроллеров включите их в файл index.ts. После этой интеграции приложение будет готово к запуску.

import express from "express";
import postRoute from "./routes/postRoute"
import connectDB from "./config/db"


const app = express();
const port = process.env.APP_PORT || 8080;

// подключение к базе данных
connectDB();

// промежуточное ПО
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.get("/ping", (_, res) => {
res.send("🏓 pong!");
});

// маршруты
app.use('/api/post', postRoute);

app.listen(port, () => {
console.log(Listening on port: ${port} );
});

Теперь API на базе Bun готов.

Добавление функций мониторинга в приложения Express.js

Логирование запросов в Express

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

Для начала нужно установить Morgan. Это можно сделать через Bun:

bun add morgan
bun add @types/morgan -d

Необходимо добавить Morgan в качестве промежуточного ПО в приложение Express. Это делается с помощью app.use(). Morgan имеет различные предопределенные форматы логирования, такие как dev, tiny, combined, common и т. д. Пользователь также может создать собственный формат. Добавим пользовательский формат в файл index.ts.

app.use(morgan(':method :url :status :response-time ms'));

Morgan подключен к приложению Express и готов регистрировать все HTTP-запросы. Ведение лога очень удобно для контроля и устранения ошибок. Гибкость Morgan позволяет настроить его в соответствии с потребностями пользователя.

Валидация данных в Express

Express-validator  —  незаменимый инструмент валидации, гарантирующий чистоту и структурированность входящих данных в соответствии с установленными в приложении спецификациями. Это отличный промежуточный модуль, который упрощает валидацию и очистку данных запроса. Посмотрим, как реализовать Express-validator в проекте.

Прежде всего установите его в проект следующим образом:

bun add express-validator
bun add -d @types/express-validator

Затем в файле маршрута postRoute.ts нужно будет импортировать и использовать его так, как показано ниже:

const router = express.Router();

export const postValidator = [
body('title').notEmpty(),
body('content').notEmpty(),
body('author').notEmpty(),
];

router.post('/post',postValidator, createPost);
// другие маршруты

В приведенном выше коде видно, что еще до перехода к обработчику маршрута /post, Express-validator проверит поля имени пользователя, электронной почты и пароля на соответствие установленным критериям. Чтобы протестировать операцию валидации, можно сделать POST-запрос, не передав требуемый ключ author или передав пустую строку для одного из полей. Это вызовет ответ об ошибке, указывающий на отсутствие или пустоту поля.

-2

Для тех, кто хочет узнать больше, официальная документация по Express.js, MongoDB и Bun  —  отличная отправная точка. Но этой статьи должно быть достаточно для создания готового к производству приложения с помощью Bun.

Читайте также:

Читайте нас в Telegram, VK

Перевод статьи Tharaka Romesh: Building a Web API using Express.js, Bun and MongoDB