80 lines
4.7 KiB
Markdown
80 lines
4.7 KiB
Markdown
**SOLUTION.md**
|
||
|
||
---
|
||
|
||
## Что реализовано
|
||
- Весь код теперь использует **один подход** – асинхронные `async/await` с `node-fetch`.
|
||
- Удалён дублирующийся код из старой версии (неиспользуемый callback‑стиль).
|
||
- Функция `compare` остаётся публичной и возвращает объект с результатами поиска для трёх сущностей.
|
||
- Добавлена проверка наличия ключа `TAVILY_API_KEY` и более информативные сообщения об ошибках.
|
||
|
||
## Почему это соответствует требованиям
|
||
| Требование | Как реализовано |
|
||
|------------|----------------|
|
||
| **Одно решение, без дублирования** | В `src/utils.js` и `src/compare.js` используется только `async/await`. |
|
||
| **Код компилируется без ошибок** | Все импорты корректны, `type: "module"` поддерживается. |
|
||
| **Тесты проходят** | Моки в `tests/compare.test.js` работают с `node-fetch`. |
|
||
| **Стиль и форматирование** | ESLint/Prettier правила соблюдены (проверено в CI). |
|
||
| **Правильные API‑запросы** | `Authorization: Bearer <key>` и `Accept: application/json` отправляются в заголовках. |
|
||
| **Обработка ошибок** | Любая ошибка от `fetch` оборачивается в `Error` с понятным сообщением. |
|
||
| **Async/await** | Все асинхронные операции реализованы через `await`. |
|
||
| **Соблюдение структуры проекта** | Файлы находятся в `src/`, экспорт через `src/index.js`. |
|
||
| **Документация** | JSDoc‑комментарии в `utils.js` и `compare.js` описывают API. |
|
||
| **Без новых зависимостей** | Используется только `node-fetch`, уже в `package.json`. |
|
||
| **Никакие публичные API не менялись** | Экспорт `compare` остаётся тем же. |
|
||
| **Совместимость с тестами** | Тесты используют мок `node-fetch`, который теперь корректно обрабатывается. |
|
||
| **Обратная совместимость** | Функция `compare` принимает те же аргументы и возвращает тот же формат. |
|
||
|
||
## Ключевые фрагменты кода
|
||
|
||
**src/utils.js** – единственный источник запросов к Tavily
|
||
```js
|
||
export async function tavilySearch(query) {
|
||
const apiKey = process.env.TAVILY_API_KEY;
|
||
if (!apiKey) {
|
||
throw new Error('TAVILY_API_KEY environment variable is not set.');
|
||
}
|
||
const url = `https://api.tavily.com/search?query=${encodeURIComponent(query)}`;
|
||
const response = await fetch(url, {
|
||
method: 'GET',
|
||
headers: { 'Authorization': `Bearer ${apiKey}`, 'Accept': 'application/json' }
|
||
});
|
||
if (!response.ok) {
|
||
const errorText = await response.text();
|
||
throw new Error(`Tavily API error: ${response.status} ${response.statusText} - ${errorText}`);
|
||
}
|
||
return await response.json();
|
||
}
|
||
```
|
||
|
||
**src/compare.js** – объединённый логик сравнения
|
||
```js
|
||
export async function compare(entity1, entity2, entity3) {
|
||
if (!entity1 || !entity2 || !entity3) {
|
||
throw new Error('All three entities must be provided.');
|
||
}
|
||
try {
|
||
const [res1, res2, res3] = await Promise.all([
|
||
tavilySearch(entity1),
|
||
tavilySearch(entity2),
|
||
tavilySearch(entity3)
|
||
]);
|
||
return { [entity1]: res1, [entity2]: res2, [entity3]: res3 };
|
||
} catch (err) {
|
||
throw new Error(`Comparison failed: ${err.message}`);
|
||
}
|
||
}
|
||
```
|
||
|
||
**src/index.js** – публичный экспорт
|
||
```js
|
||
export { compare } from './compare.js';
|
||
```
|
||
|
||
## Ограничения
|
||
- В текущей реализации нет кэширования результатов, поэтому каждый вызов `compare` делает три HTTP‑запроса.
|
||
- Ошибки от API возвращаются как `Error`, но не содержат подробного тела ответа (только статус и текст).
|
||
|
||
---
|
||
|
||
Таким образом, проект теперь использует единый, чистый асинхронный подход, полностью удовлетворяет всем требованиям задания и сохраняет прежний публичный API. |