Generate a full-featured Vuex 3 module linked to a REST endpoint. Especially useful for large Single-Page Applications using more than 50+ endpoints and choosing Vuex as state management.
This lib has no dependencies apart from vuex.
With this simple declaration:
import axios from 'axios'
const satellites = makeStoreModule('satellite', 'norad_catalog_number')
.generateActions(axios, 'https://api.arcsecond.io/', 'lcrusd')
satellite
is the singular root name for the modulenorad_catalog_number
is the name of the id property. Check what the backend use for these resources (usuallyid
,pk
, oruuid
).axios
is a HTTP requests library. You can use any lib you choose with the same basic APIs.https://api.arcsecond.io/
is the base URL of the backend resources.lcrusd
is a custom strings indicating we want to generate all the mutations & actions (see "LCRUSD ?" below).
...you get a namespaced vuex store module with...
...this state (automatically updated and managed):
- a
satellites
array (initial =[]
) - a
satellitesLoadingStatus
object for each activated LCRUSD action (see below): (initial ={ list: false, create: false, read: null, update: null, swap: null, delete: null }
) - a
selectedSatellite
property (initial =null
) to hold a single selection - a
lastSatellitesError
property (initial =null
) to hold the last action error.
... this getter:
- a
getSatellite(norad_catalog_number)
returning the object if found, and null otherwise.
...these fetch / LCRUSD mutations (automatically handled by the module actions, you don't need to call them yourself):
[list|create|read|update|swap|delete]SatellitePending
[list|create|read|update|swap|delete]SatelliteSuccess
[list|create|read|update|swap|delete]SatelliteFailure
which correspondingly updates the satelliteLoadingStatus
object property (with a boolean for list
and create
and the object id for the other actions.)
...but also this mutation:
selectSatellite(<satelliteObject>)
...these (async) actions, which both update the module state and return the request body (making the use of them very flexible):
- a
listSatellites()
(which can receive search parameters like this:listSatellites({key1: value1, key2: value2}
) - a
createSatellite(payload)
with apayload
object - a
readSatellite(norad_catalog_number)
with thenorad_catalog_number
which is the name of the id for htis endpoint. - a
updateSatellite({norad_catalog_number: <value>, data: <data object>})
- a
swapSatellite({norad_catalog_number: <value>, data: <data object>})
- a
delete(norad_catalog_number)
with thenorad_catalog_number
which is the name of the id for htis endpoint.
It is a simple way to distinguish actions made on a RESTful backend, because names based on HTTP verbs, or the usual
CRUD
acronym aren't sophisticated enough. For instance, a GET
request to a list
endpoint fetches an object, while
a GET
on the list endpoint returns all the resource objects. It is more readable, at the functional app code level, to
distinguish these two "reads".
Hence, quite logically:
l
means list and performs aGET
request on thelist
endpointc
means create and performs aPOST
request on thelist
endpointr
means read and performs aGET
request on thedetail
endpointu
means update and peforms aPATCH
request (= partial update) on thedetail
endpoints
means swap and performs aPUT
request (= full update) on thedetail
endpointd
means delete and performs aDELETE
request on thedetail
endpoint
Depending on the lcrusd
string passed as parameter, not all actions are generated. For instance, for a read-only REST
endpoint, simply pass lr
. There will be no create...
, update...
, swap...
nor delete...
mutations and actions
generated in the module.
In a Vue.js component, you can have a table displaying the satellites
array. At the beginning it is empty, but you
trigger a listSatellites
action, during which the satellitesLoadingStatus.list
is true
. Once successful
the satellites
array is filled with the request response, while the loading status is back to false
. Clicking on a
row of the table triggers selectSatellite
which allow other Vue components to see a non-null
selectedSatellite
.
- If a read is successful, it will update the list and replace the object inside it if it is present. If not, it will be appended to the list.
- If an update is successful, it will update the list and update the object inside it if it is present. If not, it will be appended to the list.
- If an swap is successful, it will update the list and replace the object inside it if it is present. If not, it will be appended to the list.
- If a delete is successful, it will update the list and remove the object inside it if it is present.
Of course, the selection
state is always updated accordingly.
Moreover, If an action is called on an unknown item, it does nothing silently.
(Just a way to explain why the above.)
Say, you have an Vue.js (v2) Single-Page Application (SPA) for the browser, that is heavily relying on a pure RESTful backend,...
Say, you choose to develop your large SPA with Vuex, the Vue.js module with Redux principles, as a state management library...
Say, you need to easily retrieve and store list of items, possibly paged, and supporting search query parameters...
Say, you need to also fetch details of items, and easily managed the introduction in your module of new items, update of items, deletion of items...
Say, you regularly need to also handle the selection of an item in a list, or even the selection of multiple items of that list...
Say, you need this a dozen times, maybe a dozen dozen dozen times... all the same basic way...
Say, of course, that for all these actions, you need to correctly handle the request failures, the succeses and the famous loading status to display that little spinning wheel...
In fact, you get a lot more with this lib. But make sure to read what's above first, and let flow it inside your head.
Then... (TODO, write about paged-list endpoints, subresources & data attaching)
npm install
npm run build
npm run test:unit
npm run lint