Vuex-ORM brings Object-Relational Mapping to the Vuex Store. vuex-orm-rest lets you communicate with RESTful backends.
The plugin extends the basic model of Vuex-ORM with some helful functions to make CRUD operations such as (save, fetch, fetchAll, update and delete).
You no longer need to access your http client manually. All the comunication happens thru the enhanced Vuex-ORM models.
yarn add vuex
yarn add @vuex-orm/core
- axios (recommended)
yarn add axios
yarn add vuex-orm-rest
The following exmaple installs the plugin using axios as the HTTP-Client and a vue-router instance.
import Vue from 'vue'
import Vuex from 'vuex'
import VuexORM from '@vuex-orm/core';
import VuexORMRest from 'vuex-orm-rest';
import axios from 'axios';
const client = axios.create({ baseURL: '/api' });
const database = new VuexORM.Database();
VuexORM.use(VuexORMRest, { client });
Vue.use(Vuex);
export default new Vuex.Store({
plugins: [VuexORM.install(database)],
});
The plugin requires a HTTP-Client to make requests to the backend. The client is passed as an option to the plugin. The following tables shows the association between the client- and CRUD method.
Plugin | Client |
---|---|
fetch | get |
fetchAll | get |
save | post |
update | patch |
replace | put |
destroy | delete |
Go to https://vuex-orm.github.io/vuex-orm/guide/components/models.html to see how to define models using Vuex-ORM.
Assume we have a user
model. Additionally to the entity
an apiPath
variable has to be defined.
The apiPath
represents the URL under which the entity is reachable on the REST API.
import { Model } from '@vuex-orm/core';
class User extends Model {
static entity = 'users';
static apiPath = 'users';
static fields () {
return {
id: this.attr(null),
name: this.attr('')
}
}
}
Your vuex-orm instance need to know about your model.
database.register(User, {});
Fills the store with a single item by id. Returns a promise with the fetched data.
User.fetch(1);
The fetched user now lies in the store and can be retrieved by using the Vuex-ORM actions.
const user = User.find(1);
Fills the store with a list of items. Returns a promise with the fetched data.
User.fetchAll();
Pass filter to append it as query string to the get request.
User.fetchAll({ filter: { active: true } });
Pass relations to fetch nested structure.
const user = User.find(1);
Comments.fetchAll({ relations: [user] });
// fetches using /user/1/comments
Retrieve the fetched users.
User.all();
Saves a user instance using post verb. Returns a promise with the post response.
const user = new User({ name: 'John Doe' });
user.save();
Pass keys as param to define which attributes should be send to the backend.
const user = new User({ name: 'John Doe' });
user.save(['name']);
Updates an existing user using patch verb. Returns a promise with the patch response. The update function also accepts a list of keys for every property that should be part of the patch payload.
// Retrieve the user from the store
const user = User.find(1);
user.name = 'Michelangelo';
// This only updates the name property
user.update(['name']);
Replaces a whole user instance using put verb. Returns a promise with the put response.
// Retrieve the user from the store
const user = User.find(1);
user.name = 'Michelangelo';
// This only updates the name property
user.replace();
Destroys a user using the delete verb. Returns a promise with the delete response.
// Retrieve the user from the store
const user = User.find(1);
user.destroy();
Generate a route URL with prefix on a model instance.
const user = User.find(1);
user.routeURL('some'); // --> { name: 'some-user', params: { id: 1 } }
Passing options allows for having params such as a hash on the link
const user = User.find(1);
user.routeURL('show', { hash: '#hash' }); // --> { name: 'some-user', params: { id: 1 }, hash: '#hash' }
Generate a route URL with show prefix on a model instance.
const user = User.find(1);
user.showURL(); // --> { name: 'show-user', params: { id: 1 } }
Generate a route URL with edit prefix on a model instance.
const user = User.find(1);
user.showURL(); // --> { name: 'edit-user', params: { id: 1 } }
Generate unique key for iterations in DOM such as v-for
in vuejs.
const user = User.find(1);
user.listKey(); // --> 'user-1'
Serializes all fields by default but the $id
of an entity. Using the keys
parameter you can define which keys should be serialized.
const user = User.find(1);
user.pickKeys(); // --> { firstname: 'Hugo', lastname: 'Boss' }
user.pickKeys(['firstname']); // --> { firstname: 'Hugo' }
The save
and update
method uses pickKeys
to determine which fields should be send to the backend.
You could override this method to always include a certain key:
pickKeys(keys) {
return super.pickKeys([
...keys,
'this_key_is_always_in_the_payload',
]);
}
Every fetch
or fetchAll
request first hits the store and returns the entities immediately if found.
In the background the http request happens and updates as soon as the response is back.
This method will make your UI respond fast on the first hit but may be outdated.
But the request in the background will update it as soon as possible.
The caching is enabled by default and can be turned of globally by passing the useCache
option.
import VuexORM from '@vuex-orm/core';
import VuexORMRest from 'vuex-orm-rest';
VuexORM.use(VuexORMRest, { useCache: false });
It is also possible to disable the caching for a single request.
User.fetch(1, { useCache: false });
The async queue is a utility which helps to manage fetching data.
It is possible to execute functions sequentially or in parallel.
All the methods from the queue are chainable. The whole queue is executed using the exec
method.
The sequence method executes functions sequentially. The result from the previous sequence is passed to the next step when resolved.
const res = await Queue
.sequence(() => Promise.resolve(1))
.sequence((res) => Promise.resolve(res + 1))
.exec(); // Evaluates to 2
The parallel method executes functions in parallel. The result from the previous parallel is passed to the next step as an array when all functions are resolved.
const res = await Queue
.parallel(() => Promise.resolve(1))
.parallel(() => Promise.resolve(2))
.parallel(() => Promise.resolve(3))
.exec(); // Evaluates to [1, 2, 3]
It is also possible to mix the parallel and sequence method.
const res = await Queue
.sequence(() => Promise.resolve(1))
.parallel((res) => Promise.resolve(res + 1))
.parallel((res) => Promise.resolve(res + 1))
.parallel((res) => Promise.resolve(res + 1))
.sequence((res) => Promise.resolve(res))
.exec(); // Evaluates to [2, 2, 2]