The VueRestClient integrates Axios and the concept of Active Record to allows the communication with a back-end api with minimum code. It has an integrated http client with request and response interceptors that allows using authentication (via header Bearer) and localization via header and url parameter that can be automatically added if your options tell so. It can also optionally send request pending events (when still pending and when all are finished) so that you can catch these events and show a loading component.
It was tested with VueJS 2.x, but might work with newer versions.
There are four ways to use this component:
- Use the
HttpClient
as an stand-alone client (supporting Bearer authentication, localization and loading events). - Define a
ModelService
that will be linked to a resource and perform CRUD operations. - Use the
CrudController
attached to a component, so that it will have thesave
,get
,index
,update
,destroy
andconfirmAndDestroy
. Additionally it also can automatically add form validation, callbacks that allow you to listen to events and intercept actions, and options that allow you to customize behaviors and message translations. - A combination of the three previously listed use cases.
Install the library with npm:
npm install vue-rest-client --save
Or build the distribution file to use in HTML file or app:
npm run browserBundleProduction
This will be saved to vue-rest-client/dist/vue-rest-client.js
.
The solution is composed of the following files:
- crud-controller.js
- form-helper.js
- model-service.js
- http-client.js
- model.js
- VrcForm.js
- crud.i18n.en.js
The ModelService
class allows defining an instance that is linked to a given resource in the API. Once defined, it can be used to run REST actions (like query and get) for the defined endpoint/resource. Internally it uses the Model. By default the returned resources are converted into Active record models so that they have methods like $save
, $destroy
and $update
.
ModelService
constructor parameters:
endPoint
(string) - the relative url of the resourceresourceName
(string) - the resource name (used to build the default confirmation messages)options
(Object) - options that allows to customize (optional)the model service behavior.
The options object may contain the following properties:
transformRequest
(function, optional): executed before the request is made. Useful to change data in special circumstances. This function will receive an object with the endpoint and filters (when available) attributes. It is not intended to replace the Axios. request interceptor!transformResponse
(function, optional): executed after the request is made, passing the original response object received. Useful if it necessary to modify the data returned before transforming them in a Model instanceraw
(boolean, optional): defines if the default transformation of the results into Model instances must be skipped. If it is true, the active record will not work with the returned items. Useful when you just want to get data, and not destroy/update thempk
(string, optional): overwrites the default primary key attribute, that is 'id'. Use it if your model on the remote server uses a different field as primary key.httpClientOptions
(object, optional): http client api options. It is expected an object with the structure described below:
const httpClientOptions = {
baseURL: '' // String, an empty string is the default
isAuthenticated: () => {
// run your logic to determine if a user is authenticated and return a boolean
},
getVueInstance: () => {
// return the vuejs main instance
},
getBearerToken: () => {
// run your logic and return the Bearer token
},
geLocale: () => {
// run your logic and return the current app locale
},
appendLocaleToHeader: true/false,
appendLocaleToGetUrl: true/false,
urlLocaleKey: 'l' // String, 'l' is the default
}
export default httpClientOptions
How to create a model service to represent a resource in the back-end:
// file my-model-service.js
import {ModelService} from 'vue-rest-client'
let options = {
pk: 'my-pk-field-name' // necessary only if different of `id`
// This is optional but if not
// passed some features will not work. Have a look in the
// http-client.js to check the details.
httpClientOptions: httpClientOptions, // An object according example above (optional)
raw: true/false // If you don't want the items to be converted to active record models. Default is false.
}
const myModelService = new ModelService('relative/url/to/resource/endpoint', 'My resource nice name', options)
export default myModelService
After this my-model-service.js file is created, you can import it anywhere in the app, and use the following methods:
-
get(pkValue)
- get a resource identified by its primary key value -
query(filters)
- receives an array of query filters and returns a promise, that when resolved, passes a collection of resources -
customQuery(customOptions, endPoint)
- receives an endpoint, an array of query filters and an object with custom options and returns a promise, that when resolved, passes a collection of resources. The customOptions allows the overwrite of the instance options only for the executed request. ThecustomOptions
andendPoint
parameters are optional and will be replaced by the instance options endpoint if are null. The following options attributes can defined:query
(object): containing key -> value attributes to be used as query string)data
(object): containing key -> value attributes to be used as post data)verb
(string): verb to be used - default is 'get'transformRequest
: function to be called back on transformRequest event
-
newModelInstance (rawObject)
- convert a raw object into an active record Model. -
getName
- returns the defined model nice name -
getEndPoint
- returns the endpoint defined for the model service
Example of model service usage:
import myModelService from './my-model-service'
export default {
created () {
// The properties defined in the filters object will be added to
// the query string using. For example page, page size or any other
// parameter that your api supportes. It is optional.
let filters = {}
// Get the resources using the model service
myModelService.query(filters).then((activeRecordModels) => {
this.myModels = activeRecordModels
// by default, each model is an instance of Model /src/model
// having the $save, $update, $destroy, $copy methods
})
}
}
The CrudController
utility uses the form-helper.js
to validate the form before submitting the form. It looks for the validate
function i the form object and traverse all the inputs and looks the properties valid
required
and inputValue
and pushes an error message to the errorBucket
, if it exists and is an array.
It is possible to disable the auto form validation by passing the skipFormValidation:true
in the options object passed to the CrudController constructor. If the default behavior is on, the solution will look for a v-form
reference, in your component context (passed as vm
), named form
(like vm.$refs.form, where vm
is the component context passed to the CrudController). It is also possible to specify a alternative form ref name, by setting the formRef:<my-form-ref-name>(string)
in the options object passed to the constructor of CrudController.
It is also possible to use the form validation apart from the crud component. You just have to import it, create a new instance passing:
- the
formRef
object, - the
vm
object (the component this) - the optional
options
object.
Then, just run the validate
method. It will run the default form object passed in the formRef validation and also check for the required
attribute in each input and validate it. If any field is invalid, it will highlight it, set the valid
status as false and also add a string to the inputs the error bucket using input label and crud translations for required
.
The CrudController class allows to add common extended CRUD actions (get, index, save, update, destroy) to a component that uses the RESTFul API pattern. It is intended to be used in conjunction with the class ModelService (required by the constructor)
This crud class implements the full cycle to get and send data to/from a remote server, including before destroy confirmation dialog, refresh listed data after save, destroy and update and success and confirmation messages.
To use this feature you will need to import Controller
and CrudData
and use them as follows:
The Controller
set method expects the following parameters:
- @param {}
vm
- the component instance, that can be passed usingthis
- @param {}
modelService
- an instance of the ModelService class representing the service that provides the data service to a resource. @see src/model-service - @param {}
options
- object with optional parameters that allows to customize the CRUD behavior
The options object may contain the following properties:
resourceSavedMsg
(string): custom message for resource savedresourceEmptyMsg
(string) custom message for resource emptyresourceUpdatedMsg
(string) custom message for resource updatedoperationAbortedMsg
(string): custom message for operation aborted.failWhileTryingToGetTheResourceMsg
(string): custom message for fail while trying to get resourcesaveFailedMsg
(string): custom message to be displayed on save action failureupdatedMsg
(string): custom message to be displayed on update action failureconfirmDestroyTitle
(string): custom title to be displayed on the confirm dialog shown before destroy actiondoYouReallyWantToRemoveMsg
(string): custom text to be displayed on the confirm dialog shown before destroy actiondestroyedMsg
(string): custom message to be displayed after an resource has been destroyedfailWhileTryingToDestroyResourceMsg
(string): custom message to be displayed on destroy action failurefailWhileTryingToUpdateResourceMsg
(string): custom message for update failuredestroyAbortedMsg
(string): custom message to be displayed when a destroy is abortedresourceDestroyedMsg
(string): custom message for resource destroyedinvalidFormMsg
(string): custom invalid form messageremovalConfirmTitle
: (string): custom message for removal conform title
queryOnStartup
(boolean): if the index action must be ran on the first CRUD runskipFormValidation
(boolean): skips the auto form validationskipDestroyConfirmation
(boolean): skips the destroy confirmation dialog and runs the destroy directlyskipFormValidation
(boolean): skips the auto form validationskipAutoIndexAfterAllEvents
(boolean) : skips the auto resources reload after data change events (update, destroy and save)skipAutoIndexAfterSave
(boolean) : skips the auto resources reload after saveskipAutoIndexAfterUpdate
(boolean) : skips the auto resources reload after updateskipAutoIndexAfterDestroy
(boolean) : skips the auto resources reload after destroyskipServerMessages
(boolean) : skip using server returned message and use only front end messages do display toastersskipShowValidationMsg
(boolean) : skit showing the validation error message via toaster when a form is invalidformRef
(string, optional) : the alternative name of the form ref you are using in the template. Used to auto validate the form. If not provided, it is assumed that the form ref name isform
showSuccess
: function to be called to show action success messageshowInfo
: function to be called to show action info messageshowError
: function to be called to show action errorconfirmDialog
: function to be called when a confirm resource removal action is run. Expected to return a promise[http-error-status-code-number]
: defines the message to be used when an http error status code is returned by a request (only available fot status code from300
to505
)
If your component/vue instance has the functions showSuccess
, showInfo
, showError
and confirmDialog
, they will be called if these functions are not passed via options and when the corresponding event occurs. the same way, if your component/vue instance has the $t
function (created by vue-i18n
component) it will be used to translate the CRUD messages by trying to get it, for example, via crud.resourceSavedMsg
. If you are not using it, just pass the translations via options or translationFn
via options.
Example of adding CRUD features to a Vue component:
import VueRestClient from 'vue-rest-client'
import myModelService from 'path/to/my/defined/model-service'
// Then, inside your default export
export default {
data: () => ({
// create the crud data objects (resource, resources and modelService) using three dots notation
...VueRestClient.CrudData
})
// The second one must be used to instantiate the crud class on the vue created event, like this:
created () {
// Extend this component, adding CRUD functionalities
let options = {...}
// `this` below represents the `vm` object inside the CrudController
VueRestClient.Controller.set(this, myModelService, options)
}
}
A toast message is shown after each action using the following priority: server response message,
custom message specified in options or the default one (defined in src/i18n/crud.i18n.en.js
). To show these toasters, the CrudController
meeds to use the showSuccess
, showInfo
, showError
and confirmDialog
methods. So it will look for them and use them, in the following order:
- In the options object
- Defined in your component (passed via
vm
) - Use the fall back version defined in
CrudController
(that will redirect the message to the console)
The CrudController will fire events during its actions and optional listening functions can be defined for these events:
If the vue component
passed via vm
to which you are adding the CRUD actions has one of the following defined methods, it is gonna be called by the CrudController. If it returns false, the execution will be rejected and stopped.
beforeIndex
- index means listing resources of a given endpointbeforeGet
beforeSave
beforeUpdate
beforeDestroy
beforeShowError
If the vue component
passed via vm
to which you are adding the CRUD has one of the following defined methods, it is gonna be called by the CrudController passing the related data
afterIndex
afterGet
afterSave
afterUpdate
afterDestroy
afterError
Form validation:
If the vue component
passed via vm
to which you are adding the CRUD has a $ref
named form
and it does not have the option skipFormValidation
defined as true
, the auto form validation will be ran before saving and updating resources.
<!-- the `crudReady` property was added my the CrudController -->
<form ref="form" v-if="crudReady" @keyup.native.enter="save"> <!-- this `save` method was added by the CrudController -->
<input required v-model="resource.username"> <!-- the `resource` object was created/added by the CrudData and you can define custom properties, like `username` in this case -->
<input required v-model="resource.email"> <!-- the `resource` object was created/added by the CrudData and you can define custom properties, like `email` in this case -->
<!-- the `crudReady` and `save` method were added my the CrudController -->
<button v-if="crudReady" @click="save">Save</button>
</form>
<!-- if queryOnStartup was passed as true via options the resources will be listed when the app runs -->
<!-- if skipAutoIndexAfterSave was not passed as false via options the resources will be updated automatically when a resource is saved -->
<div class='listing-resources-example'>
<template v-for="(resource, index) in resources">
<p><b>username</b>: {{resource.username}}</p>
<p><b>Email</b>: {{resource.email}}</p>
</template >
</div>
- The
save
method created by theCrudController
is called. Internally,create
orupdate
will be called depending it the resource has the primary key value. - The the validation will be performed (if it was not disabled via options)
- The
transformRequest
will be run, if defined. - The request is run using the endpoint defined in the
ModelService
instance. - If
transformResponse
is defined, it will be run. - If auto run index after saving is active, an
index
request (that retrieves all the resources) will be made. It can be skipped by passingskipAutoIndexAfterSave:true
via options). - The
afterSave
call back will be called, if defined, passing the resource. - The result of the action will be returned. If it was saved, the resource will be transformed into an active record Model.
- The action result is displayed via toaster (if you defined a toaster message, like
showSuccess
)
Alternative flows may happen and are supported. A similar flow applies for destroy/delete action. In any case you could call a custom method on the button click, run any custom logic and then run, this.save()
(and the others: update, destroy etc).
index
- list all the resources, updating theresources
property added byCrudData
.save
- saves or updates a resourceupdate
- updates a resourcedestroy
- destroy/delete a resourceget
- get a resource by its primary keyconfirmAndDestroy
runs theconfirmDialog
method (passed via options or defined in your component) that must return a promise. When the promise is resolved (the user confirmed the deletion) the destroy action is run.
<vrc-form
sendTitle="my-custom-btn-send-title"
:options="{...}"
recaptcha-key="recaptcha-site-key-if-you-want-to-use-it"
:res="{}"
mode="create"
content-name="my-resource-name"
endpoint="wpp/v1/message/send">
<div slot="default">
<v-text-field label="My input label" v-model="resource.name" autofocus required></v-text-field>
</div>
</vrc-form>
The options parameter expect an object with the same properties that the Controller.set
method expects, plus:
http
-> an object with the possible parameters expected by yheHttpClient
, plus theraw
flag (boolean)
The options object may contain the following properties:
transformRequest
(function, optional): executed before the request is made. Useful to change data in special circumstances. This function will receive an object with the endpoint and filters (when available) attributes. It is not intended to replace the Axios. request interceptor!transformResponse
(function, optional): executed after the request is made, passing the original response object received. Useful if it necessary to modify the data returned before transforming them in a Model instanceraw
(boolean, optional): defines if the default transformation of the results into Model instances must be skipped. If it is true, the active record will not work with the returned items. Useful when you just want to get data, and not destroy/update thempk
(string, optional): overwrites the default primary key attribute, that is 'id'. Use it if your model on the remote server uses a different field as primary key.
The flow of VrcForm is similar to the direct use of a CrudController. The difference is that is might emit the following events during form events/handling:
- resourceLoaded (pass resource)
- reourceLoadingFailed (pass error)
- loaded
- saved (pass resource)
- saveError (pass error)
- submitting (when submit process starts)
- captchaVerified (if using recaptcha and it is verified)
- captchaExpired (if using recaptcha and it expires)
- newEvent (passing {eventName: String, data: {*}})