Vuex-CRUD
Introduction
Vuex-CRUD is a library for Vuex which helps you to build CRUD modules easily.
Installation
yarn add vuex-crud
OR
npm install vuex-crud
Vuex-CRUD uses Array.prototype.includes
, Object.assign
and Promise
. Make sure hat your project use polyfill for those if you want to support older browsers! Look at here: https://babeljs.io/docs/usage/polyfill/ for more info.
Basic Usage
- Create your first CRUD resource:
import createCrudModule from 'vuex-crud';
export default createCrudModule({
resource: 'articles'
});
- Register your CRUD resource in your store:
import Vue from 'vue';
import Vuex from 'vuex';
import articles from '@/store/articles';
Vue.use(Vuex);
export default new Vuex.Store({
state: {},
modules: {
articles
}
});
- Use it in your components:
<!-- src/components/Articles -->
<template>
<main>
<article v-for="article in articleList">
<h1>{{ article.title }}</h1>
<p>{{ article.content }}</p>
</article>
</main>
</template>
<script>
import { mapGetters, mapActions, mapState } from 'vuex';
export default {
name: 'articles',
computed: {
...mapGetters('articles', {
articleList: 'list'
}),
...mapState([
'route', // vuex-router-sync
]),
},
methods: {
...mapActions('articles', {
fetchArticles: 'fetchList'
}),
fetchData() {
return this.fetchArticles();
}
},
watch: {
$route: 'fetchData',
},
created() {
this.fetchData();
}
};
</script>
<!-- src/components/Article -->
<template>
<main>
<article v-if="currentArticle">
<h1>{{ currentArticle.title }}</h1>
<p>{{ currentArticle.content }}</p>
</article>
</main>
</template>
<script>
import { mapGetters, mapActions, mapState } from 'vuex';
export default {
name: 'article',
computed: {
...mapGetters('articles', {
articleById: 'byId'
}),
...mapState([
'route', // vuex-router-sync
]),
currentArticle() {
return this.articleById(this.route.params.id);
}
},
methods: {
...mapActions('articles', {
fetchArticle: 'fetchSingle'
}),
fetchData() {
return this.fetchArticle({
id: this.route.params.id
});
}
},
watch: {
$route: 'fetchData',
},
created() {
this.fetchData();
}
};
</script>
Advanced Usage
The following options are available when creating new Vuex-CRUD module:
import createCrudModule, { defaultClient } from 'vuex-crud';
export default createCrudModule({
resource: 'articles',
idAttribute: 'id',
urlRoot: '/api/articles',
state: {},
actions: {},
mutations: {},
getters: {},
client: defaultClient,
onFetchListStart: () => {},
onFetchListSuccess: () => {},
onFetchListError: () => {},
onFetchSingleStart: () => {},
onFetchSingleSuccess: () => {},
onFetchSingleError: () => {},
onCreateStart: () => {},
onCreateSuccess: () => {},
onCreateError: () => {},
onUpdateStart: () => {},
onUpdateSuccess: () => {},
onUpdateError: () => {},
onReplaceStart: () => {},
onReplaceSuccess: () => {},
onReplaceError: () => {},
onDestroyStart: () => {},
onDestroySuccess: () => {},
onDestroyError: () => {},
only: [
'FETCH_LIST',
'FETCH_SINGLE',
'CREATE',
'UPDATE',
'REPLACE',
'DESTROY'
],
parseList: res => res,
parseSingle: res => res,
parseError: res => res
});
Nested Resources
Vuex-CRUD is designed mainly for flatten APIs like:
/api/articles/
/api/users/1
/api/pages?byBook=1
but it also supports nested resources like:
/api/books/1/pages/10
/api/users/john/tasks/15
However your store will always be flattened and will look similar to this:
{
books: {
entities: {
'1': {
}
}
},
pages: {
entities: {
'1': {
},
'2': {
},
'3': {
}
},
list: ['1', '2', '3']
},
}
There are 2 possible ways to implement provide custom URL:
- Provide custom url for each request:
fetchList({ customUrl: '/api/books/1/pages' });
fetchSingle({ customUrl: '/api/books/1/pages/1' });
create({ data: { content: '...' }, customUrl: '/api/books/1/pages' });
update({ data: { content: '...' }, customUrl: '/api/books/1/pages/1' });
replace({ data: { content: '...' }, customUrl: '/api/books/1/pages/1' });
destroy({ customUrl: '/api/books/1/pages/1' });
- Define a getter for custom url:
import createCrudModule from 'vuex-crud';
export default createCrudModule({
resource: 'pages',
customUrlFn(id, type, bookId) {
const rootUrl = `/api/books/${bookId}`;
return id ? `rootUrl/${id}` : rootUrl;
}
});
and your requests will look this:
const id = 2;
const bookId = 1;
fetchList({ customUrlFnArgs: bookId });
fetchSingle({ id, customUrlFnArgs: bookId });
create({ data: { content: '...' }, customUrlFnArgs: bookId });
update({ id, data: { content: '...' }, customUrlFnArgs: bookId });
replace({ id, data: { content: '...' }, customUrlFnArgs: bookId });
destroy({ id, customUrlFnArgs: bookId });
Custom client
Vuex-CRUD is using axios for API requests. If you want to customize interceptors or something else, then you can do following:
import createCrudModule, { defaultClient } from 'vuex-crud';
import authInterceptor from './authInterceptor';
defaultClient.interceptors.request.use(authInterceptor);
createCrudModule({
resource: 'comments',
client: defaultClient
});
Parsing Data from Your API
You can provide a custom methods to parse data from your API:
import createCrudModule, { defaultClient } from 'vuex-crud';
createCrudModule({
resource: 'articles',
parseList(response) {
const { data } = response;
return Object.assign({}, response, {
data: data.result
});
},
parseSingle(response) {
const { data } = response;
return Object.assign({}, response, {
data: data.result
});
}
});
Getters
Vuex-CRUD ships with following getters:
list()
returns list of resourcesbyId(id)
returns resource by ID
Actions
Vuex-CRUD ships with following actions (config is configuration for axios):
{
fetchList({ commit }, { config } = {}) {
},
fetchSingle({ commit }, { id, config } = {}) {
},
create({ commit }, { data, config } = {}) {
},
update({ commit }, { id, data, config } = {}) {
},
replace({ commit }, { id, data, config } = {}) {
},
destroy({ commit }, { id, config } = {}) {
},
}
Usage with Nuxt
vuex-crud
works with Nuxt modules system as well. You can simply define your Nuxt modules as following:
import createCRUDModule from 'vuex-crud';
const crudModule = createCRUDModule({
resource: 'articles'
});
const state = () => crudModule.state;
const { actions, mutations, getters } = crudModule;
export {
state,
actions,
mutations,
getters
};
and then use it in your component:
export default {
computed: {
...mapGetters('articles', {
articleList: 'list'
})
},
fetch({ store }) {
store.dispatch('articles/fetchList');
}
};
License
The MIT License (MIT) - See file 'LICENSE' in this project
Copyright
Copyright © 2017 Jiří Chára. All Rights Reserved.