VueJS Vuex Axios cURL API for Wordpress - api

I'm using Vuex to make all my API calls and since the beginning the doc was giving example of HTTP requests for displaying posts. But when it comes to CRUD the examples mention cURL requests instead of HTTP ones. It's the first time I'm working with API and I don't know if the syntax/the way I called the API since now is reusable for cURL API. Here's my code so far.
state: {
posts: [],
cats: [],
},
actions: {
async fetch({ commit }) {
try {
const data = await axios.get(
"http://localhost:8080/wp-json/wp/v2/posts"
);
const data2 = await axios.get(
"http://localhost:8080/wp-json/wp/v2/categories"
);
commit("SET_posts", data.data);
commit("SET_cats", data2.data);
} catch (error) {
alert(error);
console.log(error);
}
},
},
mutations: {
SET_posts(state, posts) {
state.posts = posts;
},
SET_cats(state, cats) {
state.cats = cats;
},
},
And the API call example that deletes a post
curl -X DELETE https://example.com/wp-json/wp/v2/posts/<id>
I guess I have to create another function with at least one argument/parameter since we have to pass the id to make the api call work.
It's the first time I'm using Vuex and the first time I'm using API, sorry if what I'm asking for is obvious...

Add a new action:
actions: {
async fetch({ commit }) {
...
},
async deletePost({ dispatch }, postId) {
await axios.delete(
`http://localhost:8080/wp-json/wp/v2/posts/${postId}`
);
// fetching posts again after delete is completed
await dispatch('fetch');
},
}

Related

Nuxt + axios ...how to add {{this.$route.params}} in axios url?

Hello im trying to add {{this.$route.params}} to my axios url for get the data on dedicated profil pages.
here is the part i want to add in axios url the "id" :
The Axios code from 'RikLamers' who explain me how to get data, it is where i want to add "this.$route.params" :
data() {
return {
results: [],
}
},
async mounted() {
await axios.get(`API url" ${to.params.id}`)
.then(response => {this.results = response.data.content})
},
but i mistake somewhere, hope someone can explain me ?
You can access URL param using this.$route.params.id. Use try catch, when you use await.
data() {
return {
results: [],
}
},
async mounted() {
try {
const response = await axios.get(`[Your API URL]/${this.$route.params.id}`)
this.results = response.data.content
catch (e) {}
},

Nuxt.js - The best place for API calls

I'm new to Vue.js Nuxt and all front-end stuff.
I have a question about API calls. I'm not sure what is the right way, the best practice here.
I have a store. In that store, I have actions that are calling my API and sets state eg.
async fetchArticle({ state, commit }, uuid) {
const response = await this.$axios.get(`articles/${uuid}/`)
commit('SET_ARTICLE', response.data)
},
And that is fine it is working for one component.
But what if I want to just fetch the article and not changing the state.
To be DRY first thing that comes to my mind is to create the service layer that is fetching the data and is used where it is needed.
Is it the right approach? Where can I find some real-world examples that I can take inspiration from?
Using the repository pattern to abstract your API is definitely a good idea! Whether you use the #nuxtjs/axios module or the #nuxt/http module, you can pass either instance to your repository class/function. Below a real world example of an abstracted "repository.js" file.
export default $axios => resource => ({
index() {
return $axios.$get(`/${resource}`)
},
create(payload) {
return $axios.$post(`/${resource}`, payload)
},
show(id) {
return $axios.$get(`/${resource}/${id}`)
},
update(payload, id) {
return $axios.$put(`/${resource}/${id}`, payload)
},
delete(id) {
return $axios.$delete(`/${resource}/${id}`)
}
})
You can then create a plugin to initialize all different kinds of repositories for your endpoints:
import createRepository from '~/path/to/repository.js'
export default (ctx, inject) => {
const repositoryWithAxios = createRepository(ctx.$axios)
const repositories = {
posts: repositoryWithAxios('posts'),
users: repositoryWithAxios('users')
//...
}
inject('repositories', repositories)
}
Further read: Organize and decouple your API calls in Nuxt.js
I will an example of a service layer implementation for my portfolio to create my dashboard that shows some statics about my github and stackoverflow profiles, to do this i created a folder called services inside the project root :
pages
services
|_AxiosConfig.js
|_GitHubService.js
|_StackoverflowService.js
...
in the AxiosConfig.js file i put i created an axios instance with its configuration :
import axios from 'axios';
const clientAPI = url =>
axios.create({
baseURL: url,
withCredentials: false,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
});
export default clientAPI;
then in my GitHubService.js i imported that axios instance called clientAPI which i used to my requests :
import clientAPI from './AxiosConfig';
const baseURL = 'https://api.github.com';
export default {
getUser(name) {
return clientAPI(baseURL).get('/users/' + name);
},
getRepos(name){
return clientAPI(baseURL).get('/users/' + name+'/repos');
},
getEvents(name,page){
return clientAPI(baseURL).get('/users/' + name+'/events?per_page=100&page='+page);
},
getLastYearCommits(name,repo){
return clientAPI(baseURL).get('/repos/' + name+'/'+repo+'/stats/commit_activity');
}
};
then in my page i used asyncData hook to fetch my data :
import GitHubService from '../../services/GitHubService'
export default {
...
async asyncData({ error }) {
try {
const { data } = await GitHubService.getUser("boussadjra");
const resRepos = await GitHubService.getRepos("boussadjra");
return {
user: data,
repos: resRepos.data
};
} catch (e) {
error({
statusCode: 503,
message: "We cannot find the user"
});
}
}
I wanted to use axios in my service/service.js file, so instead of passing axios, I accessed it directly like this:
export default {
async fetchArticle() {
let response = await $nuxt.$axios.$get('/api-url')
return response
},
}
In Nuxt, if you want to just get the data without keeping it in your store, you could use the asyncData function, which asynchronously loads data (from API calls and the like) and pushes it into the component's data object before rendering.

Update a data in database using vuex

I'm struggling to implement an EDIT_DETAILS feature in vuex but I can implement this without using vuex but I prefer to use vuex because I am practicing my vuex skills.
Below snippets are the code that I am using to make my edit feature work.
this is in my profile.vue
editUser(id) {
this.id = id;
let details = {
id: this.id,
FULL_NAME: this.personDetails[0].FULL_NAME,
EMAIL: this.personDetails[0].EMAIL
};
//this will pass the details to my actions in vuex
this.editDetails(details);
}
personDetails, just retrieves the details of my user in my database.
id is the user number which is the primary key of my table in my backend.
below is the example json came from my database
this is my action in my vuex:
async editDetails({ commit }, payload) {
try {
const response = await axios.put("http:/localhost:9001/profile/edit/" + payload);
commit("EDIT_DETAILS", response.data);
} catch (err) {
console.log(err);
}
}
and this is my mutation:
EDIT_DETAILS(state, detail) {
state.details.findIndex((param) => param.id === detail);
let details = state.details
details.splice(details.indexOf(detail), 1)
state.details = details.body
}
and my state:
details: [],
Use a comma instead of plus in your axios request
Not sure what your response is but this does nothing
state.details.findIndex((param) => param.id === detail);
You need to push into array if not exists

Axios GET not including params in Nuxt template

I want to pass an id to axios so that I can switch url dynamically.
My axios request in my template is as follows:
async asyncData({ params }) {
const { data } = await axios.get('http://localhost:8000/api/', {
params: {
id: 1
}
})
return { data }
}
The request being passed to my api is:
GET /api/?id=1
but I need
GET /api/1
What is happening here?
It looks like the asyncData function is called once when the page is loaded. I am still no wiser as to why it does not accept params in the way outlined in the docs and numerous tutorials, but it would not refresh the page because it is never called again.
To refresh the page data with a new api call, you need to return the axios promise from within the methods part of the export. The code below does the axios get request first, then adds or subtracts 1 from the id with plus and minus functions.
<script>
import axios from 'axios'
export default {
head() {
return {
title: 'Weather'
}
},
data: function() {
return { counter: 1 }
},
methods: {
plus: function(counter, data, datalength) {
this.counter += 1
axios.get('http://localhost:8000/api/' + this.counter).then(res => {
console.log(this.counter)
console.log(res.data)
return (this.data = res.data)
})
},
minus: function(counter, data) {
if (this.counter >= 2) {
this.counter -= 1
axios.get('http://localhost:8000/api/' + this.counter).then(res => {
console.log(this.counter)
console.log(res.data)
return (this.data = res.data)
})
} else {
this.counter = 1
}
}
},
async asyncData({ params, counter }) {
let { data } = await axios.get('http://localhost:8000/api/1')
return { data }
}
}
</script>
If anybody wants to elaborate or post a better solution, please go ahead - but I'm posting this because I searched so many tutorials and nothing worked until I found a way to interpret the documentation, which is certainly not beginner-friendly.

Unit testing HTTP request with Vue, Axios, and Mocha

I'm really struggling trying to test a request in VueJS using Mocha/Chai-Sinon, with Axios as the request library and having tried a mixture of Moxios and axios-mock-adaptor. The below examples are with the latter.
What I'm trying to do is make a request when the component is created, which is simple enough.
But the tests either complain about the results variable being undefined or an async timout.
Am I doing it right by assigning the variable of the getData() function? Or should Ireturn` the values? Any help would be appreciated.
Component
// Third-party imports
import axios from 'axios'
// Component imports
import VideoCard from './components/VideoCard'
export default {
name: 'app',
components: {
VideoCard
},
data () {
return {
API: '/static/data.json',
results: null
}
},
created () {
this.getData()
},
methods: {
getData: function () {
// I've even tried return instead of assigning to a variable
this.results = axios.get(this.API)
.then(function (response) {
console.log('then()')
return response.data.data
})
.catch(function (error) {
console.log(error)
return error
})
}
}
}
Test
import Vue from 'vue'
import App from 'src/App'
import axios from 'axios'
import MockAdapter from 'axios-mock-adapter'
let mock = new MockAdapter(axios)
describe('try and load some data from somewhere', () => {
it('should update the results variable with results', (done) => {
console.log('test top')
mock.onGet('/static/data.json').reply(200, {
data: {
data: [
{ id: 1, name: 'Mexican keyboard cat' },
{ id: 2, name: 'Will it blend?' }
]
}
})
const VM = new Vue(App).$mount
setTimeout(() => {
expect(VM.results).to.be.null
done()
}, 1000)
})
})
I am not sure about moxios mock adaptor, but I had a similar struggle. I ended up using axios, and moxios, with the vue-webpack template. My goal was to fake retreiving some blog posts, and assert they were assigned to a this.posts variable.
Your getData() method should return the axios promise like you said you tried - that way, we have some way to tell the test method the promise finished. Otherwise it will just keep going.
Then inside the success callback of getData(), you can assign your data. So it will look like
return axios.get('url').then((response) {
this.results = response
})
Now in your test something like
it('returns the api call', (done) => {
const vm = Vue.extend(VideoCard)
const videoCard = new vm()
videoCard.getData().then(() => {
// expect, assert, whatever
}).then(done, done)
)}
note the use of done(). That is just a guide, you will have to modify it depending on what you are doing exactly. Let me know if you need some more details. I recommend using moxios to mock axios calls.
Here is a good article about testing api calls that helped me.
https://wietse.loves.engineering/testing-promises-with-mocha-90df8b7d2e35#.yzcfju3qv
So massive kudos to xenetics post above, who helped in pointing me in the right direction.
In short, I was trying to access the data incorrectly, when I should have been using the $data property
I also dropped axios-mock-adaptor and went back to using moxios.
I did indeed have to return the promise in my component, like so;
getData: function () {
let self = this
return axios.get(this.API)
.then(function (response) {
self.results = response.data.data
})
.catch(function (error) {
self.results = error
})
}
(Using let self = this got around the axios scope "problem")
Then to test this, all I had to do was stub the request (after doing the moxios.install() and moxios.uninstall for the beforeEach() and afterEach() respectively.
it('should make the request and update the results variable', (done) => {
moxios.stubRequest('./static/data.json', {
status: 200,
responseText: {
data: [
{ id: 1, name: 'Mexican keyboard cat' },
{ id: 2, name: 'Will it blend?' }
]
}
})
const VM = new Vue(App)
expect(VM.$data.results).to.be.null
VM.getData().then(() => {
expect(VM.$data.results).to.be.an('array')
expect(VM.$data.results).to.have.length(2)
}).then(done, done)
})