Поиск в коде (SDK)
Встройте поиск в приложение с помощью JavaScript.
Если вам нужен кастомный поиск (не виджет), используйте SDK.
Что это?
SDK — это набор функций на JavaScript для поиска. Вы вызываете функции и получаете результаты.
Это нужно, если:
- Вам нужен кастомный дизайн поиска
- Вы делаете мобильное приложение
- Вы интегрируете в свою систему
Установка
npm install @aacsearch/search-clientИли если у вас в package.json:
"@aacsearch/search-client": "latest"Простой поиск
import { SearchClient } from '@aacsearch/search-client';
const client = new SearchClient({
apiKey: 'ss_search_xxx',
baseUrl: 'https://api.aacsearch.com'
});
// Выполнить поиск
const results = await client.search({
indexSlug: 'товары',
q: 'красная рубашка',
limit: 10
});
console.log(results.documents); // массив товаров
console.log(results.total); // всего товаров найденоReact компонент
import { useSearch } from '@aacsearch/search-client/react';
export function SearchComponent() {
const [query, setQuery] = useState('');
const { results, loading } = useSearch({
apiKey: 'ss_search_xxx',
indexSlug: 'товары',
query
});
return (
<div>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Найти товар..."
/>
{loading && <p>Загрузка...</p>}
<div>
{results.map(doc => (
<div key={doc.id}>
<h3>{doc.title}</h3>
<p>{doc.description}</p>
<p>₽ {doc.price}</p>
</div>
))}
</div>
</div>
);
}С фильтрами
const results = await client.search({
indexSlug: 'товары',
q: 'рубашка',
filters: {
price: { min: 1000, max: 3000 },
brand: 'Nike'
}
});Сортировка
const results = await client.search({
indexSlug: 'товары',
q: 'рубашка',
sort: 'price_asc' // или 'price_desc', 'relevance'
});Автозаполнение (подсказки)
const suggestions = await client.suggest({
indexSlug: 'товары',
q: 'кра', // пользователь печатает "кра"
limit: 5
});
// Возвращает:
// ['красная рубашка', 'краска', 'крайние сроки']Обработка ошибок
try {
const results = await client.search({
indexSlug: 'товары',
q: 'рубашка'
});
} catch (error) {
if (error.code === 'auth_failed') {
console.log('Ключ неверный или истёк');
} else if (error.code === 'rate_limited') {
console.log('Много запросов. Подождите 60 секунд');
} else {
console.log('Ошибка:', error.message);
}
}Аналитика
SDK автоматически отправляет статистику:
- Какие товары кликают
- Какие запросы не дали результатов
- Сколько времени занял поиск
Всё это видно в панели управления.
Документация
Полную документацию смотрите в GitHub репозитории: https://github.com/aacsearch/search-client
Там же примеры для:
- Vue.js
- Angular
- Svelte
- Next.js
- Python
- Java
Установка
SDK является пакетом воркспейса. В внешних проектах (после публикации):
npm install @aacsearch/search-client
# или: yarn add @aacsearch/search-clientВнутри монорепозитория:
{
"dependencies": {
"@repo/search-client": "workspace:*"
}
}Инициализация клиента
import { AacSearchClient } from "@repo/search-client";
const client = new AacSearchClient({
baseUrl: "https://your-app.com", // ваш эндпоинт AACsearch
apiKey: "ss_search_your_key", // ключ только для поиска
indexSlug: "products", // индекс по умолчанию
});Базовый поиск
const results = await client.search({
q: "wireless headphones",
queryBy: "title,description,brand",
page: 1,
perPage: 20,
});
// results.hits: массив совпадающих документов
// results.found: общее количество
// results.facetCounts: значения фасетов (если запрошены)Поиск с фильтрами
const results = await client.search({
q: "headphones",
queryBy: "title,brand",
filterBy: "availability:=in_stock && price:<200",
sortBy: "price:asc",
facetBy: "brand,categories",
page: 1,
perPage: 20,
});Синтаксис фильтров соответствует синтаксису фильтров AACSearch.
Мульти-поиск
Мульти-поиск выполняет несколько запросов за один HTTP-вызов. Полезен для автодополнения (один запрос на тип подсказки) и федеративного поиска по различным наборам результатов.
const [productResults, categoryResults] = await client.multiSearch([
{
indexSlug: "products",
q: "shoes",
queryBy: "title,brand",
perPage: 5,
},
{
indexSlug: "categories",
q: "shoes",
queryBy: "name",
perPage: 3,
},
]);Использование ограниченных токенов
Для ограничений на уровне пользователя (например, показывать только товары в наличии), генерируйте ограниченный токен на стороне сервера и передавайте его клиенту:
// Сервер: генерация ограниченного токена (например, в Server Action или API route Next.js)
const scopedToken = await orpc.search.createScopedToken.call({
organizationId: session.organizationId,
indexSlug: "products",
scopedFilter: "availability:=in_stock",
expiresInSeconds: 3600,
});
// Клиент: используйте ограниченный токен как API-ключ
const client = new AacSearchClient({
baseUrl: process.env.NEXT_PUBLIC_API_URL,
apiKey: scopedToken,
indexSlug: "products",
});Ограниченный фильтр объединяется через AND с любыми фильтрами клиента. Он не может быть удалён вызывающей стороной.
Шаблон автодополнения
Для отзывчивого поиска по мере ввода текста используйте дебаунсинг запросов и мульти-поиск:
import { useDeferredValue, useEffect, useState } from "react";
function useSearch(query: string) {
const deferredQuery = useDeferredValue(query);
const [results, setResults] = useState(null);
useEffect(() => {
if (!deferredQuery.trim()) return;
client
.search({
q: deferredQuery,
queryBy: "title,sku",
perPage: 5,
highlightFields: "title",
})
.then(setResults);
}, [deferredQuery]);
return results;
}Обработка ошибок
SDK выбрасывает типизированные ошибки из каталога ошибок:
import { AacSearchError } from "@repo/search-client";
try {
const results = await client.search({ q: "test" });
} catch (err) {
if (err instanceof AacSearchError) {
switch (err.code) {
case "unauthorized": // недействительный или истёкший ключ
case "quota_exceeded": // достигнут лимит плана
case "rate_limit": // слишком много запросов
case "search_failed": // ошибка AACSearch на стороне сервера
case "index_not_found": // неверный indexSlug
}
}
}Сырые сообщения об ошибках AACSearch никогда не пересылаются клиентам — они сопоставляются с типизированными кодами на стороне сервера.
Интеграции с фреймворками
Next.js App Router
// app/search/page.tsx — Server Component
import { AacSearchClient } from "@repo/search-client";
const client = new AacSearchClient({
baseUrl: process.env.NEXT_PUBLIC_API_URL!,
apiKey: process.env.SEARCH_API_KEY!, // ключ только для поиска из переменной окружения
indexSlug: "products",
});
export default async function SearchPage({ searchParams }: { searchParams: { q?: string } }) {
const results = await client.search({ q: searchParams.q ?? "" });
return <ResultsList results={results} />;
}Клиентский React-компонент
"use client";
import { useQuery } from "@tanstack/react-query";
function SearchResults({ query }: { query: string }) {
const { data, isLoading } = useQuery({
queryKey: ["search", query],
queryFn: () => client.search({ q: query, perPage: 20 }),
enabled: query.length > 1,
});
if (isLoading) return <Skeleton />;
return <ResultsList results={data} />;
}