Files
dashback/docs/api/routes/article/search.md
2026-07-19 17:09:14 +02:00

121 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# `GET /article/search`
Protected. Requires a valid session cookie (`credentials: 'include'`).
Fuzzy article search. Use this to build a search box / result list with category facets.
## Query parameters
| Param | Required | Description |
|-------|----------|-------------|
| `target` | yes | Search string. Split on spaces; each word must match (AND). Each word is matched with `LIKE %word%` against EAN, supplier article number, name, article number, or barcode. |
| `filter` | no | Comma-separated category IDs. Omit or leave empty to search all categories. See [Category filter](#category-filter). |
| `offset` | no | Pagination offset (default `0`). |
| `maxCount` | no | Page size (default `10`). |
## Search behaviour
- Multiple spaces are collapsed to one.
- Example: `target=bizz allmix` → both `bizz` **and** `allmix` must match somewhere on the article.
- By default only **active** articles (`cAktiv = 'Y'`) are returned.
- Without a category filter, at most **2000** rows are returned (before pagination).
- Results are ordered by product name ascending.
- `length` is the total match count (before `offset` / `maxCount`); `recordset` is the current page.
## Category filter
| `filter` value | Effect |
|----------------|--------|
| *(omitted or empty)* | All categories; `TOP 2000` |
| `751` | Include inactive articles (no `cAktiv = 'Y'` restriction). Still uses category branch logic if other IDs are present. |
| `16` or `16,39` | Restrict to articles in those categories (OR). No row limit. |
Pass category IDs as a comma-separated list: `filter=16,39`.
Whenever `filter` is present, **`categories` always includes every id from `filter`**, even when `length` is `0` or a filtered id has no hits. Those entries use master-data `name` / `parent` and may have `count: 0`. Other facet categories with hits are still returned as usual.
## Response `200`
```json
{
"length": 42,
"recordset": [
{
"categories": "16,39",
"available": 0,
"id": 49,
"stock": null,
"sku": "42000044",
"name": "BioBizz AllMix Peat Free 20L",
"price": 13.5,
"tax": 19
}
],
"categories": {
"16": { "name": "Dünger", "count": 42, "parent": 0 },
"39": { "name": "Erde", "count": 18, "parent": 16 }
}
}
```
Empty result with an active filter still returns the applied category:
```json
{
"length": 0,
"recordset": [],
"categories": {
"16": { "name": "Dünger", "count": 0, "parent": 0 }
}
}
```
### Top-level fields
| Field | Type | Notes |
|-------|------|-------|
| `length` | number | Total matching articles (unpaginated). |
| `recordset` | array | Current page of shaped article rows. |
| `categories` | object | Map keyed by category id (string). Facet counts for the current search (+ filters). |
### `recordset[]` fields
| Field | Type | Notes |
|-------|------|-------|
| `id` | number | Internal article ID (`kArtikel`) |
| `sku` | string | Article number — pass to [`GET /article/get`](get.md) |
| `name` | string | Display name |
| `stock` | number \| null | Stock in warehouse 1 |
| `available` | number \| null | Available stock |
| `price` | number \| null | Brutto VK, rounded to 1 decimal |
| `tax` | number \| null | Tax rate percent for the article’s Steuerklasse |
| `categories` | string \| null | Comma-separated category IDs on the article |
### `categories` map entries
| Field | Type | Notes |
|-------|------|-------|
| `name` | string \| null | Display label from category master data |
| `count` | number | Hit count under the current search (+ other filters); may be `0` |
| `parent` | number \| null | Parent category id, or `0` if root |
Counts include parent categories rolled up from each article’s category path. Use for category sidebar / facet UI. Resolve labels via `categories[id].name` (skip ids without a name).
## Errors
| Status | Body |
|--------|------|
| 400 | `{ "error": "Query parameter \"target\" is required" }` |
| 401 | `{ "error": "Unauthorized" }` |
| 500 | `{ "error": "..." }` |
## Example
```js
const res = await fetch(
'http://localhost:4208/api/article/search?target=bizz%20allmix&filter=16&maxCount=10',
{ credentials: 'include' }
);
const { categories, length, recordset } = await res.json();
```