Getting ActiveCampaign API results to frontend in nuxt/vue app - vue.js

I seem to be misunderstanding something about either the API I'm working with or how nuxt works.
Tools
ActiveCampaign API
NuxtJS
Goal
I just want to get all contacts stored in my ActiveCampaign Account and display them on the frontend.
Current Solution
components/contactList.vue
<script setup>
const contactList = await useFetch('/api/contacts')
</script>
<template>
<h1>ActiveCampaign Contact</h1>
{{ contactList }}
</template>
server/api/contacts.vue
const options = {
method: 'GET',
headers: {
Accept: 'application/json',
'Api-Token': 'MY-API-TOKEN'
}
};
const contactList = fetch('https://MY-DOMAIN.api-us1.com/api/3/contacts?status=-1&orders[email]=ASC', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));
export default () => contactList;
Problem
I'm getting the results in my console (so I suppose on the server-side of nuxt).
How do I display them on the frontend? I'm getting nothing here.

Related

Using computed and composables in vue 3.2 with the setup script tag

I'm currently trying out some of the latest vue version and features (3.2).
I've created a useFetch composable to reuse some logic (it's based on the vue documentation)
useFetch.js
import { ref } from 'vue'
import axios from 'axios';
const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_ENDPOINT,
withCredentials: false,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
timeout: 10000,
});
export function useFetch(url) {
const data = ref(null);
const error = ref(null);
const isLoading = ref(true);
apiClient({ method, url, data: body })
.then((response) => (data.value = response.data))
.catch((err) => (error.value = err))
.finally(() => isLoading.value = false)
return { data, error }
}
I'm using the useFetch composable in a component to fetch companies from the backend. The data I'm getting back is rough so I want to reformat it using a computed (That was the way I did it when using vue 2)
CompanyList.vue
<script setup>
import { computed } from 'vue';
import useFetch from '#/composables/useFetch';
import { formatEmail, formatPhone, formatEnterpriseNumber } from '#/utils/formatters';
const { data, isLoading, error } = useFetch('get', '/companies');
const companies = computed(() =>
data.companies?.map((company) => ({
id: `#${company.id}`,
name: `${company.legal_entity_type} ${company.business_name}`,
enterprise_number: formatEnterpriseNumber(company.enterprise_number),
email: formatEmail(company.email),
phone: formatPhone(company.phone),
}))
);
</script>
<template>
<div v-if="isLoading">Loading...</div>
<div v-else-if="error">Oops! Error encountered: {{ error }}</div>
<div v-else-if="companies">
Companies:
<pre>{{ companies }}</pre>
</div>
<div v-else>No data :(</div>
</template>
When using Companies inside the template tags it stays null. I've checked and data has a companies property of the type Array with data in it.
Anyone an idea how to handle this?
I think the issue may be due to use of ref. Try using reactive for data instead of ref
export function useFetch(url) {
const data = reactive(null);
const error = ref(null);
const isLoading = ref(true);
apiClient({ method, url, data: body })
.then((response) => (data = response.data))
.catch((err) => (error.value = err))
.finally(() => isLoading.value = false)
return { data, error }
}
To use ref, you would need to access the value via ref.value. Also, ref is not the best choice for objects and arrays as it was meant for primitive data types. to use ref you can
const companies = computed(() =>
data.value?.companies?.map((company) => ({
id: `#${company.id}`,
name: `${company.legal_entity_type} ${company.business_name}`,
enterprise_number: formatEnterpriseNumber(company.enterprise_number),
email: formatEmail(company.email),
phone: formatPhone(company.phone),
}))
);
note the use of ?. after value, which is required since the ref is null initially.

How to delete data using Vue.axios.delete()

I am new to vuejs. I am having trouble deleting json data from a fakeserve by using axios.delete().
I tried doing this :-
axios.delete('http://localhost:3000/users/', {params: {id: this.idToDelete} })
.then((response) => {
console.log(response)
}, (error) => {
console.log(error)
})
This is my html:-
<v-text-field v-model="idToDelete" type="number" hide-details outline
label="Enter Id to delete"></v-text-field>
<v-btn #click="userIdtoDelete()" color="error">Delete</v-btn>
This is my javascript (src/views/pages/Delete.vue):
import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
export default {
data () {
return {
idToDelete: ''
}
},
methods: {
userIdtoDelete () {
axios.delete('http://localhost:3000/users/', {params: {id: this.idToDelete} })
.then((response) => {
console.log(response)
//alert('response = ' + response)
}, (error) => {
console.log(error)
//alert('error = ' + error)
})
}
}
}
My code is in https://github.com/boidurja/users.git
And fakeserver is in https://github.com/boidurja/fakeserver.git
When I click the delete button data is not getting deleted and I am getting the following error message:-
DELETE http://localhost:3000/users/?id=3 404 (Not Found)
JSON Server automatically creates routes in a RESTful format, eg
GET /users
GET /users/1
POST /users
PUT /users/1
PATCH /users/1
DELETE /users/1
So with that in mind, you should be using
axios.delete(`http://localhost:3000/users/${encodeURIComponent(this.idToDelete)}`)
.then(res => { console.log(res) })
.catch(err => { console.error(err) })
I think your issue is that you are calling a function inline with () vue does this for you, try
<v-btn #click="userIdtoDelete" color="error">Delete</v-btn>
I think you are triggering the function twice.
In addition, you can try instead of using v-model to catch the id directly in the function like userIdtoDelete($event.target.value)

How to use twilio with dynamic routes in nuxt

Hoping I can explain this clearly and someone has some insight on how I can solve this.
I am trying to enter a input then have a text message delivered to the number that was entered. That simple.
On the homepage, I have an input component with:
<template>
<form class="right-card" #submit.prevent="submit">
<input v-model="search" />
<button class="clear" type="submit" v-on:click="submit"></button>
</form>
</template>
With this function set as a method to pass the param
export default {
data () {
return {
search: ''
}
},
methods: {
submit: function (event) {
this.$router.push(`sms/${this.search}`)
}
}
}
Then I have a /sms page located in pages/sms/_sms.vue which is landed on once the form is submitted
<template>
<div>
<h1>Success Page {{phoneNumber}} {{$route.params}}</h1>
<KeyboardCard/>
</div>
</template>
<script>
import KeyboardCard from '~/components/KeyboardCard.vue'
import axios from '~/plugins/axios'
export default {
asyncData ({ params, error }) {
return axios.get('/api/sms/' + params.sms)
.then((res) => {
console.log(res)
console.log(params)
return { phoneNumber: res.data }
})
.catch((e) => {
error({ statusCode: 404, message: 'Sms not found' })
})
},
components: {
KeyboardCard
}
}
</script>
And finally within api/sms/sms.js I have this on express running.
(note my API keys are replaced with placeholder)
router.get('/sms/:sms', (req, res, next) => {
console.log('express reached')
const accountSid = 'ACCOUNTSIDPLACEHOLDER'
const authToken = 'AUTHTOKENPLACEHOLDER'
const client = require('twilio')(accountSid, authToken)
client.messages.create({
to: '14169190118',
from: '+16477993562',
body: 'This is the ship that made the Kessel Run in 14 parsecs?!'
})
.then((message) => console.log(message.sid))
})
How can I pass the parameter.sms within the to field in my /api/routes/sms.js
Expected: When user enters # into the input how can the api/sms/:sms be called dynamically to the number that was typed in the input component?
Thanks in advance if anyone see's whats going on here :)
Edit: I have my middleware defined in the nuxt.config file, like so:
serverMiddleware: [
// API middleware
'~/api/index.js'
]
and my api/index.js file has:
const express = require('express')
// Create express instnace
const app = express()
// Require API route
const sms = require('./routes/sms')
// Import API Routes
app.use(sms)
// Export the server middleware
module.exports = {
path: '/api',
handler: app
}
I guess this is more an Express.js related question than a Vue.js question.
You can use the passed sms param from your request, like this:
router.get('/sms/:sms', (req, res, next) => {
console.log('express reached')
const accountSid = 'ACCOUNTSIDPLACEHOLDER'
const authToken = 'AUTHTOKENPLACEHOLDER'
const client = require('twilio')(accountSid, authToken)
client.messages.create({
to: req.params.sms,
from: '+16477993562',
body: 'This is the ship that made the Kessel Run in 14 parsecs?!'
})
.then((message) => console.log(message.sid))
})

VueJS data from nested Axios requests not rendering in view

I am trying to list a set of posts from an API on a page using VueJS and Axios. The issue I am facing is one piece of the data (the post url) needs to be retrieved with a separate API call for that specific post and they provide the url for that data in the initial API call. I have the first part working perfectly, but I can't get the href to render in the view when the value is showing up in the Vue devtools.
JS
const vm = new Vue({
el: '#app',
data: {
posts: []
},
mounted() {
this.getPosts();
},
methods: {
getPosts() {
axios.get("api_url")
.then((response) => {
this.posts = response.data.posts;
// Get URL for each post from separate API call
this.posts.map(post => {
axios.get(post.details_url+"&output=json")
.then((response) => {
post.official_url = response.data.post.pet_details_url;
}).catch( error => { console.log(error); });
});
}).catch( error => { console.log(error); });
}
}
});
HTML
<div id="app">
<div v-for="post in posts">
<a :href="post.official_url"> //href won't render
<h2>{{ post.title }}</h2>
<p>{{ post.text }}</p>
</a>
</div>
</div>
Data showing up in Vue DevTools
It might be reactive problem. You can try Vue.set
getPosts() {
let vm = this
axios.get("api_url")
.then((response) => {
this.posts = response.data.posts;
// Get URL for each post from separate API call
this.posts.map((post, index) => {
axios.get(post.details_url+"&output=json")
.then((response) => {
post.official_url = response.data.post.pet_details_url;
Vue.set(vm.posts, index, JSON.parse(JSON.stringify(post)))
}).catch( error => { console.log(error); });
});
}).catch( error => { console.log(error); });
}

VueJS / ExpressJS (Backend) - Getting data from an API

I'm learning VueJS / Express and I'm trying to display data from an external API onto my page. I'm using Express as the API Calls require headers + I believe its safer to keep it separate from Vue.
Here is my Express
app.get('/summoner', function(request, response) {
axios.get('https://euw1.api.riotgames.com/lol/summoner/v3/summoners/by-name/XXXXXXXX', {headers: headers})
.then(response => {
console.log(response.data)
})
.catch(error => {
console.log(error)
})
})
Here is my Vue code:
import axios from 'axios'
export default {
name: 'summoner',
data () {
return {
summoner: [],
errors: []
}
},
created () {
console.log('Created')
axios.get('/api/summoner')
.then(response => {
console.log('Hit me')
this.summoner = response.data
})
.catch(e => {
this.errors.push(e)
console.log(e)
})
}
}
The console.log(response.data) is showing me the object I expect which is:
{ id: XXXXXXXX,
accountId: XXXXXXXX,
name: 'XXXXXXXX',
profileIconId: XXXXXXXX,
revisionDate: XXXXXXXX,
summonerLevel: XXXXXXXX }
The console.log('Hit Me') is never fired
The console.log('Created') is fired on page load.
Nothing I seem to try allows me to display any of the object using Vue e.g:
{{ summoner.id }}
Just to add, I have configured a proxy in webpack which forwards the below requests to Express. As far as I can tell, this is working as each time I refresh the page, I see the ExpressJS console.log(response.data) fire
Could anyone help?
Thanks!
In your express code you do not return the repsonse (which you also override in the axios response). Try changing it to
app.get('/summoner', function(request, res) { // <--- careful here is a change
axios.get('https://euw1.api.riotgames.com/lol/summoner/v3/summoners/by-name/XXXXXXXX', {headers: headers})
.then(response => {
console.log(response.data)
return res.status(200).send(response.data);
})
.catch(error => {
console.log(error)
return res.status(400).send(error);
})
})
I actually resolved this by doing:
res.json([response.data])
In the ExpressJS side of things.
I also had to use response.data[0] within Vue.