DEV Community

loading...
Cover image for Nuxt like a pro. Use service pattern (My Best practice)

Nuxt like a pro. Use service pattern (My Best practice)

radonirinamaminiaina profile image Radonirina Maminiaina ・Updated on ・2 min read

Intro

We all know that NuxtJS is an awesome framework. Unlike Angular which has a well structured folder for services, nuxt doesn't. But like every good nuxt developer, using services are essential, especially when you use VueX with NuxtJS.

Implementation of services in Nuxt

Before we implement services, make sure you have vuex, nuxtjs/axios installed in your project.

Into the plugins directories, create a new file (e.g: service.js)

export default ({$axios}, inject) => {
  inject('getProductList', async (params) => await $axios.get('cool_get_url', {
    params
  }))
  inject('createProduct', async (data) => await $axios.post('cool_post_url', data))
  // ... and so on
}
Enter fullscreen mode Exit fullscreen mode

So, in our Nuxt Component, we can access those service within the context this.

<template>
  <div><!-- Make a liste of product--></div>
</template>

<script>
  export default {
    name: 'MyAwesomeProduct',
    async mounted() {
      // accessing $getProductList service using this
      const { data } = this.$getProductList({type: 'awesome type'})

      // accessing $createProduct service
      const { data } = this.$createProduct({
        name: 'awesome product'
      })

    }
  }
</script>
Enter fullscreen mode Exit fullscreen mode

Or if your system is more complicated, and you use vuex, you can access those service within vuex store as well.

export default {
  // some basic store configuration
  actions: {
    async getProductList({ commit }) {
      const { data } = this.$getProductList({type: 'awesome type'})
      // data manipulation before commit ...
      commit('MY_AWESOME_MUTATION', data)
    },
    async createProduct({ commit }) {
      const { data } = this.$createProduct({type: 'awesome type'})
      // data manipulation before commit ...
      commit('MY_AWESOME_MUTATION', data)
    },
  }
}
Enter fullscreen mode Exit fullscreen mode

And within your component, you can use MapGetters to retrieve data after calling the action using MapActions

Let refactor the code, My Best Practice

Now, time is coming, so let rewrite those services.
In the root of your project, you can create a folder called services, and within that folder, create a new file named product.js (If you like, you can prefix it with service πŸ˜‰ ). Here the content of that file:

export default ($axios) => {
  getProductList: async  (params) => {
    return await $axios.get('cool_get_url', {
      params
    })
  },
  createProduct: async  (data) => {
    return await $axios.post('cool_post_url', data)
  }
  // more verbs and more actions
}
Enter fullscreen mode Exit fullscreen mode

Now, the file [service.js] within the plugins will look like this:

import productService from '~/services/product'

export default ({ $axios }, inject) => {
  const allMethods = {
    ...productService($axios),
    // import another service here
  }
  const methods = Object.keys(allMethods)
  methods.forEach((method) => {
    inject(method, allMethods[method])
  })
}

Enter fullscreen mode Exit fullscreen mode

We know that Object.keys(allMethods) that it will returns the keys of allMethods, and then, we use those key, as the name of our services, and allMethods[method] will return the methods within the services.
Now inject will contains small code, and it's more clear.
Our services are separated in new file.

Pros

  • Separation of concern
  • Clean code
  • Easy for e2e testing
  • Easy for unit testing

Cons

  • More files to handle
  • (Put in comments if you find another cons with this approach)

Now for deployment you can read this article which is about optimisation.

Note: I repeat it again, it's my own best practice that I use for any of our projects. If you find it usefull, feel free to use it. πŸ˜‡

Discussion (12)

pic
Editor guide
Collapse
bacodekiller profile image
Quang Hiep • Edited

how to use it with Interceptors axios for refresh token when "token is invalid"? And save token, refresh token to cookies?

Collapse
radonirinamaminiaina profile image
Radonirina Maminiaina Author

You can use interceptor and in onResponse you can check if your token is valid or not.

Collapse
bacodekiller profile image
Quang Hiep

yes. when refresh token success but should I save token to vuex or cookies? thanks.

Thread Thread
radonirinamaminiaina profile image
Radonirina Maminiaina Author

The simplest way is using localstorage to save your token.

Thread Thread
bacodekiller profile image
Quang Hiep

But localStorage is client-side. How can i save it from server nuxtjs?

Thread Thread
radonirinamaminiaina profile image
Radonirina Maminiaina Author

You can use this lib and use cookie for saving the info within nuxt server

Thread Thread
bacodekiller profile image
Quang Hiep

can you give an example using lib or project using lib? tks you

Thread Thread
radonirinamaminiaina profile image
Collapse
geminii profile image
Jimmy

It’s a great best practices that i apply on my project but i precise a prefix due to multiple services. Nice sharing πŸ‘

Collapse
radonirinamaminiaina profile image
Collapse
patarapolw profile image
Pacharapol Withayasakpunt

I use openapi-client-axios + openapi.json (i.e. Swagger) + TypeScript (optional).

But I don't know how to inject to $axios.

Collapse
radonirinamaminiaina profile image
Radonirina Maminiaina Author

You can use nuxtjs/axios module and follow the installation intruction