@soleil-se/app-util 5.3.0 → 5.4.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/CHANGELOG.md +4 -0
- package/README.md +74 -1
- package/client/fetch-json/index.js +48 -0
- package/client/index.js +2 -0
- package/package.json +2 -2
- package/docs/2.vue.md +0 -57
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [5.4.0] - 2023-08-09
|
|
9
|
+
|
|
10
|
+
- Add `fetchJson` function to make requests to app routes or other resources.
|
|
11
|
+
|
|
8
12
|
## [5.3.0] - 2023-07-06
|
|
9
13
|
|
|
10
14
|
- Added helper functions for managing parameters in the URL-field.
|
package/README.md
CHANGED
|
@@ -180,7 +180,7 @@ Stringify an object to a query string compatible with Sitevision.
|
|
|
180
180
|
| Param | Type | Default | Description |
|
|
181
181
|
| --- | --- | --- | --- |
|
|
182
182
|
| params | `Object` | | Object with parameters to stringify. |
|
|
183
|
-
| [options] | `Object` | `{}` |
|
|
183
|
+
| [options] | `Object` | `{}` | Options object. |
|
|
184
184
|
| [options.addQueryPrefix] | `Boolean` | `false` | If a leading `?` should be added to the string. |
|
|
185
185
|
|
|
186
186
|
```js
|
|
@@ -214,6 +214,79 @@ const params = parseParams('?foo=bar&arr[]=1&arr[]=2');
|
|
|
214
214
|
|
|
215
215
|
Following API:s are available in a client context.
|
|
216
216
|
|
|
217
|
+
### Fetch
|
|
218
|
+
|
|
219
|
+
Fetch wrapper for calling app routes, rest-api or external resources.
|
|
220
|
+
|
|
221
|
+
#### fetchJson() => `Promise<Object>`
|
|
222
|
+
|
|
223
|
+
| Param | Type | Default | Description |
|
|
224
|
+
| --- | --- | --- | --- |
|
|
225
|
+
| uri | `String` | | URI for resource |
|
|
226
|
+
| [options] | `Object` | `{}` | Options object, two custom options rest is standard [fetch options](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) |
|
|
227
|
+
| [options.params] | `Object` | `{}` | Object with parameters to be appended to the URI |
|
|
228
|
+
| [options.retries] | `Number` | `0` | Number of retries if the request times out. |
|
|
229
|
+
|
|
230
|
+
**Returns**: `Promise<Object>` - Promise containing parsed JSON-data.
|
|
231
|
+
**Throws** `Error` - Extended error object with custom properties for `status`, `aborted` and other JSON-data returned by the request.
|
|
232
|
+
|
|
233
|
+
Most common usage is getting data from a route in the current app.
|
|
234
|
+
|
|
235
|
+
```js
|
|
236
|
+
import { fetchJson } from '@soleil-se/webapp-util/client';
|
|
237
|
+
|
|
238
|
+
async function getItems() {
|
|
239
|
+
const params = { query: 'foo', start: 0, num: 10 };
|
|
240
|
+
const result = await fetchJson('/items', { params });
|
|
241
|
+
console.log(result);
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Posting form data.
|
|
246
|
+
|
|
247
|
+
```js
|
|
248
|
+
import { fetchJson } from '@soleil-se/webapp-util/client';
|
|
249
|
+
|
|
250
|
+
async function postForm() {
|
|
251
|
+
const body = new FormData();
|
|
252
|
+
body.append('name', 'Foo');
|
|
253
|
+
body.append('mail', 'foo@bar.com');
|
|
254
|
+
|
|
255
|
+
const result = await fetchJson('/create', { method: 'POST', body }));
|
|
256
|
+
console.log(result);
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Specify number of retries if a request times out.
|
|
261
|
+
|
|
262
|
+
```js
|
|
263
|
+
import { fetchJson } from '@soleil-se/webapp-util/client';
|
|
264
|
+
|
|
265
|
+
async function getItems() {
|
|
266
|
+
const params = { query: 'foo', start: 0, num: 10 };
|
|
267
|
+
const result = await fetchJson('/items', { params, retries: 5 });
|
|
268
|
+
console.log(result);
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Handle aborted requests called in rapid succession, for example searching when typing.
|
|
273
|
+
|
|
274
|
+
```js
|
|
275
|
+
import { fetchJson } from '@soleil-se/webapp-util/client';
|
|
276
|
+
|
|
277
|
+
async function onInput() {
|
|
278
|
+
const params = { query: 'foo' };
|
|
279
|
+
try {
|
|
280
|
+
const result = await fetchJson('/search', { params });
|
|
281
|
+
console.log(result);
|
|
282
|
+
} catch(e) {
|
|
283
|
+
// Ignore aborts due to new search.
|
|
284
|
+
if(e.aborted) return;
|
|
285
|
+
// Handle error as usual.
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
217
290
|
### URL Parameters
|
|
218
291
|
|
|
219
292
|
Helper functions setting, getting, updating and clearing query parameters in the URL-field.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { getRouteUri, stringifyParams } from '../../common';
|
|
2
|
+
|
|
3
|
+
function getUrl(uri, params) {
|
|
4
|
+
if (uri.startsWith('/rest-api') || uri.startsWith('/appresource') || !uri.startsWith('/')) {
|
|
5
|
+
return uri + stringifyParams(params, { addQueryPrefix: true });
|
|
6
|
+
}
|
|
7
|
+
return getRouteUri(uri, params);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function toJson(response) {
|
|
11
|
+
try {
|
|
12
|
+
return response.json();
|
|
13
|
+
} catch (e) {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function handleResponse(response) {
|
|
19
|
+
const json = await toJson(response);
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
const error = new Error(json?.message || response?.statusText);
|
|
22
|
+
Object.entries(json).forEach(([key, value]) => {
|
|
23
|
+
error[key] = value;
|
|
24
|
+
});
|
|
25
|
+
error.status = response.status;
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return json;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const controllers = {};
|
|
33
|
+
|
|
34
|
+
export default function fetchJson(uri, { params = {}, retries = 0, ...options } = {}) {
|
|
35
|
+
if (controllers[uri]) controllers[uri].abort();
|
|
36
|
+
controllers[uri] = new AbortController();
|
|
37
|
+
return fetch(getUrl(uri, params), { signal: controllers[uri].signal, ...options })
|
|
38
|
+
.then(handleResponse)
|
|
39
|
+
.catch((error) => {
|
|
40
|
+
const isTimeout = error.status === 504 || error.status === 408 || error.message.includes('SocketTimeoutException');
|
|
41
|
+
if (isTimeout && retries > 0) {
|
|
42
|
+
return fetchJson(uri, { ...options, params, retries: retries - 1 });
|
|
43
|
+
}
|
|
44
|
+
// eslint-disable-next-line no-param-reassign
|
|
45
|
+
error.aborted = error.name === 'AbortError';
|
|
46
|
+
return Promise.reject(error);
|
|
47
|
+
});
|
|
48
|
+
}
|
package/client/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soleil-se/app-util",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.0",
|
|
4
4
|
"description": "Utility and rendering functions for WebApps.",
|
|
5
5
|
"main": "./common/index.js",
|
|
6
6
|
"author": "Soleil AB",
|
|
@@ -14,6 +14,6 @@
|
|
|
14
14
|
"peerDependencies": {
|
|
15
15
|
"@sitevision/api": "*"
|
|
16
16
|
},
|
|
17
|
-
"gitHead": "
|
|
17
|
+
"gitHead": "b590af917fa521db8bdb7e6f97bd35dffa50a0de",
|
|
18
18
|
"dependencies": {}
|
|
19
19
|
}
|
package/docs/2.vue.md
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# Vue (DEPRECATED)
|
|
2
|
-
|
|
3
|
-
Sitevision only supports client side rendering with Vue.
|
|
4
|
-
|
|
5
|
-
## index.js
|
|
6
|
-
|
|
7
|
-
Render an app with only client code.
|
|
8
|
-
`index.js`
|
|
9
|
-
|
|
10
|
-
```javascript
|
|
11
|
-
import router from '@sitevision/api/common/router';
|
|
12
|
-
|
|
13
|
-
router.get('/', (req, res) => {
|
|
14
|
-
const props = { foo: 'bar' };
|
|
15
|
-
res.agnosticRender('', props)
|
|
16
|
-
});
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## main.js
|
|
20
|
-
|
|
21
|
-
### `render(App, { target, props })`
|
|
22
|
-
|
|
23
|
-
`@soleil-api/webapp-util/client/vue`
|
|
24
|
-
|
|
25
|
-
Renders a client side Vue application.
|
|
26
|
-
|
|
27
|
-
**Returns**: <code>\*</code> - Initialized Vue app.
|
|
28
|
-
|
|
29
|
-
| Param | Type | Default | Description |
|
|
30
|
-
| --- | --- | --- | --- |
|
|
31
|
-
| App | <code>\*</code> | | Svelte app root component. |
|
|
32
|
-
| [settings] | <code>Object</code> | <code>{}</code> | Settings object. |
|
|
33
|
-
| [settings.target] | <code>Element</code> | | Target where app should be mounted. |
|
|
34
|
-
| [settings.props] | <code>Object</code> | | Root component props. |
|
|
35
|
-
|
|
36
|
-
`main.js`
|
|
37
|
-
|
|
38
|
-
```javascript
|
|
39
|
-
import { render } from '@soleil-api/webapp-util/client/vue';
|
|
40
|
-
import App from './App.vue';
|
|
41
|
-
|
|
42
|
-
export default (props, target) => {
|
|
43
|
-
render(App, { props, target });
|
|
44
|
-
};
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Mount the app in another element:
|
|
48
|
-
`main.js`
|
|
49
|
-
|
|
50
|
-
```javascript
|
|
51
|
-
import { render } from '@soleil-api/webapp-util/client/vue';
|
|
52
|
-
import App from './App.vue';
|
|
53
|
-
|
|
54
|
-
export default (props) => {
|
|
55
|
-
render(App, { props, target: document.querySelector('#mount_app_here') });
|
|
56
|
-
};
|
|
57
|
-
```
|