How are you organizing your API calls? Have you considered API factories to make your codebase easier to work with, increasing your team’s productivity?
A while back, I shared a few tips on how you can build and maintain a large Vue.js project. One of them was to use API factories (also known as API modules) to organize your code. In this article, we will dig a little deeper so you can better understand and use this structure in your work.
Do you follow a special convention to organize your API calls inside your application❓
If you don’t … ♀ Well, you need to read this! Because, I really do believe that this structure will benefit your team and all your future colleagues.
How? API factories will make your codebase easier to understand and so it will end up increasing everyone’s productivity. ⏱
Why You Should Use API Factories in Your Project
In a nutshell, API factories offer some significant advantages to developers who use them:
-
This practice gathers all your endpoints inside one or multiple modules. Thus, they are not scattered randomly inside your project, and everyone can quickly have a glimpse of every endpoint the application is using.
-
When you make a change to one endpoint, you only have to update it in one place. You will be more confident in your code, and it will prevent you from breaking your application.
-
If you need to reuse your API modules in multiple projects, you can package them with npm.
-
By comparing your backend API routes with your frontend API factories side by side, you can quickly identify all the endpoints that you do not call anymore. Your application becomes one bit easier to maintain by removing all the unused code.
-
You can make all your API factories available from anywhere in your app by defining a new property to the Vue instance. Each endpoint will be accessible with something like this.$api.myModule.myEndpoint()
. (Go to the end of the article—part 3—to learn more about how to properly proceed with Vue and Nuxt.)
Let's see how to get API factories up and running in our app.
1. Installing Axios
In the following example, for Vue.js and Nuxt.js, respectively, we will use the Axios library to fetch our API.
Here is how you can install it and making it globally available inside your application:
Vue.js
npm install --save axios vue-axios
// src/main.js
import Vue from "vue";
import axios from "axios";
import VueAxios from "vue-axios";
Vue.use(VueAxios, axios);
⚠️ Note: In Vue.js, you can access Axios with this.axios
or this.http
.
Nuxt.js
npm install @nuxtjs/axios
// nuxt.config.js
module.exports = {
modules: ["@nuxtjs/axios"]
};
⚠️ Note: In Nuxt.js, you can access Axios with this.$axios
.
2. Gathering All Your Endpoints Inside One or Multiple Modules
Create an api
folder (you can call it anything you want).
And yes! You guessed it, buddy: We will store all our API modules inside it.
⚠️ If you are using Vue, this should be in src
. On the other hand, Nuxt users will have to place that folder directly at the root of the project.
api
├── auth.js
├── blog.js
├── ..
└── settings.js
Each module will host all the endpoints associated to its given feature. Here is how it could look like for an auth
module.
// api/auth.js
export default axios => ({
forgotPassword(email) {
return axios.post("/auth/password/forgot", { email });
},
login(email, password) {
return axios.post("/auth/login", { email, password });
},
logout() {
return axios.get("/auth/logout");
},
register(payload) {
return axios.post("/auth/register", payload);
},
resetPassword(password, passwordConfirmation, resetToken) {
return axios.post("/auth/password/reset", {
password: password,
password_confirmation: passwordConfirmation,
token: resetToken
});
}
});
The critical thing here is to keep in mind that the axios
instance is passed in every module.
Of course, you’re asking why. ♀ So that each function can fetch API endpoint related to it. Besides, as it returns a promise, we will be able to use the await
keyword when calling them.
3. Making Your API Factories Available Everywhere in Your App
Now that you have a better idea of how you can create an API module, let’s dive into how we can make them available throughout your app.
Vue.js
First, create an api.js
file inside your src
folder and import all your API modules inside.
Then, make sure you are also importing Vue
, so that you can pass the Axios instance to each factory (as explained above).
// src/api.js
import Vue from "vue";
import Auth from "@/api/auth";
import Blog from "@/api/blog";
import Settings from "@/api/settings";
// Initialize all or API factories
const factories = {
auth: Auth(Vue.axios),
blog: Blog(Vue.axios),
settings: Settings(Vue.axios)
};
// Make them available in the app with this.$api
// https://vuejs.org/v2/cookbook/adding-instance-properties.html
Vue.$api = factories;
Finally, import the api.js
inside your main.js
file.
// src/main.js
// NPM
import Vue from "vue";
import axios from "axios";
import VueAxios from "vue-axios";
// PROJECT
import "@/api.js";
Vue.use(VueAxios, axios);
⚠️ Because Nuxt.js can also run code on the server side, the process is a little different than with a standard Vue application.
Nuxt.js
If you are not familiar with what a combined injection is with Nuxt, I suggest you read this part of the documentation before going further.
But because I’m nice, I’m still going to tell you what it is. In a nutshell, a combined injection allows you to access any function inside any of your components, (wait for it) as well as inside your Vuex modules (which will be really handy in your dispatchers).
To make get it to work, though, we need to create a plugin.
// plugins/api.js
import Auth from "@/api/auth";
import Blog from "@/api/blog";
import Settings from "@/api/settings";
export default (context, inject) => {
// Initialize API factories
const factories = {
auth: Auth(context.$axios),
blog: Blog(context.$axios),
settings: Settings(context.$axios)
};
// Inject $api
inject("api", factories);
};
And now, all you have left to do is to register the plugin like any other one you’d use. ⚠️ But make sure you are not restricting it to the client mode.
// nuxt.config.js
module.exports = {
plugins: [{ src: "@/plugins/api.js" }]
};
4. How to Use Your API Factories Now
Congratulation, we made it!
Now, here is an example of how we can log the response into our app.
<template>
<div>
<input v-model="email" type="text" placeholder="email" />
<input v-model="password" type="password" placeholder="password" />
<button @click="onLogin">Login</button>
</div>
</template>
<script>
export default {
data() {
return {
email: "",
password: ""
};
},
methods: {
async onLogin() {
const response = await this.$api.auth.login(this.email, this.password);
console.log(response);
}
}
};
</script>
I hope this structure will help you to better organize your API calls in your next project. I use it inside each of my client projects, and I’ve never had any issue with it.
If you have any questions or even have a suggestion to improve this structure, please feel free to let me know in the comments or on Twitter @RifkiNada.