@whidb/restapi
v0.4.7
Published
Custom hooks and utilities to make it easier to work with our whirest node server code and its dynamic endpoints.
Downloads
49
Readme
@whidb/restapi
Custom hooks and utilities to make it easier to work with our whirest node server code and its dynamic endpoints.
- useCrudApi and useQueryApi help with using the dynamic rest endpoints created from the data in the REST_ENDPOINTS table.
See also the @whidb/restui-pr library for ui code utilities that work with these hooks.
Getting Started
Install @whidb/restapi and its dependencies...
npm i @whidb/restapi npm i axios @tanstack/react-query @tanstack/react-query-devtools
Wrap your application code in a RestApiContextProvider (index.js or app.js).
import { QueryClient } from "@tanstack/react-query" import { RestApiContextProvider } from "@whidb/restapi" const queryClient = new QueryClient() export default function App() { return ( <RestApiContextProvider client={queryClient}> <!--your app code here --> </RestApiContextProvider> ) }
The RestApiContextProvider does several things.
- it wraps your code in a react-query QueryClientProvider so it can use react-query and adds the react-query devtools to help debugging react-queries in development (little flower thing in the bottom right corner when you run the code in development mode)
- it sets up a react context so the filtering you apply to useCrudApi and useQueryApi are "remembered" even when you leave and come back to pages
Handy, but not required... Setup .env.development and constants.js files to define paths to the rest apis
.env.devlopmentREACT_APP_JSON_API_ROOT = "https://devccc.whi.org/api"
constants.js
export const JSON_API_ROOT = process.env.REACT_APP_JSON_API_ROOT || "/api" export const QUERYURL = `${JSON_API_ROOT}/query` export const CRUDURL = `${JSON_API_ROOT}/crud` export const PROCURL = `${JSON_API_ROOT}/proc`
This way you use path strings like `${QUERYURL}/endpointname` in your useCrudApi calls.
useCrudApi and useQueryApi
Custom hooks to help with performing crud operations with the dynamic rest endpoints defined in our web.rest_endpoints table.
- useQueryApi is the same as useCrudApi, but doesn't include the crud state and functions in its return values.
- These hooks include setGlobalFilter and setColFilters functions to performing filtering of the fetched data
- They also include a few state variables and functions useful for building forms and screens to display the data and perform crud operations (e.g. the @whidb/restui library).
NOTE: These hooks are just a wrapper around react-query useQuery and useMutation hooks. Reading the react-query documentation may be helpful in debugging situations. Also you can use the react-query dev tools for help in debugging query problems.
Usage
const [state, controller] = useCrudApi(queryKey, options)
useCrudApi takes two parameters
queryKey
The endpoint url. It must be either...
a string - the url to an endpoint as defined in the REST_ENDPOINTS table,
e.g.https://devccc.whi.org/api/crud/fact-db
.
Note: this can contain url parameters, but it's recommended that you use the array form of queryKey if you have parameters.an 2 element array - an array with a url string and a url parameter object.
e.g. [`${CRUDURL}/fact-data-sources`, { dsrcId: dsrcId }].
This format makes it easier to work with multiple parameters, especially when some of them may be optional, See the examples section below. The elements of the parameter object will be converted into an url parameter string for the fetch.
Note: This is the queryKey value sent to the react-query useQuery hook. Changing this value will trigger a refetch of the data.
options
An optional object containing one or more of the following
Data Processing functions - Rarely needed, these are async functions that are executed before or after crud operations. They allow you to add custom processing to these events (e.g. sorting/manipulating the data after fetching, running pl/sql functions pre or post crud operations).
processFetchedData - async function that runs after a fetch. It takes the fetched data as a parameter and returns the modified data object. Use this if you need to manipulate the raw data in some way, e.g. sorting.
preProcessEditItem - async function that executes before inserts and updates. Gets passed editItem and must return a possibly modified editItem. Can be used for validation, and will abort crud operation completion if an error is thrown.
preInsert, preUpdate and preDelete - async functions that execute before the corresponding crud operation. Gets passed editItem and must return a possibly modified editItem. Can be used for validation, and will abort crud operation completion if an error is thrown.
dbDelete - async function to REPLACE the normal db delete operation. e.g. if the object has children that need to be deleted, you can use this to replace the normal delete with a rest call that fires a db procedure to delete the row and its children.
postInsert and postUpdate - async functions to execute after the insert or update has fired, but before the new item is added to the data array. Gets passed the return value from the insert/update and returns the object to put into the data array
Filtering options - for customizing how the colFilters are applied
- filterOnServer - if true, apply column filtering on server side. Defaults to false. Turn this on if table is very large and you want to perform filtering before sending to the client.
- fetchOnlyOnColFilters - if true will not fire the fetch
Mutation options - Rarely needed, these allow you to add to or override the normal useCrud mutatation options. See react-query documentation for the options available to mutations.
- useMutationOptions - will be applied to the insert, update and delete mutations
- insertMutationOptions - will only be applied to the insert mutation
- updateMutationOptions - will only be applied to the update mutation
- deleteMutationOptions - will only be applied to the delete mutation
useQuery options - Any other key value pairs in this object will be assumed to be react-query options and will be passed to the useQuery call. See the react-query documentation for available options. Note enabled and staletime options are especially useful, see examples below.
useCrudApi returns an array with two objects
state - holds the various state variables related to fetching and crud operations
- data - the data fetched from the url. *note if filtering is applied this will be the filtered data
- isLoading - true if data fetch is running (and not idle see react-query docs)
- isError - true if an error occurred during data fetch
- isSuccess - true if an error occurred during data fetch
- query - the return value from the react-query useQuery call
- globalFilter - current globalFilter value (see filtering)
- colFilters - current colFilters (see filtering)
- editItem - used by form ui to hold the item to edit
- insertMode - if true code will attempt to insert the item, otherwise it will do an edit
controller - Crud/Utility functions
setGlobalFilter - Sets the text value used for datatable globalfilter property. This will trigger filtering the data.
setColFilters - an array of objects to be passed to the server to do server side column filtering. Setting this will trigger filtering the data. If filterOnServer is true, colFilters will be passed to the server for processing (helpful for very large tables)
doInsert, doUpdate, doDelete - takes an object of row data to send to the crud endpoint.
setNewItem and setEditItem - holds the row data for use by an edit form. using setNewItem sets insertMode to true.
Notes
- these are in an array so you can name the return variables whatever you want (see examples)
- You can have several useCrudAPI calls pointing to different urls in the same screen.
- you dont have to use the crud capabilities, you can use this to just fetch data, although useQueryApi is designed for this usage.
useCrudApi and useQueryApi usage examples
Simple, no parameters
const [dtypState, dtypCtrl] = useCrudApi(`${CRUDURL}/F2_DATA_TYPES`)
fetch will fire immediately
With url parameters
using the array style for parameters, with the url parameters expressed as an object
const [dsrcState, dsrcCtrl] = useCrudApi([`${CRUDURL}/fact-data-sources`, { dsrcId: 5 }])
params will be converted into a url param string ("?dsrcId=5") and added to the fetch. Any change to the params object will fire a re-fetch
Only fire fetch if parameters exist (enabled react-query option)
Add the "enabled" useQuery option to only fire the fetch when enabled condition is true.
const { dsrcId } = useParams()
const [dataSourceQuery] = useQueryApi(`${CRUDURL}/fact-data-sources`, { dsrcId }, { enabled: !!dsrcId })
In this example, useParams is asyncronous and dsrcId will be null at first. The enabled option ensures the query will only fire when the parameter has a value, saving an unneeded fetch that would return all data sources.
Use staletime to reduce the number of fetches react-query performs
React-query automatically refreshes your data at various times. Sometimes the design of your ui will trigger new fetches as you move around (e.g. tabs/modals). If the data doesnt change very often you can use the staletime to keep the data in the react-query cache longer and reduce the number of network fetches.
e.g. this keeps the data in the cache for a minute.
const [dtypState, dtypCtrl] = useCrudApi(`${CRUDURL}/fact-data-types`, undefined, { staleTime: 1000 * 60 })
Crud operations performed in the app will refesh the data regardless of the cache setting, but if there are other users editing data, you would not see those changes for an hour with this setting.
Converting from whireact library
- whireact is now split into two libraries @whidb/restapi and @whidb/restui
- make sure to make the changes to your top level components as explained in the getting started instructions