-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pkp/pkp-lib#9527 Document useFetch&useFetchPaginated. Refine GA to ru…
…n only on PR and master
- Loading branch information
1 parent
d55b056
commit 716c15a
Showing
7 changed files
with
251 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import {Meta} from '@storybook/blocks'; | ||
|
||
<Meta title="Composables/useFetch" /> | ||
|
||
# useFetch | ||
|
||
`useFetch` is designed for interactions with our API. | ||
|
||
## Technical decisions | ||
|
||
The promise-based [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) serves as a modern replacement for [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest). It is already sufficiently supported across various browser versions, making it a reliable choice. | ||
|
||
There are several libraries available to enhance the Fetch API and add useful features. We have chosen to use the [ofetch](https://github.com/unjs/ofetch) package as underlying library, a fundamental component of the well-known Vue.js framework [Nuxt.js](https://nuxt.com). We believe this provides good chance of long-term support. | ||
|
||
## Features | ||
|
||
This is not ultimate list of features, but highliging ones that are relevant to our usage. | ||
|
||
- **Auto Retry** implemented in [ofetch](https://github.com/unjs/ofetch#%EF%B8%8F-auto-retry) and helps with unstable internet connection. Currently it retries only for GET requests. | ||
- **Encoding Query params** implemented in [ofetch](https://github.com/unjs/ofetch#%EF%B8%8F-adding-query-search-params) to make easy to pass query params that are automatically correctly encoded | ||
- **CSRF token** implemented in **useFetch**. to automatically add CSRF token in header for POST/PUT/DELETE requests. | ||
- **Last request wins** implemented in **useFetch**. Typical use case is if user is changing filters/search criteria on slower connection to make sure that the last request data are applied. Internally it aborts previous request. | ||
- **Automatic X-Http-Method-Override** implemented in **useFetch**. For better [compatibility](https://github.com/pkp/pkp-lib/issues/5981) with some servers its using **X-Http-Method-Override** header for **PUT/DELETE** requests, while keeping method as **POST**. | ||
- **Error Handling** is implemented in useFetch. By default, any response that is not a **200** status is considered an unexpected error, and a dialog is displayed to inform the user. If you anticipate a validation error of user input (**4xx** status codes) that requires handling, this must be explicitly enabled. For more details, refer to the [POST 4xx](?path=/docs/composables-usefetch--docs#post-4xx-with-validation-error) in the Examples section. | ||
|
||
## API | ||
|
||
For detailed list of options please check `useFetch.js`. For common use cases following example should provide enough guidance. | ||
|
||
## Examples | ||
|
||
Note that currently API urls are generated on PHP side and passed to the pages on initial load. In future we intend to bring such utilities to client side as well. | ||
|
||
All examples can be found also in `useFetch.test.js`. There might be use cases that we have not covered yet, feel free to open github [issue](https://github.com/pkp/pkp-lib/issues) to bring it to our attention. | ||
|
||
### GET 200 | ||
|
||
```javascript | ||
const url = ref(submissionsGetApiUrl); | ||
const queryParams = ref({param1: 4, param2: 5}); | ||
// url, query and body can be normal objects or Refs | ||
const {data, isLoading, fetch} = useFetch(url, { | ||
query: queryParams, | ||
}); | ||
|
||
console.log(isLoading.value); // false | ||
console.log(data.value); // null | ||
|
||
await fetch(); | ||
console.log(data.value); // { ... } data returned from server | ||
console.log(isLoading.value); // false | ||
``` | ||
|
||
### POST 200 | ||
|
||
```javascript | ||
const body = {title: 'abc'}; | ||
const url = ref(submissionPostApiUrl); | ||
|
||
// url, query and body can be normal objects or Refs | ||
const {data, validationError, fetch} = useFetch(url, { | ||
method: 'POST', | ||
body, | ||
// important if we expect endpoint to validate user input | ||
// if endpoint returns 4xx, response is saved to validationError | ||
expectValidationError: true, | ||
}); | ||
|
||
await fetch(); | ||
|
||
console.log(validationError.value); // null | ||
console.log(data.value); // {...} data returned from server | ||
``` | ||
|
||
### POST 4xx with validation error | ||
|
||
```javascript | ||
const body = {title: 'abc'}; | ||
const url = ref(submissionPostApiUrl); | ||
|
||
// url, query and body can be normal objects or Refs | ||
const {data, validationError, fetch} = useFetch(url, { | ||
method: 'POST', | ||
body, | ||
// important if we expect endpoint to validate user input | ||
// if endpoint returns 4xx, response is saved to validationError | ||
expectValidationError: true, | ||
}); | ||
|
||
await fetch(); | ||
|
||
console.log(validationError.value); // {title: ['Unsupported characters']} | ||
console.log(data.value); // null | ||
``` | ||
|
||
### PUT 200 | ||
|
||
```javascript | ||
const url = ref(submissionPutApiUrl); | ||
const {data, validationError, fetch} = useFetch(url, { | ||
method: 'PUT', | ||
body: {title: 'abc'}, | ||
expectValidationError: true, | ||
}); | ||
|
||
await fetch(); | ||
|
||
console.log(validationError.value); // null | ||
console.log(data.value); // {...} data returned from server | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import {Meta} from '@storybook/blocks'; | ||
|
||
<Meta title="Composables/useFetchPaginated" /> | ||
|
||
# useFetchPaginated | ||
|
||
`useFetchPaginated` is based on `useFetch` and provides additional features for pagination. | ||
|
||
## API | ||
|
||
For detailed list of options please check `useFetchPaginated.js`. For common use cases following example should provide enough guidance. | ||
|
||
## Examples | ||
|
||
All examples can be found also in `useFetchPaginated.test.js`. | ||
|
||
### GET 200 | ||
|
||
```javascript | ||
const url = ref(submissionsGetApiUrl); | ||
const page = ref(1); | ||
const pageSize = ref(5); | ||
const {items, pagination, isLoading, fetch} = useFetchPaginated(url, { | ||
query: {param1: 4, param2: 5}, | ||
page, | ||
pageSize, | ||
}); | ||
|
||
console.log(isLoading.value); // false | ||
console.log(items.value); // [] | ||
console.log(pagination.value); | ||
/* { | ||
"firstItemIndex": 0, | ||
"itemCount": 0, | ||
"lastItemIndex": 0, | ||
"offset": 0, | ||
"page": 1, | ||
"pageCount": 0, | ||
"pageSize": 5, | ||
} | ||
*/ | ||
|
||
await fetch(); | ||
|
||
console.log(items.value); // [{...},{...},{...},{...},{...}] | ||
console.log(pagination.value); | ||
/* | ||
{ | ||
"firstItemIndex": 1, | ||
"itemCount": 11, | ||
"lastItemIndex": 5, | ||
"offset": 0, | ||
"page": 1, | ||
"pageCount": 3, | ||
"pageSize": 5, | ||
} | ||
*/ | ||
|
||
// based on user interaction, changing to second page and changing pageSize to 3 | ||
page.value = 2; | ||
pageSize.value = 3; | ||
|
||
// intentionally separate execution of fetch and waiting for result to illustrate isLoading=true | ||
|
||
const fetchPromise = fetch(); | ||
console.log(isLoading.value); // true | ||
await fetchPromise(); | ||
|
||
console.log(items.value); // [{...}, {...}, {...}] | ||
console.log(pagination.value); | ||
/* | ||
{ | ||
"firstItemIndex": 4, | ||
"itemCount": 11, | ||
"lastItemIndex": 6, | ||
"offset": 3, | ||
"page": 2, | ||
"pageCount": 4, | ||
"pageSize": 3, | ||
} | ||
*/ | ||
``` |
Oops, something went wrong.