vuex-orm / plugin-axios Goto Github PK
View Code? Open in Web Editor NEWVuex ORM persistence plugin to sync the store against a RESTful API.
Home Page: https://vuex-orm.github.io/plugin-axios/
License: MIT License
Vuex ORM persistence plugin to sync the store against a RESTful API.
Home Page: https://vuex-orm.github.io/plugin-axios/
License: MIT License
Hi there,
I need to add a parameter when calling Model.$fetch(). I tried like this:
await Resource.$fetch({
params: {
branch_id: 1,
},
});
but seems like it doesn't pass it to axios. When I use axios to do it manually it works:
const axios = await this.$axios.get('/api', {
params: {
branch_id: 1,
},
});
Any idea?
Is there a way to implement our own methods other than the ones provided by default in methodConf of the model?
If so, how can I access it?
I tried to make one, but I don't have access to it by the model.
Thank you
Do you have plan to do example app for plugin-axios
on top of your example - Vuex-ORM examples Nuxt?
I am a noob at Vuejs and Nuxtjs and couldn't make it work by reading README of both repositories.
I want to use plugin-axios plugin with vuex-orm-localforage plugin
Plugin-axios plugin has methods of the same name with plugin vuex-orm-localforage
eg:
Model Methods
import User from '../models/User';
/**
* @uri `/users`
*/
User.$fetch();
import User from '../models/User';
/*
Load data from the IndexedDB store associated to a model and persist them in the Vuex Store
*/
User.$fetch();
For plugin plugin-axios сhanging method name in methodConf does not work
The current merge strategy forces a uri prefix on the method. This is a problem when a REST API requires a totally different URI for a specific method or invocation.
It would be better to follow this merge criteria which is evaluated in order:
default (model) -> context -> methodConf -> method -> invocation ($fetch({http:{uri:"..."}}
)
Criteria (evaluated in order):
^[^:]+://
discard current and return uri^/
discard current and return uri (axios will apply baseURL)^[^/]
append to current uri value with '/'First of all, thank you for this wonderful plugin! It has helped me quite a lot. I did run into a snag that I hope you can help with.
I am stumped trying to add params to the fetch action.
When I try this:
myModel.$fetch({
params: {
$limit: 100,
$skip: 100
}
})
It ignores all of my params. Is there a way to add params to the fetch? Thanks again!
Hey!
I got the same problem explained in this issue axios/axios#1093.
I'm not sure that is possible to do this in this plugin. As far as I unsterstand, this method is responsible to handle the query params
plugin-axios/src/actions/Action.js
Line 61 in 70cc314
const filter = {
start_at: new Date().toISOString()
}
TimeEntry.$fetch({
query: {
filter: filter
}
})
// At this moment the endpoint should be : /filter[start_at]=2019-10-05T22:00:00.000Z
If you confirm my point, I will try to open a PR to allow that behaviour.
Thank you
Hey,
this could be an issue maybe for quasar but actually it should work. So i included the plugin as in the readme and when trying to do some call i get the following error:
index.js?5a64:formatted:10623 Uncaught (in promise) TypeError: Cannot read property 'url' of undefined at Function.transformParams (index.js?5a64:formatted:10623) at Function.call (index.js?5a64:formatted:10682) at Array.wrappedActionHandler (vuex.esm.js?2f62:704) at Store.dispatch (vuex.esm.js?2f62:426) at Store.boundDispatch [as dispatch] (vuex.esm.js?2f62:332) at Function.Model.dispatch (vuex-orm.esm.js?0937:1618) at Function.t.components.Model.$fetch (index.js?5a64:formatted:10755) at Store.fetchCurrentUser (users.js?a98b:17) at Array.wrappedActionHandler (vuex.esm.js?2f62:704) at Store.dispatch (vuex.esm.js?2f62:426)
Maybe somebody knows where this is coming from. If needed i provide more information about including.
We try to handle errors using the onError function which we set during creation of plugin (with config).
The error method is processed nicely (we just added a "console.log" command).
But nevertheless the Devtools console show an unhandled error:
What can be done to catch the promise nicely?
Best greets,
Mario Minati
Is there a posibility to define custom event methods for each model?
eg.
For getting or fetching data:
static methodConf = {
methods: {
$get: {
name: 'fetch',
http: {
url: '',
method: 'get',
},
onResponse(response) {
// format response data to match the model
return data
}
},
}
}
or for updating or creating:
static methodConf = {
methods: {
$update: {
name: 'update',
http: {
url: '',
method: 'patch',
},
onBeforeUpdate(data) {
// Transform data to API acceptable...
return data
}
},
}
}
I am using JSON:API 1.1 with relations etc and it would be nice to have this feature
I get an error connect ECONNREFUSED 127.0.0.1:80
when I do a cross domain request from my frontend server to my backend server on my Docker machine. They are on the same network. I properly added the baseURL (with proper casing) but didn't work. Spend some time debugging and found out the default config that is set in /support/interfaces.js
has proxy: {}
(an empty object).
Now that goes wrong in the http adapter. It checks for truthyness of the proxy
option and if true it uses the host
and port
defined in that object, see the code here.
So the solution is to totally remove that (wrong) proxy
default or set it to false
.
It would be good to unify the structure of the configurations across this plugin. For example currently the method invocation has a different structure and options than the methodConf block and individual method block. This makes documentation easier and allows overriding options at the different config levels.
A lodash merge of each of these configuration objects before evaluating the request would be ideal as described in #29
Hey!
Since the version 0.32.2
of @vuex-orm/core, the $delete method has some bugs.
I tried to downgrade to 0.32.1
and everything work fine.
The api call is done but the entry is not removed from the store.
There is lot of changes between these two versions and I don't know if it broke something.
Thank you in advance
How i can configure a interceptor for example refresh a token?
There is a bug in version 0.19 of axios that does not merge the params config.
axios/axios#2190
It is recommended to downgrade to 0.18.1 until the issue is resolved.
By default Django Rest Framework return 204 status code on success method DELETE. With this status code there are no payload data.
https://tools.ietf.org/html/rfc7231#section-6.3.5
Is it possible to configure library to delete object from vuex on get 204 status code? I think it will be good for default behavior.
Currently the actions return the axios response. This is largely useless and causes the following pattern everywhere:
let response = await Model.$fetch();
let fetchedModels = Model.query().where('id' a=>response.map(b=>b.id).includes(a)).get();
rather than
let fetchedModels = await Model.$fetch();
In the current version, there does not seem to be (or its undocumented) a way to mutate an API response before it's being saved/loaded etcetera.
Using an external API, which in my case provides far more information than is needed for the application to function, I only need a few values from an API response. However some are nested in sub-objects. While for the application I'm only in need of (for example) member.username
, memberships.active.id
and displayName
, there currently is no way to "cherry pick" the desired data in a mutator function on a model or specific call.
Partially related to #21
Hey!
This new release looks nice !
But I'm confused on how to upgrade my code base from old versions to the new one with the best practices.
For instance, how I'm supposed to migrate this simple code:
TimeEntry.$create({
data: {
description
}
})
I'm supposed to set the url for every axios call of this model ? I'm not sure
Thanks
Providing an axios instance like this:
VuexORM.use(VuexORMAxios, {
http: {
axios: axiosInstance,
}
});
results in a response handler being added to the handlers list on each call, which in turns breaks proper response handling since each handler in the chain will return (and pass on) the response.data
property.
This is usually not a problem because the Axios constructor does
this.instance = http.axios || axios.create(http);
so that a fresh axios instance is assigned each time. But it breaks as soon as the instance gets reused.
I'm submitting a pull request to fix this issue.
Hi! The method
option as in methodConf.http.methods.$update.http.method
does not have any effect. In my case I wish to issue a patch
request instead of a put
. As far as I can see, it's not implemented, right? Do you plan to implement this config option?
Hi,
tried to load data with async fetch await with nuxt in ssr-mode. Every time I get 404.
Think the http-config is not loaded at this time so api-resource could not be found.
async fetch() {
await MyModel.$fetch() // ends in 404
}
created() {
MyModel.$fetch() // works, but with big render-delay
}
Is there any way to load the resource asynchronously?
Thanks.
Axios should handle appending params to the uri rather than Action.js#L61
This should probably make use of Axios paramsSerializer
.
The query
option at method invocation should be discarded for params
and any :param
present in the uri should just flag the param for removal when passed to axios. This would leverage #29 and #31
I'm wondering if it's possible to use this with cacheAdapterEnhancer. Namely, I would like to be able to conditionally disable caching when doing a request like Model.$get({ cache: false, params: { id } })
. The cache: false
option has no effect in this case.
I guess another way to ask this question is: is there a way to pass axios options through Model.$get
?
Hello!
I'm trying to attach data to delete
request:
MyModel.$delete({
params: {
id: id
},
data: {
some_parameter: 'some_value'
}
})
But in the developers console there is no request body. Am I missing something?
My model:
MyModel.methodConf = {
http: {
url: '/some-url'
},
methods: {
$delete: {
name: 'delete',
http: {
url: '/:id',
method: 'delete'
}
}
}
}
Config:
VuexORM.use(VuexORMAxios, {
database,
http: {
baseURL: 'some-endpoint',
url: '/',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
withCredentials: true
}
})
How can I serialize and deserialize data before saving to server and vuex?
I would like to be able to store on server json data.
For example:
class User extends Model {
static fields () {
return {
id: this.attr(null),
profile: this.jsonField(),
}
}
}
User.$create({
data: {
profile: {
imageUrl: 'http//example.com/image.jpg'
}
}
});
User.query().first().profile.imageUrl // => 'http//example.com/image.jpg'
For now I do:
User.$create({
data: {
profile: JSON.stringify({
imageUrl: 'http//example.com/image.jpg'
})
}
});
JSON.parse(User.query().first().profile).imageUrl // => 'http//example.com/image.jpg'
But it will be more convenient to make hidden serialization.
Related to #23 because also need some logic related to model before save data from API to vuex.
Hi,
I was playing around with Single Table Inheritance and found an issue with plugin-axios breaking custom fields on descendant models in STI.
My setup with STI:
import { Model } from "@vuex-orm/core";
export default class Post extends Model {
static entity = "posts";
static primaryKey = "id";
static types() {
return {
draft: DraftPost
};
}
static fields() {
return {
id: this.increment(),
title: this.string("")
};
}
}
export class DraftPost extends Post {
static entity = "draft_posts";
static baseEntity = "posts";
static fields() {
return {
...super.fields(),
customDraftAttr: this.attr("")
};
}
}
// database.js
const database = new VuexORM.Database();
database.register(Post);
database.register(DraftPost);
VuexORM.use(VuexORMAxios, { database });
const store = new Vuex.Store({
plugins: [VuexORM.install(database)]
});
When I insert a new Post with custom type the model instance is missing the fields defined in descendants of Post:
Post
.insert({ data: { type: 'draft', title: 'Foo', customDraftAttr: 'bar' } })
.then(data => console.log(data))
Object {posts: Array[1]}
posts: Array[1]
0: DraftPost
$id: 1
$isUpdating: false
$updateErrors: Array[0]
$isDeleting: false
$deleteErrors: Array[0]
id: 1
title: "Foo"
<constructor>: "DraftPost"
As you can see the customDraftAttr is not present on the model instances. When I disable plugin-axios, my custom fields work just fine:
// VuexORM.use(VuexORMAxios, { database });
Post
.insert({ data: { type: 'draft', title: 'Foo', customDraftAttr: 'bar' } })
.then(data => console.log(data))
Object {posts: Array[1]}
posts: Array[1]
0: DraftPost
$id: 1
id: 1
title: "Foo"
customDraftAttr: "bar"
<constructor>: "DraftPost"
I looked at the source code of the plugin and found that model fields are being somehow cached here:
plugin-axios/src/actions/Action.js
Lines 30 to 43 in 70cc314
I presume when the base model is installed, it caches fields for the base class so model.cachedFields
is already present on classes that inherit from the base model class.
Here's the repro sandbox: https://codesandbox.io/s/vuex-orm-sti-axios-bug-nl3vg
Cheers
Since vuex-orm is somewhat Laravel inspired, it would be great to be able to pass an array to "with"
User.with(['clothes', 'posts.comments'])
Here's the related documentation for Laravel
Cheers!
Line 18 in 2ed5dcd
Does this plugin support nested resources? If so are the any examples of this?
For example if I had a url like: /lists/:list_id/items/:item_id
If anyone else is getting the following warning in console:
Classic mode for store/ is deprecated and will be removed in Nuxt 3.
Edit store/index.js and change:
export default () => new Vuex.Store({
plugins: [VuexORM.install(database)]
})
to:
export const plugins = [VuexORM.install(database)]
See also nuxt/nuxt#4912
Currently there is no way to inject custom headers
My hot module replacement gets about factor 10 slower by including this library. I copied the library files into my own project and figured it get's fast again by including the individual lodash functions instead of the entire library. Here's an article about it.
So replacing all import _ from 'lodash';
(e.g. in the actions/Action.js
file) with import { merge, map, forEach, has } from 'lodash';
significantly improves build-performance.
Currently the http of methodconf is merged with the context http block.
Please also merge the http block of the method to allow for different configuration per method.
For example, the request headers need to be different for a POST vs GET.
Currently the only means of doing this is via transformRequest
in the methodconf http block. This feels hacky.
It would also be good to merge the http block passed to the method to allow per request customization of the config. ie.
MyModel.$fetch({
http: {
onUploadProgress(){...}
...
}
});
I am having issue with following code
Product.$create({
data: this.model
}).then(response => {
/*Commented code
Product.insert({
data: response.product
})
*/
console.warn("Response from api:", response) //Response is fine,
})
This plugin automatically should insertOrUpdate
after $create
as I've seen in the source code.
However, here is a breakdown. For some example commitInsert mutation data is not populated properly. It is templated model but without corresponding data. Everything seems fine but it just populate the store with empty no_key object. I tried to one more update with Commented Code and it works fine, but the commitInsert is populating for some reason no_key object. Where am I wrong?
Hi there, I've recently started using Vuex ORM with Axios Plugin and noticed that the dist/index.js
contains arrow function .some(t=>t in i)
, which ultimately breaks IE11. Also, after running my bundle thru webpack-bundle-analyzer
I noticed a bunch of extra dependencies like pako
, browserify-zlib
, and node-libs-browser
. I assume none of that should be in there. Not sure if its a broken build, or something else at fault. Can you please shed some light on this? Thanks!
I am new to vuex-orm and axios plugin and I am trying to get data from api and then access it in vuex store.
Data is successfully fetched from api with this:
mounted() {
User.$get({
query: {
offset: 0,
limit: 100
}
})
}
And then I am trying to access that data from vuex store with:
computed: {
users: () => User.all()
}
But this.users
doesnt contain fetched data. Just this:
[
{
"$id":"_no_key_1",
"$isUpdating":false,
"$updateErrors":[],
"$isDeleting":false,
"$deleteErrors":[],
"id":0,
"first_name":"",
"last_name":""
}
]
In vue dev tools I can see that it is not pushed in state.
How can I push it into state?
Thanks
When using this plugin in a project that is server-side rendered, we get the error ReferenceError: window is not defined
indist/index.js:1:278
, because window
does not exist in a server-side environment.
The plugin should be working with server-side rendering.
I noticed that the insertOrUpdate
method doesn't allow using a data function for nested properties. Without that, I am stuck using an if-else
statement with update and insert like so:
if (Project.find(id)) {
Project.update({
where: id,
data(project) {
project.permissions.canEdit = response.data.allowed;
}
});
} else {
Project.insert({
data: {
id,
permissions: {
canEdit: response.data.allowed
}
}
});
}
Is there any plan to support this in the future?
Thanks
the vue-orm core support typescript implementation, have any plan to add support on this plugin???
When I initialize VuexORMAxios I do not yet have my authorization token since the user isn't logged in yet at that point.
VuexORM.use(VuexORMAxios, {
database,
http: {
baseURL: (process.env.NODE_ENV === 'development' && !process.env.CORDOVA_PLATFORM)
? 'https://api.mydomain.dev' : 'https://api.mydomain.com',
url: '/',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
},
});
Then when I try to perform a $fetch operation on one of my orm models, I get "token not provided"
If I pass the token as a get query parameter then it works but I would prefer not to do that and pass it as a header.
Can I add a header to this axios plugin after it's already been initialized?
Or else what is the best practice for including an authorization header with every axios call?
Thank you..
Frameworks like Laravel often have built in pagination methods, which in turn change the default return data from the API. plugin-axios
current $fetch
method requires that the model data is in the root of the response array, however Laravel's pagination method returns something like the following, with the data nested in the response:
{
current_page: 1,
data: [
{ ID: 512, FirstName: 'Bob', LastName: 'Smith' },
{ ID: 747, FirstName: 'Ryan', LastName: 'Mack' },
...
],
first_page_url: "http://example.test/api/users?page=1",
from: 1,
last_page: 215,
last_page_url: "http://example.test/api/users?page=215",
next_page_url: "http://example.test/api/users?page=2",
path: "http://example.test/api/users",
per_page: 75,
prev_page_url: null,
to: 75,
total: 16113
}
It is necessary that this data is paginated server side, as you can see there is a total of 16113
records, which in reality have many more columns and each have their own relationships.
Would it be possible to cater for this by including some configuration (either globally or within each model, maybe even just as simple as paginated: true
would be amazing) where you could specify the expected response structure, or key of the data or something? It would be great if the pagination keys could be stored too, although would not need to be queried in the same way as the data.
At the moment I simply can't use this as half of my API routes return paginated data, which I'm sure is common. I've tested a route without it and it works perfectly so thank you for this, huge huge help with working with a large scale SPA.
Maybe even be as simple as changing this in Fetch.js
from:
static onSuccess(commit, model, data) {
commit('onSuccess')
model.insertOrUpdate({
data,
});
}
To this:
static onSuccess(commit, model, data) {
commit('onSuccess')
if (model.paginated) {
model.insertOrUpdate(data);
} else {
model.insertOrUpdate({
data
})
}
}
But I'm unsure of what other side effects this may have or what exactly insertOrUpdate
is expecting.
Many thanks in advance.
EDIT: Have since tried the insertOrUpdate
part in the promise returned from $fetch
, this got the data working great (albeit with an empty default record at index 0) but doesn't populate any of the pagination values, even after manually specifying the keys in each model's state.
In the readme, there is a reference to database
:
import database from './database'
Presumably the user has to create this module. But what is it meant to contain? There's a real gap in the documentation here.
for example
const m = new MyModel();
m.$update({params:{id:123}, data:{mydata:'abc'}}); //Doesn't fire put request
MyModel.$update({params:{id:123}, data:{mydata:'abc'}}); //Works as expected
Hey folks, there was no update for 1 1/2 months and there are 8 open pull requests. Are you guys looking for maintainers by any chance?
Example: we have a simple Vue component code to load an image
...
methods: {
async upload(event) {
let data = new FormData()
data.append('file', this.takeFileFromInput(event, 'image.*'))
let image = await FileModel.$create({data})
this.$emit('input', image.id || null)
},
...
But it won't work because in the file @vuex-orm\plugin-axios\src\support\interfaces.js
has a field with an empty Data object, which is passed by default
plugin-axios/src/support/interfaces.js
Line 41 in 2ed5dcd
I'm getting "unknown action type: entities/positions/$fetch" when calling Position.$fetch();
:
import { Position } from '@/entities/Position';
Position.$fetch();
Position.$get({
params: {
id: 1
}
});
Position
model:
export class Position extends Model {
static entity = 'positions';
static fields() {
return {
id: this.attr(null),
title: this.attr(''),
};
}
}
positions
module:
export const positions = {};
database.js
:
import { Database } from '@vuex-orm/core';
import { Position, positions } from './Position';
const database = new Database();
database.register(Position, positions);
export default database;
The rest of the elements (Model methods, state module, initial state and getters) are all created:
Hello
i cannot override axios instance
i found bug , the promise not return with ajax original response.
export default ({ $axios }) => {
VuexORM.use(VuexORMAxios, {
database,
http: {
axios: $axios
}
})
})
TEST.$create({
data: { }
})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error)
})
Thank you
As many people are probably already using Axios in their project, it would be nice to allow us to inject an already existing instance of Axios as opposed to providing a new config all over.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.