Giter Site home page Giter Site logo

vuex-orm / plugin-axios Goto Github PK

View Code? Open in Web Editor NEW
361.0 17.0 53.0 4.03 MB

Vuex ORM persistence plugin to sync the store against a RESTful API.

Home Page: https://vuex-orm.github.io/plugin-axios/

License: MIT License

JavaScript 17.73% TypeScript 82.27%
axios vue vuex vuex-orm vuex-orm-plugin vuex-plugin

plugin-axios's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

plugin-axios's Issues

Add query param to $fetch

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?

Custom methods in methodConf

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

sharing with the plugin vuex-orm-localforage

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:

1. plugin-axios:

Model Methods

import User from '../models/User';

/**
 * @uri `/users`
 */
User.$fetch();

2. vuex-orm-localforage

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

Better uri merge strategy

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):

  • uri matches ^[^:]+:// discard current and return uri
  • uri matches ^/ discard current and return uri (axios will apply baseURL)
  • uri matches ^[^/] append to current uri value with '/'

Unable to add params to fetch

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!

Get parameter array with key value

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

if (config.query) endpoint += `?${Object.keys(config.query).map(k => `${encodeURIComponent(k)}=${encodeURIComponent(config.query[k])}`).join('&')}`;
and does not allow to deal with array as params right ?

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

Using Plugin with quasar framework

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.

error handling

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:
image

What can be done to catch the promise nicely?

Best greets,
Mario Minati

Events methods for models

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

Cross-domain requests from node go to 127.0.0.1:80

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.

Unify config structure

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

$delete call the action but does not remove from the store

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

Interceptors

How i can configure a interceptor for example refresh a token?

All actions should return the model

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();

Mutating data from an API call

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

Migration examples from version < 0.7

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

Repeated response handlers when working with provided Axios instance

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.

Patch method / missing config implementation of "http.method"

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?

Fetch data with async await in nuxt.js

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.

Better params handling

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

Usage with axios-extensions cacheAdapterEnhancer

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?

How can I attach data to $delete request?

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
  }
})

Serialization

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.

Plugin axios breaks Single Table Inheritance custom model fields

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:

model.getFields = () => {
if (!model.cachedFields) {
model.cachedFields = merge({}, {
$id: model.attr(undefined),
$isUpdating: model.boolean(false),
$updateErrors: model.attr([]),
$isDeleting: model.boolean(false),
$deleteErrors: model.attr([]),
}, model.fields());
}
return model.cachedFields;
};

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

Nested Resources Support

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

Slow HMR due to full lodash imports

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.

Merge http of method

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(){...}
        ...
    }
});

_no_key_

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.

nokey

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?

Broken IE11 and extra dependencies in Webpack output

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!

Access data in store

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.
gnome-shell-screenshot-T6D46Z

How can I push it into state?

Thanks

Data function support for insertOrUpdate method

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

Improper use of asyncronous method

The promise created here should be returned and awaited on after awaiting here rather than calling .then.

The current behavior causes a race condition when awaiting any action and then querying the store for the result.

how to use with JWT token Bearer Authorization

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..

Support different API response structures (for pagination)

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.

What is "database"

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.

Is this still maintained?

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?

Attach an image with FormData when using the $create model method [Axios instance]

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

Actions not created

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:
2018-10-08_09-24-31

override axios instance doesn't work

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

Allow injecting existing Axios instances

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.