Setting the file. One moment.
Items · Wix Headless Templates · wix/skills · Skills Docs
ContentsBack to the top of the page This file
Number 16.204
Position 204 of 828
Type TypeScript
Size 9 KB
Lines 189 cms/rest/ items.ts
TypeScript · 189 lines · 9 KB
import
{ WixApiError, wixRequest }
from
"../../shared/rest/client.js"
;
13 import { imgRatio, imgSrc } from "../../shared/rest/media.js" ;
14 import {
15 DEFAULT_LIMIT,
16 DISTINCT_LIMIT,
17 countBody,
18 distinctBody,
19 patchModifications,
20 queryBody,
21 referencesBody,
22 restHasNext,
23 restWriteData,
24 toItem,
25 toPage,
26 toValues,
27 type Media,
28 type Raw,
29 } from "../app/wix/cms/items-core.js" ;
30 import type { CmsFilter, CmsItem, CmsPage, CmsQuery } from "../app/wix/cms/types.js" ;
31
32 const media : Media = { imgSrc, imgRatio };
33 const notFound = ( e : unknown ) : boolean => e instanceof WixApiError && e.status === 404 ;
34
35 /**
36 * Query one page of a collection. An empty result on a PUBLIC collection is a seed permissions bug
37 * (read must be "ANYONE"), not a query bug.
38 * POST /wix-data/v2/items/query { dataCollectionId, query: { filter, sort, paging: { limit, offset } }, includeReferences: [{ field }], returnTotalCount }
39 * → { dataItems: [{ id, dataCollectionId, data: { _id, …fields } }], pagingMetadata: { count, offset, total?, hasNext } }
40 */
41 export async function queryItems ( collectionId : string , query : CmsQuery = {}) : Promise < CmsPage > {
42 const { limit = DEFAULT_LIMIT , skip = 0 } = query;
43 const res = await wixRequest < Raw >( "/wix-data/v2/items/query" , { body: queryBody (collectionId, query) });
44 const items = ((res?.dataItems ?? []) as Raw []). map (( d ) => d.data ?? {});
45 return toPage (items, restHasNext (res?.pagingMetadata, skip, limit), res?.pagingMetadata?.total, media);
46 }
47
48 /**
49 * Fetch one item by `_id`. Null when not found (404 WDE0073). `includeReferences.field` is the
50 * request's key per the installed typings — confirm once on a live site that get honours it; if the
51 * referenced fields come back as ids, route through getItemBy("_id", …).
52 * GET /wix-data/v2/items/{id}?dataCollectionId=…&includeReferences.field=… → { dataItem: { data } }
53 */
54 export async function getItemById (
55 collectionId : string ,
56 itemId : string ,
57 { include = [] } : { include ?: string [] } = {},
58 ) : Promise < CmsItem | null > {
59 try {
60 const res = await wixRequest < Raw >( `/wix-data/v2/items/${ encodeURIComponent ( itemId ) }` , {
61 method: "GET" ,
62 query: { dataCollectionId: collectionId, ... (include. length ? { "includeReferences.field" : include } : {}) },
63 });
64 return res?.dataItem?.data ? toItem (res.dataItem.data, media) : null ;
65 } catch (e) {
66 if ( notFound (e)) return null ;
67 throw e;
68 }
69 }
70
71 /**
72 * Fetch the first item whose `field` equals `value` — slug-style routing (Wix Data has no native
73 * get-by-slug). Null when not found → render a not-found state, never invent an item.
74 */
75 export async function getItemBy (
76 collectionId : string ,
77 field : string ,
78 value : string | number ,
79 { include = [] } : { include ?: string [] } = {},
80 ) : Promise < CmsItem | null > {
81 const page = await queryItems (collectionId, { filters: [{ field, op: "eq" , value }], limit: 1 , include });
82 return page.items[ 0 ] ?? null ;
83 }
84
85 /**
86 * Count items matching the filters — no items transferred.
87 * POST /wix-data/v2/items/count { dataCollectionId, filter } → { totalCount }
88 */
89 export async function countItems ( collectionId : string , filters : CmsFilter [] = []) : Promise < number > {
90 const res = await wixRequest < Raw >( "/wix-data/v2/items/count" , { body: countBody (collectionId, filters) });
91 return typeof res?.totalCount === "number" ? res.totalCount : 0 ;
92 }
93
94 /**
95 * The distinct values a field holds across the collection (optionally within `filters`) — filter
96 * chips and selects from live data. Values normalized like item values; a reference field yields ids.
97 * POST /wix-data/v2/items/query-distinct-values { dataCollectionId, fieldName, filter, paging: { limit, offset } } → { distinctValues: [...] }
98 */
99 export async function distinctValues (
100 collectionId : string ,
101 field : string ,
102 { filters = [], limit = DISTINCT_LIMIT } : { filters ?: CmsFilter []; limit ?: number } = {},
103 ) : Promise < unknown []> {
104 const res = await wixRequest < Raw >( "/wix-data/v2/items/query-distinct-values" , { body: distinctBody (collectionId, field, filters, limit) });
105 return toValues ((res?.distinctValues ?? []) as unknown [], media);
106 }
107
108 /**
109 * Insert an item (visitor form / member submission). Never set `_owner` — Wix stamps it from the
110 * caller's identity. Date fields must be Date objects (the core spells them `{ $date }` on the wire;
111 * an ISO string is stored as text and breaks date queries). A MULTI_REFERENCE value inside `data` is
112 * DROPPED by the endpoint (200, no error) — pass those as `link: { field: [referencedIds] }` and they
113 * are linked right after the insert. The returned item predates the links.
114 * POST /wix-data/v2/items { dataCollectionId, dataItem: { data } } → { dataItem: { data } }
115 */
116 export async function insertItem (
117 collectionId : string ,
118 data : Record < string , unknown >,
119 { link = {} } : { link ?: Record < string , string []> } = {},
120 ) : Promise < CmsItem > {
121 const res = await wixRequest < Raw >( "/wix-data/v2/items" , { body: { dataCollectionId: collectionId, dataItem: { data: restWriteData (data) } } });
122 const item = toItem (res?.dataItem?.data ?? {}, media);
123 for ( const [ field , refIds ] of Object. entries (link)) await linkItems (collectionId, field, item._id, refIds);
124 return item;
125 }
126
127 /**
128 * REPLACE an item — fields omitted from `item` are WIPED (update does not patch). Spread the full
129 * item you hold and override; for an id + a few changed fields use patchItemFields. Wrap each date
130 * field back into a Date (`new Date(iso)`) before updating.
131 * PUT /wix-data/v2/items/{id} { dataCollectionId, dataItem: { id, data } } → { dataItem: { data } }
132 */
133 export async function updateItem ( collectionId : string , item : CmsItem ) : Promise < CmsItem > {
134 const res = await wixRequest < Raw >( `/wix-data/v2/items/${ encodeURIComponent ( item . _id ) }` , {
135 method: "PUT" ,
136 body: { dataCollectionId: collectionId, dataItem: { id: item._id, data: restWriteData (item) } },
137 });
138 return toItem (res?.dataItem?.data ?? {}, media);
139 }
140
141 /**
142 * Patch only the named fields — the safe partial change.
143 * PATCH /wix-data/v2/items/{id} { dataCollectionId, patch: { dataItemId, fieldModifications: [{ fieldPath, action: "SET_FIELD", setFieldOptions: { value } }] } }
144 */
145 export async function patchItemFields (
146 collectionId : string ,
147 itemId : string ,
148 fields : Record < string , unknown >,
149 ) : Promise < CmsItem > {
150 const res = await wixRequest < Raw >( `/wix-data/v2/items/${ encodeURIComponent ( itemId ) }` , {
151 method: "PATCH" ,
152 body: { dataCollectionId: collectionId, patch: { dataItemId: itemId, fieldModifications: patchModifications (fields) } },
153 });
154 return toItem (res?.dataItem?.data ?? {}, media);
155 }
156
157 /**
158 * Remove an item by `_id`. Irreversible. Returns the removed item (null if it didn't exist).
159 * DELETE /wix-data/v2/items/{id}?dataCollectionId=… → { dataItem: { data } }
160 */
161 export async function removeItem ( collectionId : string , itemId : string ) : Promise < CmsItem | null > {
162 try {
163 const res = await wixRequest < Raw >( `/wix-data/v2/items/${ encodeURIComponent ( itemId ) }` , { method: "DELETE" , query: { dataCollectionId: collectionId } });
164 return res?.dataItem?.data ? toItem (res.dataItem.data, media) : null ;
165 } catch (e) {
166 if ( notFound (e)) return null ;
167 throw e;
168 }
169 }
170
171 /**
172 * Add references to a MULTI_REFERENCE field of `itemId` — the only way a multi-reference is set
173 * (insert/update drop the value silently). Existing references stay; needs the collection's update
174 * permission. A no-op for an empty list.
175 * POST /wix-data/v2/bulk/items/insert-references { dataCollectionId, dataItemReferences: [{ referringItemFieldName, referringItemId, referencedItemId }] }
176 */
177 export async function linkItems ( collectionId : string , field : string , itemId : string , refIds : string []) : Promise < void > {
178 if ( ! refIds. length ) return ;
179 await wixRequest < Raw >( "/wix-data/v2/bulk/items/insert-references" , { body: referencesBody (collectionId, field, itemId, refIds) });
180 }
181
182 /**
183 * Remove references from a MULTI_REFERENCE field of `itemId`. Other references stay. A no-op for an empty list.
184 * POST /wix-data/v2/bulk/items/remove-references { dataCollectionId, dataItemReferences: [...] } (same body as the insert)
185 */
186 export async function unlinkItems ( collectionId : string , field : string , itemId : string , refIds : string []) : Promise < void > {
187 if ( ! refIds. length ) return ;
188 await wixRequest < Raw >( "/wix-data/v2/bulk/items/remove-references" , { body: referencesBody (collectionId, field, itemId, refIds) });
189 }