@minipim/sdk 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -0
- package/dist/openapi.d.cts +65 -5
- package/dist/openapi.d.ts +65 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -130,6 +130,43 @@ const all = await collectAll<Product>(pim, '/v1/products');
|
|
|
130
130
|
|
|
131
131
|
Endpoints that return a **plain array** instead of the envelope (`/v1/categories` without `?limit=`, `/v1/attributes`, `/v1/products/{id}/variants`) are handled too (v0.3.0+): the array is treated as the one-and-only page, so `collectAll` works uniformly across every list endpoint.
|
|
132
132
|
|
|
133
|
+
## Listing by category, and by price (v0.5.0+)
|
|
134
|
+
|
|
135
|
+
Two things storefronts almost always need, and previously had to do in memory.
|
|
136
|
+
|
|
137
|
+
**Category subtrees.** `categoryId` on its own is **self-only** — it matches products filed directly against that category. Catalogs commonly assign products to leaf categories, so a parent category can legitimately return an empty page. Add `includeDescendants` for the whole subtree:
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
// Everything anywhere under "Backdrops", in ONE paginated query.
|
|
141
|
+
const { data } = await pim.GET('/v1/products', {
|
|
142
|
+
query: { categoryId, includeDescendants: true, limit: 50 },
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Don't fetch `/v1/categories`, resolve descendants yourself and issue one request per id — this is a single round trip and it paginates as one result set.
|
|
147
|
+
|
|
148
|
+
**Sorting and filtering by price.** There is no `sortBy: 'price'`, because a catalog's price attribute code is its own data (`price`, `msrp`, `list_price`, …). Name it:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
// Cheapest first
|
|
152
|
+
await pim.GET('/v1/products', {
|
|
153
|
+
query: { sortBy: 'attribute', sortAttribute: 'price', sortDir: 'asc' },
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// $10.00–$50.00 — money bounds are INTEGER CENTS
|
|
157
|
+
await pim.GET('/v1/products', {
|
|
158
|
+
query: { filterAttribute: 'price', filterMin: 1000, filterMax: 5000 },
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
- Works on `money`, `number` and `decimal` attributes. `measurement` is refused — its values carry a unit, so ordering raw amounts would rank 5 g above 2 kg.
|
|
163
|
+
- For `money`, bounds and ordering use `amount_cents`. **`filterMin: 1000` is $10.00.** No currency conversion — mixed-currency catalogs compare by number.
|
|
164
|
+
- The value read is the one at the **default scope** (no locale, no channel). Products with no value sort **last in both directions** and are excluded by either bound: no price, not a price of zero.
|
|
165
|
+
- An unknown code, or one of a non-orderable type, is a **422 naming the problem**. It never degrades to name ordering, so you can't get a plausible page that isn't sorted the way you asked.
|
|
166
|
+
- `sortAttribute` and `filterAttribute` are independent; set both for "cheapest first, within a budget".
|
|
167
|
+
|
|
168
|
+
Needs API **0.9.0+**. Check `GET /healthz`.
|
|
169
|
+
|
|
133
170
|
## Attribute helpers
|
|
134
171
|
|
|
135
172
|
Attribute values are `unknown` and keyed by `(locale, channel)`. List responses return the raw `{ code: [{ locale, channel, value }] }` shape (only product *detail* with `?locale=&channel=` returns a flat `resolvedAttributes`). The SDK ships the flatten + coercion helpers so you don't reimplement them:
|
package/dist/openapi.d.cts
CHANGED
|
@@ -1468,6 +1468,51 @@ interface paths {
|
|
|
1468
1468
|
* Iterate by reading `hasMore`. Pass `?withTotal=true` to add a `total`
|
|
1469
1469
|
* field (costs one COUNT query). Default `limit` is 50, **max 200**.
|
|
1470
1470
|
* Reconcile after downtime with `?updatedSince=<iso8601>`.
|
|
1471
|
+
*
|
|
1472
|
+
* ### Filtering by category
|
|
1473
|
+
*
|
|
1474
|
+
* `?categoryId=` is **self-only**: it matches products assigned directly to
|
|
1475
|
+
* that category and nothing filed beneath it. Many catalogs assign products
|
|
1476
|
+
* only to leaf categories, so a self-only filter on a parent legitimately
|
|
1477
|
+
* returns zero rows.
|
|
1478
|
+
*
|
|
1479
|
+
* Add `?includeDescendants=true` to match the category **and its entire
|
|
1480
|
+
* subtree**, resolved server-side in a single query:
|
|
1481
|
+
*
|
|
1482
|
+
* ```bash
|
|
1483
|
+
* # Every product anywhere under "Backdrops", paginated normally
|
|
1484
|
+
* curl 'https://api.minipim.com/v1/products?categoryId=8d2a1f3c-...&includeDescendants=true&limit=50'
|
|
1485
|
+
* ```
|
|
1486
|
+
*
|
|
1487
|
+
* Prefer this over fetching the tree and issuing one request per descendant —
|
|
1488
|
+
* it is one round trip, and it paginates as a single result set.
|
|
1489
|
+
*
|
|
1490
|
+
* ### Sorting and filtering by price (or any numeric attribute)
|
|
1491
|
+
*
|
|
1492
|
+
* Price is not a column — it is an attribute, and its **code is per-organization
|
|
1493
|
+
* data**, so there is no `sortBy=price`. Name the attribute instead:
|
|
1494
|
+
*
|
|
1495
|
+
* ```bash
|
|
1496
|
+
* # Cheapest first
|
|
1497
|
+
* curl '.../v1/products?sortBy=attribute&sortAttribute=price&sortDir=asc'
|
|
1498
|
+
*
|
|
1499
|
+
* # Between $10.00 and $50.00 — bounds are INTEGER CENTS for money attributes
|
|
1500
|
+
* curl '.../v1/products?filterAttribute=price&filterMin=1000&filterMax=5000'
|
|
1501
|
+
* ```
|
|
1502
|
+
*
|
|
1503
|
+
* - Works on `money`, `number` and `decimal` attributes. `measurement` is
|
|
1504
|
+
* refused: its values carry a unit, so ordering raw amounts would rank 5 g
|
|
1505
|
+
* above 2 kg.
|
|
1506
|
+
* - For `money`, bounds and ordering use `amount_cents`. **`filterMin=1000`
|
|
1507
|
+
* is $10.00.** No currency conversion happens — mixed-currency catalogs are
|
|
1508
|
+
* compared by number, so scope the query to one currency if that matters.
|
|
1509
|
+
* - The value read is the one at the **default scope** (no locale, no channel).
|
|
1510
|
+
* A product with no default-scope value sorts **last** in both directions and
|
|
1511
|
+
* is excluded by either bound — it has no price, rather than a price of zero.
|
|
1512
|
+
* - Unknown code, or a code of the wrong type, is a **422** naming the problem.
|
|
1513
|
+
* It never silently degrades to `name` ordering.
|
|
1514
|
+
* - `sortAttribute` and `filterAttribute` are independent; set both to the
|
|
1515
|
+
* same code for the usual "cheapest first, within a budget" query.
|
|
1471
1516
|
*/
|
|
1472
1517
|
get: {
|
|
1473
1518
|
parameters: {
|
|
@@ -1476,15 +1521,20 @@ interface paths {
|
|
|
1476
1521
|
q?: string;
|
|
1477
1522
|
familyId?: string;
|
|
1478
1523
|
categoryId?: string;
|
|
1524
|
+
includeDescendants?: boolean | ("true" | "false" | "1" | "0");
|
|
1479
1525
|
brand?: string;
|
|
1480
1526
|
tag?: string | string[];
|
|
1481
1527
|
connectorId?: string;
|
|
1482
1528
|
updatedSince?: string;
|
|
1483
|
-
sortBy?: "name" | "slug" | "status" | "updatedAt" | "createdAt" | "relevance";
|
|
1529
|
+
sortBy?: "name" | "slug" | "status" | "updatedAt" | "createdAt" | "relevance" | "attribute";
|
|
1530
|
+
sortAttribute?: string;
|
|
1531
|
+
filterAttribute?: string;
|
|
1532
|
+
filterMin?: number;
|
|
1533
|
+
filterMax?: number;
|
|
1484
1534
|
sortDir?: "asc" | "desc";
|
|
1485
1535
|
limit?: number;
|
|
1486
1536
|
offset?: number;
|
|
1487
|
-
withTotal?: boolean;
|
|
1537
|
+
withTotal?: boolean | ("true" | "false" | "1" | "0");
|
|
1488
1538
|
locale?: string;
|
|
1489
1539
|
channel?: string;
|
|
1490
1540
|
};
|
|
@@ -1662,11 +1712,16 @@ interface paths {
|
|
|
1662
1712
|
q?: string;
|
|
1663
1713
|
familyId?: string;
|
|
1664
1714
|
categoryId?: string;
|
|
1715
|
+
includeDescendants?: boolean | ("true" | "false" | "1" | "0");
|
|
1665
1716
|
brand?: string;
|
|
1666
1717
|
tag?: string | string[];
|
|
1667
1718
|
connectorId?: string;
|
|
1668
1719
|
updatedSince?: string;
|
|
1669
|
-
sortBy?: "name" | "slug" | "status" | "updatedAt" | "createdAt" | "relevance";
|
|
1720
|
+
sortBy?: "name" | "slug" | "status" | "updatedAt" | "createdAt" | "relevance" | "attribute";
|
|
1721
|
+
sortAttribute?: string;
|
|
1722
|
+
filterAttribute?: string;
|
|
1723
|
+
filterMin?: number;
|
|
1724
|
+
filterMax?: number;
|
|
1670
1725
|
sortDir?: "asc" | "desc";
|
|
1671
1726
|
locale?: string;
|
|
1672
1727
|
channel?: string;
|
|
@@ -3979,8 +4034,13 @@ interface paths {
|
|
|
3979
4034
|
* ```
|
|
3980
4035
|
*
|
|
3981
4036
|
* To get a single category's full ancestor path, walk `parentId` upwards
|
|
3982
|
-
* client-side
|
|
3983
|
-
*
|
|
4037
|
+
* client-side — this endpoint returns the whole tree in one call, so no extra
|
|
4038
|
+
* requests are needed. (`GET /v1/categories/{id}` returns the same row shape
|
|
4039
|
+
* for one category; it does **not** resolve an ancestor path.)
|
|
4040
|
+
*
|
|
4041
|
+
* To list the products under a category *including* its subtree, use
|
|
4042
|
+
* `GET /v1/products?categoryId=<id>&includeDescendants=true` rather than
|
|
4043
|
+
* resolving descendants here and issuing one request per id.
|
|
3984
4044
|
*
|
|
3985
4045
|
* Returns the full tree by default. `?limit=` / `?offset=` are supported
|
|
3986
4046
|
* for large taxonomies (ordered by `position`); omit them to get everything.
|
package/dist/openapi.d.ts
CHANGED
|
@@ -1468,6 +1468,51 @@ interface paths {
|
|
|
1468
1468
|
* Iterate by reading `hasMore`. Pass `?withTotal=true` to add a `total`
|
|
1469
1469
|
* field (costs one COUNT query). Default `limit` is 50, **max 200**.
|
|
1470
1470
|
* Reconcile after downtime with `?updatedSince=<iso8601>`.
|
|
1471
|
+
*
|
|
1472
|
+
* ### Filtering by category
|
|
1473
|
+
*
|
|
1474
|
+
* `?categoryId=` is **self-only**: it matches products assigned directly to
|
|
1475
|
+
* that category and nothing filed beneath it. Many catalogs assign products
|
|
1476
|
+
* only to leaf categories, so a self-only filter on a parent legitimately
|
|
1477
|
+
* returns zero rows.
|
|
1478
|
+
*
|
|
1479
|
+
* Add `?includeDescendants=true` to match the category **and its entire
|
|
1480
|
+
* subtree**, resolved server-side in a single query:
|
|
1481
|
+
*
|
|
1482
|
+
* ```bash
|
|
1483
|
+
* # Every product anywhere under "Backdrops", paginated normally
|
|
1484
|
+
* curl 'https://api.minipim.com/v1/products?categoryId=8d2a1f3c-...&includeDescendants=true&limit=50'
|
|
1485
|
+
* ```
|
|
1486
|
+
*
|
|
1487
|
+
* Prefer this over fetching the tree and issuing one request per descendant —
|
|
1488
|
+
* it is one round trip, and it paginates as a single result set.
|
|
1489
|
+
*
|
|
1490
|
+
* ### Sorting and filtering by price (or any numeric attribute)
|
|
1491
|
+
*
|
|
1492
|
+
* Price is not a column — it is an attribute, and its **code is per-organization
|
|
1493
|
+
* data**, so there is no `sortBy=price`. Name the attribute instead:
|
|
1494
|
+
*
|
|
1495
|
+
* ```bash
|
|
1496
|
+
* # Cheapest first
|
|
1497
|
+
* curl '.../v1/products?sortBy=attribute&sortAttribute=price&sortDir=asc'
|
|
1498
|
+
*
|
|
1499
|
+
* # Between $10.00 and $50.00 — bounds are INTEGER CENTS for money attributes
|
|
1500
|
+
* curl '.../v1/products?filterAttribute=price&filterMin=1000&filterMax=5000'
|
|
1501
|
+
* ```
|
|
1502
|
+
*
|
|
1503
|
+
* - Works on `money`, `number` and `decimal` attributes. `measurement` is
|
|
1504
|
+
* refused: its values carry a unit, so ordering raw amounts would rank 5 g
|
|
1505
|
+
* above 2 kg.
|
|
1506
|
+
* - For `money`, bounds and ordering use `amount_cents`. **`filterMin=1000`
|
|
1507
|
+
* is $10.00.** No currency conversion happens — mixed-currency catalogs are
|
|
1508
|
+
* compared by number, so scope the query to one currency if that matters.
|
|
1509
|
+
* - The value read is the one at the **default scope** (no locale, no channel).
|
|
1510
|
+
* A product with no default-scope value sorts **last** in both directions and
|
|
1511
|
+
* is excluded by either bound — it has no price, rather than a price of zero.
|
|
1512
|
+
* - Unknown code, or a code of the wrong type, is a **422** naming the problem.
|
|
1513
|
+
* It never silently degrades to `name` ordering.
|
|
1514
|
+
* - `sortAttribute` and `filterAttribute` are independent; set both to the
|
|
1515
|
+
* same code for the usual "cheapest first, within a budget" query.
|
|
1471
1516
|
*/
|
|
1472
1517
|
get: {
|
|
1473
1518
|
parameters: {
|
|
@@ -1476,15 +1521,20 @@ interface paths {
|
|
|
1476
1521
|
q?: string;
|
|
1477
1522
|
familyId?: string;
|
|
1478
1523
|
categoryId?: string;
|
|
1524
|
+
includeDescendants?: boolean | ("true" | "false" | "1" | "0");
|
|
1479
1525
|
brand?: string;
|
|
1480
1526
|
tag?: string | string[];
|
|
1481
1527
|
connectorId?: string;
|
|
1482
1528
|
updatedSince?: string;
|
|
1483
|
-
sortBy?: "name" | "slug" | "status" | "updatedAt" | "createdAt" | "relevance";
|
|
1529
|
+
sortBy?: "name" | "slug" | "status" | "updatedAt" | "createdAt" | "relevance" | "attribute";
|
|
1530
|
+
sortAttribute?: string;
|
|
1531
|
+
filterAttribute?: string;
|
|
1532
|
+
filterMin?: number;
|
|
1533
|
+
filterMax?: number;
|
|
1484
1534
|
sortDir?: "asc" | "desc";
|
|
1485
1535
|
limit?: number;
|
|
1486
1536
|
offset?: number;
|
|
1487
|
-
withTotal?: boolean;
|
|
1537
|
+
withTotal?: boolean | ("true" | "false" | "1" | "0");
|
|
1488
1538
|
locale?: string;
|
|
1489
1539
|
channel?: string;
|
|
1490
1540
|
};
|
|
@@ -1662,11 +1712,16 @@ interface paths {
|
|
|
1662
1712
|
q?: string;
|
|
1663
1713
|
familyId?: string;
|
|
1664
1714
|
categoryId?: string;
|
|
1715
|
+
includeDescendants?: boolean | ("true" | "false" | "1" | "0");
|
|
1665
1716
|
brand?: string;
|
|
1666
1717
|
tag?: string | string[];
|
|
1667
1718
|
connectorId?: string;
|
|
1668
1719
|
updatedSince?: string;
|
|
1669
|
-
sortBy?: "name" | "slug" | "status" | "updatedAt" | "createdAt" | "relevance";
|
|
1720
|
+
sortBy?: "name" | "slug" | "status" | "updatedAt" | "createdAt" | "relevance" | "attribute";
|
|
1721
|
+
sortAttribute?: string;
|
|
1722
|
+
filterAttribute?: string;
|
|
1723
|
+
filterMin?: number;
|
|
1724
|
+
filterMax?: number;
|
|
1670
1725
|
sortDir?: "asc" | "desc";
|
|
1671
1726
|
locale?: string;
|
|
1672
1727
|
channel?: string;
|
|
@@ -3979,8 +4034,13 @@ interface paths {
|
|
|
3979
4034
|
* ```
|
|
3980
4035
|
*
|
|
3981
4036
|
* To get a single category's full ancestor path, walk `parentId` upwards
|
|
3982
|
-
* client-side
|
|
3983
|
-
*
|
|
4037
|
+
* client-side — this endpoint returns the whole tree in one call, so no extra
|
|
4038
|
+
* requests are needed. (`GET /v1/categories/{id}` returns the same row shape
|
|
4039
|
+
* for one category; it does **not** resolve an ancestor path.)
|
|
4040
|
+
*
|
|
4041
|
+
* To list the products under a category *including* its subtree, use
|
|
4042
|
+
* `GET /v1/products?categoryId=<id>&includeDescendants=true` rather than
|
|
4043
|
+
* resolving descendants here and issuing one request per id.
|
|
3984
4044
|
*
|
|
3985
4045
|
* Returns the full tree by default. `?limit=` / `?offset=` are supported
|
|
3986
4046
|
* for large taxonomies (ordered by `position`); omit them to get everything.
|