@data-client/rest 0.1.0 → 0.2.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.
Files changed (65) hide show
  1. package/dist/index.js +10 -14
  2. package/dist/index.umd.min.js +1 -1
  3. package/legacy/OptionsToFunction.js +1 -1
  4. package/legacy/RestEndpoint.js +5 -5
  5. package/legacy/createResource.js +8 -10
  6. package/legacy/index.js +2 -1
  7. package/legacy/next/index.js +4 -4
  8. package/legacy/resourceTypes.js +2 -0
  9. package/lib/OptionsToFunction.d.ts.map +1 -1
  10. package/lib/OptionsToFunction.js +1 -1
  11. package/lib/RestEndpoint.d.ts +29 -35
  12. package/lib/RestEndpoint.js +5 -5
  13. package/lib/createResource.d.ts +51 -31
  14. package/lib/createResource.d.ts.map +1 -1
  15. package/lib/createResource.js +7 -11
  16. package/lib/index.d.ts +3 -1
  17. package/lib/index.d.ts.map +1 -1
  18. package/lib/index.js +2 -1
  19. package/lib/next/index.d.ts +5 -5
  20. package/lib/next/index.d.ts.map +1 -1
  21. package/lib/next/index.js +4 -4
  22. package/lib/resourceTypes.d.ts.map +1 -0
  23. package/lib/resourceTypes.js +2 -0
  24. package/package.json +3 -3
  25. package/src/OptionsToFunction.ts +0 -1
  26. package/src/RestEndpoint.d.ts +29 -35
  27. package/src/RestEndpoint.js +4 -4
  28. package/src/__tests__/RestEndpoint.ts +38 -9
  29. package/src/__tests__/createResource.test.ts +3 -4
  30. package/src/__tests__/hookifyResource.ts +7 -3
  31. package/src/__tests__/types.test.ts +332 -212
  32. package/src/createResource.ts +81 -60
  33. package/src/index.ts +2 -2
  34. package/src/next/index.ts +5 -5
  35. package/ts4.0/RestEndpoint.d.ts +18 -32
  36. package/ts4.0/createResource.d.ts +59 -31
  37. package/ts4.0/index.d.ts +3 -1
  38. package/ts4.0/next/index.d.ts +5 -5
  39. package/legacy/next/OptionsToFunction.js +0 -2
  40. package/legacy/next/RestEndpoint.js +0 -225
  41. package/legacy/next/createResource.js +0 -86
  42. package/legacy/next/resourceTypes.js +0 -2
  43. package/lib/next/OptionsToFunction.d.ts +0 -7
  44. package/lib/next/OptionsToFunction.d.ts.map +0 -1
  45. package/lib/next/OptionsToFunction.js +0 -2
  46. package/lib/next/RestEndpoint.d.ts +0 -542
  47. package/lib/next/RestEndpoint.js +0 -229
  48. package/lib/next/createResource.d.ts +0 -86
  49. package/lib/next/createResource.d.ts.map +0 -1
  50. package/lib/next/createResource.js +0 -100
  51. package/lib/next/resourceTypes.d.ts.map +0 -1
  52. package/lib/next/resourceTypes.js +0 -2
  53. package/src/next/OptionsToFunction.ts +0 -41
  54. package/src/next/RestEndpoint.d.ts +0 -542
  55. package/src/next/RestEndpoint.js +0 -262
  56. package/src/next/__tests__/RestEndpoint.ts +0 -1333
  57. package/src/next/__tests__/__snapshots__/RestEndpoint.ts.snap +0 -18
  58. package/src/next/__tests__/types.test.ts +0 -429
  59. package/src/next/createResource.ts +0 -194
  60. package/ts4.0/next/OptionsToFunction.d.ts +0 -16
  61. package/ts4.0/next/RestEndpoint.d.ts +0 -226
  62. package/ts4.0/next/createResource.d.ts +0 -94
  63. /package/lib/{next/resourceTypes.d.ts → resourceTypes.d.ts} +0 -0
  64. /package/src/{next/resourceTypes.ts → resourceTypes.ts} +0 -0
  65. /package/ts4.0/{next/resourceTypes.d.ts → resourceTypes.d.ts} +0 -0
@@ -1,262 +0,0 @@
1
- import { Endpoint } from '@data-client/endpoint';
2
- import { pathToRegexp } from 'path-to-regexp';
3
-
4
- import extractCollection from '../extractCollection.js';
5
- import mapCollection from '../mapCollection.js';
6
- import NetworkError from '../NetworkError.js';
7
- import { paginatedMerge, paginatedFilter } from '../paginatedCollections.js';
8
- import paginationUpdate from '../paginationUpdate.js';
9
- import paramsToString from '../paramsToString.js';
10
- import { getUrlBase, getUrlTokens, isPojo } from '../RestHelpers.js';
11
-
12
- /** Simplifies endpoint definitions that follow REST patterns
13
- *
14
- * @see https://resthooks.io/rest/api/RestEndpoint
15
- */
16
- export default class RestEndpoint extends Endpoint {
17
- #hasBody;
18
- constructor(options) {
19
- super(
20
- options.fetch ??
21
- async function (...args) {
22
- const urlParams =
23
- this.#hasBody && args.length < 2 ? {} : args[0] || {};
24
- const body = this.#hasBody ? args[args.length - 1] : undefined;
25
- return this.fetchResponse(
26
- this.url(urlParams),
27
- await this.getRequestInit(body),
28
- )
29
- .then(response => this.parseResponse(response))
30
- .then(res => this.process(res, ...args));
31
- },
32
- options,
33
- );
34
- // we want to use the prototype chain here
35
- if (
36
- !('sideEffect' in this) ||
37
- ('method' in options && !('sideEffect' in options))
38
- ) {
39
- this.sideEffect =
40
- options.method === 'GET' || options.method === undefined
41
- ? undefined
42
- : true;
43
- }
44
- if (this.method === undefined) {
45
- this.method = this.sideEffect ? 'POST' : 'GET';
46
- }
47
- if (this.urlPrefix === undefined) {
48
- this.urlPrefix = '';
49
- }
50
- this.#hasBody =
51
- (!('body' in this) || this.body !== undefined) &&
52
- !['GET', 'DELETE'].includes(this.method);
53
-
54
- Object.defineProperty(this, 'name', {
55
- get() {
56
- // using 'in' to ensure inheritance lookup
57
- if ('__name' in this) return this.__name;
58
- return this.urlPrefix + this.path;
59
- },
60
- });
61
- }
62
-
63
- key(...args) {
64
- return `${this.method} ${this.url(
65
- this.#hasBody && args.length < 2 ? {} : args[0] || {},
66
- )}`;
67
- }
68
-
69
- /** Get the url */
70
- url(urlParams = {}) {
71
- const urlBase = getUrlBase(this.path)(urlParams);
72
- const tokens = getUrlTokens(this.path);
73
- const searchParams = {};
74
- Object.keys(urlParams).forEach(k => {
75
- if (!tokens.has(k)) {
76
- searchParams[k] = urlParams[k];
77
- }
78
- });
79
- if (Object.keys(searchParams).length) {
80
- return `${this.urlPrefix}${urlBase}?${paramsToString(searchParams)}`;
81
- }
82
- return `${this.urlPrefix}${urlBase}`;
83
- }
84
-
85
- getHeaders(headers) {
86
- return headers;
87
- }
88
-
89
- /** Init options for fetch - run at fetch */
90
- async getRequestInit(body) {
91
- const bodyIsPojo = isPojo(body);
92
- if (bodyIsPojo) {
93
- body = JSON.stringify(body);
94
- }
95
- const init = {
96
- ...this.requestInit,
97
- method: this.method,
98
- signal: this.signal,
99
- body,
100
- };
101
- if (!body || bodyIsPojo) {
102
- init.headers = {
103
- // default to application/json but allow user explicit overrides
104
- 'Content-Type': 'application/json',
105
- ...init.headers,
106
- };
107
- }
108
- init.headers = await this.getHeaders(init.headers);
109
- return init;
110
- }
111
-
112
- /** Perform network request and resolve with HTTP Response */
113
- fetchResponse(input, init) {
114
- return fetch(input, init)
115
- .then(response => {
116
- if (!response.ok) {
117
- throw new NetworkError(response);
118
- }
119
- return response;
120
- })
121
- .catch(error => {
122
- // ensure CORS, network down, and parse errors are still caught by NetworkErrorBoundary
123
- if (error instanceof TypeError) {
124
- error.status = 500;
125
- }
126
- throw error;
127
- });
128
- }
129
-
130
- parseResponse(response) {
131
- // this should not have any content to read
132
- if (response.status === 204) return Promise.resolve(null);
133
- if (!response.headers.get('content-type')?.includes('json')) {
134
- return response.text().then(text => {
135
- // string or 'not set' schema, are valid
136
- // when overriding process they might handle other cases, so we don't want to block on our logic
137
- if (
138
- ['string', 'undefined'].includes(typeof this.schema) ||
139
- this.schema === null ||
140
- this.process !== RestEndpoint.prototype.process
141
- )
142
- return text;
143
-
144
- const error = new NetworkError(response);
145
- error.status = 404;
146
- error.message = `Unexpected text response for schema ${this.schema}`;
147
- // custom dev-only messages for more detailed cause
148
- /* istanbul ignore else */
149
- if (process.env.NODE_ENV !== 'production') {
150
- if (
151
- !(
152
- response.headers.get('content-type')?.includes('html') ||
153
- text.startsWith('<!doctype html>')
154
- )
155
- ) {
156
- if (tryParse(text) !== undefined) {
157
- error.message = `"content-type" header does not include "json", but JSON response found.
158
- See https://www.rfc-editor.org/rfc/rfc4627 for information on JSON responses
159
-
160
- Using parsed JSON.
161
- If text content was expected see https://resthooks.io/rest/api/RestEndpoint#parseResponse`;
162
- }
163
- } else {
164
- error.message = `Unexpected html response for schema ${this.schema}
165
- This likely means no API endpoint was configured for this request, resulting in an HTML fallback.
166
-
167
- Response (first 300 characters): ${text.substring(0, 300)}`;
168
- }
169
- }
170
- throw error;
171
- });
172
- }
173
- return response.json().catch(error => {
174
- error.status = 400;
175
- throw error;
176
- });
177
- }
178
-
179
- process(value) {
180
- return value;
181
- }
182
-
183
- errorPolicy(error) {
184
- return error.status >= 500 ? 'soft' : undefined;
185
- }
186
-
187
- get pathRegex() {
188
- return pathToRegexp(this.path);
189
- }
190
-
191
- testKey(key) {
192
- const prefix = this.method + ' ' + this.urlPrefix;
193
- if (!key.startsWith(prefix)) return false;
194
- let lastQuestion = key.lastIndexOf('?');
195
- if (lastQuestion === -1) lastQuestion = undefined;
196
- return this.pathRegex.test(key.substring(prefix.length, lastQuestion));
197
- }
198
-
199
- extend(options) {
200
- // make a constructor/prototype based off this
201
- // extend from it and init with options sent
202
- class E extends this.constructor {}
203
-
204
- Object.assign(E.prototype, this);
205
- const instance = new E(
206
- // fetch get overridden by function prototype, so we must set it explicitly every time
207
- { fetch: this.fetch, ...options },
208
- );
209
-
210
- return instance;
211
- }
212
-
213
- paginated(removeCursor) {
214
- if (typeof removeCursor === 'string') {
215
- const fieldName = removeCursor;
216
- removeCursor = ({ ...params }) => {
217
- delete params[fieldName];
218
- return [params];
219
- };
220
- }
221
- let found = false;
222
- const createPaginatedSchema = collection => {
223
- found = true;
224
- return collection.addWith(paginatedMerge, paginatedFilter(removeCursor));
225
- };
226
- const newSchema = mapCollection(this.schema, createPaginatedSchema);
227
- if (found) {
228
- return this.extend({ schema: newSchema });
229
- }
230
-
231
- return this.extend({ update: paginationUpdate(this, removeCursor) });
232
- }
233
-
234
- get push() {
235
- return this.extend({
236
- method: 'POST',
237
- schema: extractCollection(this.schema, s => s.push),
238
- });
239
- }
240
-
241
- get unshift() {
242
- return this.extend({
243
- method: 'POST',
244
- schema: extractCollection(this.schema, s => s.unshift),
245
- });
246
- }
247
-
248
- get assign() {
249
- return this.extend({
250
- method: 'POST',
251
- schema: extractCollection(this.schema, s => s.assign),
252
- });
253
- }
254
- }
255
-
256
- const tryParse = input => {
257
- try {
258
- return JSON.parse(input);
259
- } catch (e) {
260
- return undefined;
261
- }
262
- };