43

I'm currently working on a new Vue.js application. It depends heavily on api calls to my backend database.

For a lot of things I use Vuex stores because it manages shared data between my components. When looking at other Vue projects on github I see a special vuex directory with files that handles all the actions, states and so on. So when a component has to call the API, it includes the actions file from the vuex directory.

But, for messages for example, I don't want to use Vuex because those data is only important for one specific view. I want to use the component specific data here. But here is my problem: I still need to query my api. But I shouldn't include the Vuex actions file. So in that way I should create a new actions file. This way I have a specific file with api actions for vuex and for single components.

How should I structure this? Creating a new directory 'api' that handles actions for both vuex data and component-specific data? Or separate it?

Jordy
  • 4,719
  • 11
  • 47
  • 81
  • Simply put the call inside the component and not store the result in vuex since it's only for this component? – JJPandari Nov 26 '16 at 04:32
  • 1
    Yes but how to structure my files? Should I create two different actions files? One for vuex, one for component specific? Or merge them? – Jordy Nov 26 '16 at 09:23

3 Answers3

35

I am using axios as HTTP client for making api calls, I have created a gateways folder in my src folder and I have put files for each backend, creating axios instances, like following

myApi.js

import axios from 'axios'
export default axios.create({
  baseURL: 'http://localhost:3000/api/v1',
  timeout: 5000,
  headers: {
    'X-Auth-Token': 'f2b6637ddf355a476918940289c0be016a4fe99e3b69c83d',
    'Content-Type': 'application/json'
  }
})

Now in your component, You can have a function which will fetch data from the api like following:

methods: {
 getProducts () {
     myApi.get('products?id=' + prodId).then(response =>  this.product = response.data)
  }
}

Similarly you can use this to get data for your vuex store as well.

Edited

If you are maintaining product related data in a dedicate vuex module, you can dispatch an action from the method in component, which will internally call the backend API and populate data in the store, code will look something like following:

Code in component:

methods: {
 getProducts (prodId) {
     this.$store.dispatch('FETCH_PRODUCTS', prodId)
  }
}

Code in vuex store:

import myApi from '../../gateways/my-api'
const state = {
  products: []
}

const actions = {
  FETCH_PRODUCTS: (state, prodId) => {
    myApi.get('products?id=' + prodId).then(response => state.commit('SET_PRODUCTS', response))
  }
} 

// mutations
const mutations = {
  SET_PRODUCTS: (state, data) => {
    state.products = Object.assign({}, response.data)
  }
}

const getters = {
}

export default {
  state,
  mutations,
  actions,
  getters
}
Saurabh
  • 71,488
  • 40
  • 181
  • 244
  • And where do you save the actions regarding Vuex? For example to add new data into Vuex? Do you have an actions.js in the Vuex folder. Or do you do that inside each component? – Jordy Nov 26 '16 at 09:57
  • Vuex related code is separate, you are choose how to arrange it, one way can be like this in [cart example](https://github.com/vuejs/vuex/tree/dev/examples/shopping-cart/store), I don't have dedicated actions file, I have different vuex module with their actions, mutations etc in one file. – Saurabh Nov 26 '16 at 10:03
  • So inside `getProducts()` in your component you call an action to update the Vuex store? – Jordy Nov 27 '16 at 13:10
  • @Jordy Yes, If I am maintaining data in `productStore` than I can trigger a `mutation` here, or I can `dispatch` an `action` from `getProducts()` which will call backend API and trigger the mutation. – Saurabh Nov 27 '16 at 13:23
  • @Saurabh Thank you for the answer! For how long do you keep stale data in the Vuex store? When would you decide to retrieve current data from a server? – Ivan Mushketyk Sep 23 '17 at 16:12
  • What happen when I want to show information in a modal. It's not necessary in the store. What can I do in this case? Should I access the API from my component? Or should I use store to save temporal data? @Saurabh – joseglego Mar 07 '18 at 16:11
  • I like your first answer, without the Vuex. I struggled to import the axios.create into my component. I would advise placing the code for that, I wasted around 30 mins trying to do it. I had to create a new name in the import like import getData from "../service/apiCalls"; then call that name like a function getData.get(...) – artworkjpm Dec 08 '19 at 16:20
6

Note: vue-resource is retired ! Use something else, such as Axios.

I'm using mostly Vue Resource.I create services directory, and there put all connections to endpoints, for e.g PostService.js

import Vue from 'vue'

export default {
  get(id) {
    return Vue.http.get(`/api/post/${id}`)
  },
  create() {
    return Vue.http.post('/api/posts') 
  }
  // etc
}

Then in my file I'm importing that service and create method that would call method from service file

SomeView.vue

import PostService from '../services/PostService'

export default {
  data() {
    item: []
  },
  created() {
    this.fetchItem()
  },
  methods: {
    fetchItem() {
      return PostService.get(to.params.id)
        .then(result => {
          this.item = result.json()
        })
    }  
  }
}
Belmin Bedak
  • 9,011
  • 2
  • 40
  • 44
5

Based on concept of Belmin Bedak`s answer, i have wrapped it all into a simple library:

https://github.com/robsontenorio/vue-api-query

You can request your API like this:

All results

// GET /posts?filter[status]=ACTIVE

let post = await Post
  .where('status', 'ACTIVE')
  .get()

Specific result

// GET /posts/1

let post = await Post.find(1)

Editing

// PUT /posts/1 

post.title = 'Awsome!'
post.save()

Relationships

// GET /users/1
let user = await User.find(1)

// GET users/1/posts
let posts = await user
  .posts()
  .get()