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))
})
Related
In my Nuxt3 project, I have a very basic login page which is SSR like the following:
pages/login.vue
<template>
<form
#submit.prevent="login">
<input
name="email"
v-model="form.email"/>
<input
name="password"
v-model="form.password"/>
<button>login</button>
<form>
</template>
<script setup>
import { useAuth } from '~/store/auth.js';
const auth = useAuth();
const form = ref({email: '', password: ''});
const router = useRouter();
const login = async () => {
useFetch('/api/auth/tokens', {
method: 'POST',
body: form.value
})
.then(({ data }) => {
const { token, user } = data.value;
auth.setUser(user);
auth.setToken(token);
router.push('/profile');
})
}
</script>
First, I try to test it like a SPA page:
import { describe, test, expect } from 'vitest';
import { mount } from '#vue/test-utils';
import LoginPage from '~/pages/login.vue';
describe('login page', async () => {
test('store tokens', async () => {
const wrapper = mount(LoginPage);
const email = 'test#example.com';
const password = 'password';
await wrapper.find('[name="email"]').setValue(email);
await wrapper.find('[name="password"]').setValue(password);
await wrapper.find('form').trigger('submit.prevent');
expect(
wrapper.emitted('submit')[0][0]
).toStrictEqual({
email,
password,
});
// But this does not test the code in `then()` which handled the response and redirect to `/profile`
});
});
Got error:
FAIL tests/pages/login.spec.js > login page > store tokens
ReferenceError: document is not defined
Then, I followed the Nuxt3 testing
import { describe, test, expect } from 'vitest';
import { setup, $fetch } from '#nuxt/test-utils';
import { JSDOM } from 'jsdom';
describe('login page', async () => {
await setup();
test('store tokens', async () => {
const wrapper = (new JSDOM(await $fetch('/login'))).window.document;
const email = 'test#example.com';
const password = 'password';
await wrapper.find('[name="email"]').setValue(email);
await wrapper.find('[name="password"]').setValue(password);
await wrapper.find('form').trigger('submit.prevent');
expect($fetch).toHaveBeenCalledWith('/api/auth/tokens', {
method: 'POST',
body: {
email: 'test#example.com',
password: 'password'
}
});
});
});
But wrapper there is just a jsdom document instance, it can't act like a Vue component.
I wonder:
How to test the user input events?
How to test the code in resovle of useFetch() (in the example, it's the code handling data with pinia)
same question in GitHub
I would unit test the component, so check if inputs work as expected and also if the correct action is triggered on submit. So don't render a whole page, just mount the component in the test.
I would test the login action afterwards separately meaning you mock the data from the API (token, user) and check if they are set correctly to the auth. Plus, if there's a redirect. This should be possible.
You want to test the whole feature (login) which is often referred as "feature testing". But the base is unit tests.
I'm working on a project based on React-Native.
When a user signs up, I want to send an email verification code using AWS-SES.
Back-End entered AWS-SES information for this purpose
I want to use Axios to retrieve that information to Front-End
and send someone an email authentication number when I click [Button].
To do this, I'm asking you a question here
because I want to know how to get AWS-SES information from Back-End to Front-End and run it.
I need your help.
Thank you for reading my post.
Back-End
const { Router } = require("express");
const router = Router();
const aws = require("aws-sdk");
router.get("/mail", get_email);
exports.get_email = async (req, res) => {
try {
const testA = () => {
let ses = new aws.SES({
region: "ap-northeast-2",
});
let params = {
Destination: {
ToAddresses: ["test#gmail.com"],
},
Message: {
Body: {
Text: {
Data: "TEST MESSAGE",
},
},
Subject: { Data: "TEST" },
},
Source: "test#gmail.com",
};
return ses.sendEmail(params).promise();
};
return res.status(200).json({ success: true, testA });
} catch (e) {
console.log(e);
}
};
Front-End
import React, { useState, useEffect } from "react";
import axios from "axios";
const [test, setTest] = useState([]);
useEffect(() => {
getTest();
}, []);
const getTest = async () => {
await axios.get("/mail").then((res) => {
if (res.data) {
setTest(res.data.testA);
}
});
};
return (
<div>
<div onClick={()=>{
getTest();
console.log("Test AWS-SES : ", test);
}}>
Test
</div>
</div>
);
Result
Test AWS-SES : undefined
this.$axios is undefined. As I said in the title I set nuxt.config.js. This is what the error looks like.
This is the HomeView.vue page code where the error is occurring (I removed some methods as they aren't relevant) BTW, notice the line console.log(this.$axios); because this is what printed undefined in the web console:
<template>
<div>
<button
color="primary"
class="btn btn-primary btn-lg btn-block"
large
:disabled="buttonDisabled"
#click="performAction()"
>
<span v-if="isMetaMaskInstalled()">Login with Metamask</span>
<span v-if="!isMetaMaskInstalled()">{{ buttonInstallText }}</span>
</button>
</div>
<span></span>
<button
type="button"
class="btn btn-primary btn-lg btn-block"
#click="register()"
>
Block level button
</button>
</template>
<script>
import Web3 from "web3";
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap-vue/dist/bootstrap-vue.css";
export default {
data() {
return {
buttonDisabled: false,
buttonInstallText: "Click here to install Metamask",
};
},
methods: {
basicLog() {
console.log("it worked");
},
testAxiosCall() {
console.log("test call worked");
},
async register() {
console.log(this.$axios);
const result = await this.$axios.post("/register", {
wallet: "0x00fffff",
});
return result;
},
},
};
</script>
I already installed axios with yarn add #nuxtjs/axios and set up my nuxt config file:
export default {
modules: ["#nuxtjs/axios"],
axios: {
baseURL: "http://localhost:30005",
},
};
Btw, the function localhost:30005/register works perfectly in Postman when I add the parameter wallet: 0x00fffff.
Also here is the code for the register api call. It's in backend/index.js
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const sqlite3 = require("sqlite3");
const path = require("path");
const app = express();
let port = "30005";
let db = new sqlite3.Database(path.resolve(__dirname, "bonus_content.db"));
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(cors());
const registerUser = (request, response) => {
const { wallet } = request.body;
console.log(wallet);
db.run(
"INSERT INTO bonus_content (wallet) VALUES ($1)",
[wallet],
(error, results) => {
if (error) {
response.status(500).json({ status: "fail", message: error });
}
response
.status(201)
.json({ status: "success", message: "Wallet added." });
}
);
};
app.post("/register", registerUser);
// allow javascript on a different domain (or port) to call this server's routes
// e.g. front-end running on localhost:8080 can call the server on localhost:41205
app.listen(port);
console.log("App is running on port " + port);
So the problem is centered around this.$axios being undefined. What am I doing wrong?
Btw, It's worth noting that I am going off of this tutorial here: https://duartefdias.medium.com/authenticating-users-to-your-web-app-using-metamask-and-nodejs-e920e45e358
Thank you for mentioning my article, glad you found it useful.
First, you need to make sure you have axios installed as mentioned here:
https://axios.nuxtjs.org/setup
My nuxt.config.js axios setup looks like this:
export default {
axios: {
browserBaseURL: process.env.API_URL
}
}
The process.env.API_URL is an environment variable I created, but you can simply hardcode a string such as "http://localhost:3000"
Then I just call this.$axios from anywhere in the code. Example of a basic .vue page:
<template>
<button #click="getData()">
My Button
</button>
</template>
<script>
export default {
components: {},
data () {
return {
items: []
}
},
methods: {
getData() {
this.$axios.get('/items')
.then(response => {
this.items = response.data
})
.catch(error => {
console.log(error)
})
}
}
}
</script>
If I were you I would start by building a dummy backend endpoint which simply returns a string and getting that to work with Vue prior to moving into building the blockchain wallet register/login endpoints.
I'm trying to get the answer from two API routes and depending on the result display the data. But for some reason, when I trying to use more than 1 axios call it doesn't work, failing with 404/500 error.
I've tried following:
<template>
<div v-if="blogPost">
<p>post</p>
</div>
<div v-else-if="blogCategoryPosts">
<p>category,posts</p>
</div>
</template>
<script>
export default {
async asyncData({ $axios, app, route }) {
const blogPost = await $axios.get(`${process.env.API_DOMAIN}/api/blog/posts${route.path}`)
const blogCategoryPosts = await $axios.get(`${process.env.API_DOMAIN}/api/blog/categories${route.path}`)
return {
blogPost: blogPost.data,
blogCategoryPosts: blogCategoryPosts.data,
}
},
}
</script>
and
<script>
export default {
async asyncData({ $axios, app, route}) {
const [blogPost, blogCategoryPosts] = await Promise.all([
$axios.get(`${process.env.API_DOMAIN}/api/blog/posts${route.path}`),
$axios.get(`${process.env.API_DOMAIN}/api/blog/categories${route.path}`),
])
return {
blogPost: blogPost.data,
blogCategoryPosts: blogCategoryPosts.data,
}
},
}
</script>
Each call works fine separately but together they don't. Any idea why is that?
You should await your Promise.all like this
const [blogPost, blogCategoryPosts] = await Promise.all([
$axios.get(`${process.env.API_DOMAIN}/api/blog/posts${route.path}`),
$axios.get(`${process.env.API_DOMAIN}/api/blog/categories${route.path}`),
])
Also, don't forget the , at the end of the first $axios.
I gave a similar answer here few time ago.
PS: if you want to have those issues fixed quickly, use ESlint.
If you want a tutorial on how to have both ESlint and Prettier, you can follow my tutorial here.
So in my case it was sufficient to point on .then and .catch for axios
export default {
async asyncData({ $axios, app, route}) {
const blogPost = await $axios.get(`${process.env.API_DOMAIN}/api/blog/posts${route.path}`).then(response => response.data).catch(error => {})
const blogCategoryPosts = await $axios.get(`${process.env.API_DOMAIN}/api/blog/categories${route.path}`).then(response => response.data).catch(error => {})
return {
blogPost: blogPost,
blogCategoryPosts: blogCategoryPosts,
}
},
}
Everything worked well. Also I sort of misunderstood 500 error, i thought it a generic message, but my API was just telling me that category not found.
I'm following a tutorial to build a full stack app using VueJS and the MEVN stack. I have
a) built mongo db
b) build api back end with one mongoose model 'Student'
c) got the back end api running at localhost:4000/api
d) got the front end running with VueJS and Axios to read data from
the api
e) got READ, CREATE and DELETE working fine from my VueJS app
f) UPDATE is not working
g) Postman PUT is working fine though, so I know the back end is
fine.
Back end routes are
const express = require('express');
const studentRoute = express.Router();
// model
let StudentModel = require('../models/Student');
studentRoute.route('/create-student').post((req, res, next) => {
console.log('creating one student at /create-student')
StudentModel.create(req.body, (error, data) => {
if (error) {
return next(error)
} else {
console.log(`student created ${JSON.stringify(data)}`)
res.json(data)
}
})
});
studentRoute.route('/').get((req, res, next) => {
console.log('GET all students')
StudentModel.find((error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
studentRoute.route('/edit-student/:id').get((req, res, next) => {
console.log('get one student at /edit-student/:id')
StudentModel.findById(req.params.id, (error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
// Update
studentRoute.route('/update-student/:id').post((req, res, next) => {
console.log(`attempting to update one student with id ${req.params.id}`)
console.log(`request body = `)
console.log(JSON.stringify(req.body))
console.log(req.body)
StudentModel.findByIdAndUpdate(req.params.id,
{ $set: req.body },
(error, data) => {
if (error) {
console.log(`an error has taken place`)
return next(error);
} else {
res.json(data)
console.log('Student successfully updated!')
}
})
})
// Delete
studentRoute.route('/delete-student/:id').delete((req, res, next) => {
console.log('delete one student at /delete-student/:id')
StudentModel.findByIdAndRemove(req.params.id, (error, data) => {
if (error) {
return next(error);
} else {
res.status(200).json({
msg: data
})
}
})
})
module.exports = studentRoute;
front end update code is
<template>
<div class="row justify-content-center">
<div class="col-md-6">
<h3 class="text-center">Update Student</h3>
<form #submit.prevent="handleUpdateForm">
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" v-model="student.name" required>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" v-model="student.email" required>
</div>
<div class="form-group">
<label>Phone</label>
<input type="text" class="form-control" v-model="student.phone" required>
</div>
<div class="form-group">
<button class="btn btn-danger btn-block">Update</button>
</div>
</form>
</div>
</div>
</template>
<script lang="ts">
import { Vue } from 'vue-class-component';
import axios from "axios";
export default class EditComponent extends Vue {
student!: {
name: '',
email: '',
phone: ''
}
data() {
return {
student: { }
}
}
created() {
let apiURL = `http://localhost:4000/api/edit-student/${this.$route.params.id}`;
axios.get(apiURL).then((res) => {
this.student = res.data;
})
}
handleUpdateForm() {
let id = this.$route.params.id
let apiURL = `http://localhost:4000/api/update-student/${this.$route.params.id}`;
console.log(`attempt to update student at url`)
console.log(apiURL)
console.log(`with id`)
console.log(id)
console.log(`attempt to update student ${JSON.stringify(this.student)}`)
axios.put(apiURL, this.student)
.then(res => {
console.log(`response is ${res}`)
this.$router.push('/view')
})
.catch(error => {
console.log('error when updating student')
console.log(error)
});
}
}
</script>
when I use Postman I get this response from the api
attempting to update one student with id 6119d671cc9ce131207bd37c
request body =
{"_id":"6119d671cc9ce131207bd37c","name":"PHIL","email":"philanderson888#hotmail.com","phone":7888849991,"__v":0}{ _id: '6119d671cc9ce131207bd37c',
name: 'PHIL',
email: 'philanderson888#hotmail.com',
phone: 7888849991,
__v: 0 }
Student successfully updated!
when I use VueJS to update my Student I get the following error from this code
// Update
studentRoute.route('/update-student/:id').post((req, res, next) => {
console.log(`attempting to update one student with id ${req.params.id}`)
console.log(`request body = `)
console.log(JSON.stringify(req.body))
console.log(req.body)
StudentModel.findByIdAndUpdate(req.params.id,
{ $set: req.body },
(error, data) => {
if (error) {
console.log(`an error has taken place`)
return next(error);
} else {
res.json(data)
console.log('Student successfully updated!')
}
})
})
attempt to update student at url
EditComponent.vue?720f:29 http://localhost:4000/api/update-student/6119d671cc9ce131207bd37c
EditComponent.vue?720f:30 with id
EditComponent.vue?720f:31 6119d671cc9ce131207bd37c
EditComponent.vue?720f:32 attempt to update student {"_id":"6119d671cc9ce131207bd37c","name":"PHIL","email":"phil#phil.com","phone":123,"__v":0}
xhr.js?b50d:177 PUT http://localhost:4000/api/update-student/6119d671cc9ce131207bd37c 404 (Not Found)
dispatchXhrRequest # xhr.js?b50d:177
xhrAdapter # xhr.js?b50d:13
dispatchRequest # dispatchRequest.js?5270:52
Promise.then (async)
request # Axios.js?0a06:61
Axios.<computed> # Axios.js?0a06:87
wrap # bind.js?1d2b:9
handleUpdateForm # EditComponent.vue?720f:33
eval # EditComponent.vue?2308:5
eval # runtime-dom.esm-bundler.js?830f:1400
callWithErrorHandling # runtime-core.esm-bundler.js?5c40:6988
callWithAsyncErrorHandling # runtime-core.esm-bundler.js?5c40:6997
invoker # runtime-dom.esm-bundler.js?830f:347
EditComponent.vue?720f:39 error when updating student
EditComponent.vue?720f:40 Error: Request failed with status code 404
at createError (createError.js?2d83:16)
at settle (settle.js?467f:17)
at XMLHttpRequest.handleLoad (xhr.js?b50d:62)
I'm aware mongo has updated their methods for handling updates and have tried the following
1)
StudentModel.findByIdAndUpdate(req.params.id,
{ $set: req.body },
(error, data) => {
StudentModel.findOneAndUpdate({_id:req.params.id},
{ $set: req.body },
(error, data) => {
StudentModel.updateOne({_id:req.params.id},
{ $set: req.body },
(error, data) => {
In each case I am getting the error above and in each case Postman works fine. So there's a problem with the URL being formed and I'm not sure what it is???
Your help would be appreciated!
Thank you
Philip
Also, just in case it is relevant, here is the back end app.js
let express = require('express'),
cors = require('cors'),
mongoose = require('mongoose'),
database = require('./database'),
bodyParser = require('body-parser');
// Connect mongoDB
mongoose.Promise = global.Promise;
//mongoose.set('useFindAndModify',false);
mongoose.connect(database.db, {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log("Database connected")
},
error => {
console.log("Database could't be connected to: " + error)
}
)
const studentAPI = require('../api/routes/student.route')
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(cors());
// API
app.use('/api', studentAPI)
// Create port
const port = process.env.PORT || 4000;
const server = app.listen(port, () => {
console.log('Connected to port ' + port)
})
const logUsage = (logCode) => {
console.log(`http serving with code ${logCode}`)
}
app.use((req, res, next) => {
console.log(`logging data in 'next'`)
next(logUsage(200));
});
app.use(function (err, req, res, next) {
console.log('in app.use')
console.error(err.message);
if (!err.statusCode) err.statusCode = 500;
res.status(err.statusCode).send(err.message);
});
You can try to replace post in update route with put