I am trying to send data to localhost with axios post, But for some reason what ever I try, I get the same error
"not send Error: Network Error"
this is my front end code
import React, { Component } from 'react';
import axios from 'axios';
class App extends Component {
constructor(props) {
super(props);
this.state = { }
}
sendData =()=>{
var url ="http://localhost:9000/api"
var data={
code:"hello world",
}
axios.post(url,data)
.then(res => {
console.log("data send")
})
.catch(err => {
console.log("not send"+err)
console.error(err);
})
}
render() {
return (
<div>
<form>
<input type="text" name="data"/>
</form>
{this.sendData()}
</div>
);
}
}
export default App;
and this is my back end code
var express=require('express');
var app=express();
app.use(express.json());
app.post('/api', function(req,res){
res.json(req.body);
})
app.listen(9000);
Can you post the error as well. It is most likely to be A CORS issue. If you can call the API from A Rest Client like Postman and not browser it is a CORS Issue
Install cors package npm install cors
Update your backed to allow CORS
var express = require('express')
var cors = require('cors') // New
var app = express()
app.use(cors()) // New
app.use(express.json());
app.post('/api', function(req,res){
res.json(req.body);
})
app.listen(9000);
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.
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 want to send a file with axios, from my Vue.js to my Node.js,
but the req.file parameter is never filled, it's undefined
Here is the simplified code from my vue :
Inscription.vue :
<template>
<div class="main_content">
<h1>Inscription</h1>
<div><input type='file' #change='openFile'></div>
<button type='button' v-on:click="inscription" class="inscription">Inscription</button>
</div>
</template>
<script>
import Axios from 'axios';
export default {
data () {
return { selectedFile: null}
},
methods:{
openFile (event) {
this.selectedFile = event.target.files[0];
},
inscription () {
let fd = new FormData();
fd.append('avatarBase64', this.selectedFile);
Axios.create({baseURL: 'http://localhost:4444'}).post('/api/testUploadImage', {avatarBase64: fd});
}
}
My simplified node.js application :
main.ts
import express from "express";
var cors = require('cors');
var bodyParser = require('body-parser')
const multer = require('multer')
const http = require('http');
const server = express();
server.use(cors({origin: true}))
server.use(bodyParser.json({limit: '50mb', extended: true}));
server.use(
bodyParser.urlencoded({
extended: true
})
)
server.post("/api/testUploadImage", upload.single('avatarBase64'), async (req: any, res: any) => {
// req.file is undefined PROBLEM THERE
});
const httpServer = http.createServer(server);
httpServer.listen(port);
try changing headers of axios with
'content-type': 'multipart/form-data'
I found out : i was sending this
Axios.create({baseURL: 'http://localhost:4444'}).post('/api/testUploadImage', {avatarBase64: fd});
instead of this :
Axios.create({baseURL: 'http://localhost:4444'}).post('/api/testUploadImage', fd);
change your multer version and try it agian
npm i multer#2.0.0-rc.2
and edit this:
Axios.create({baseURL: 'http://localhost:4444'}).post('/api/testUploadImage', fd);
I'm building an app using node.js on the server side and used create-react-app for the client.
When running locally I want to use render Home component for path '/home' like so:
<BrowserRouter>
<div>
<Route exact path="/home" component={Home} />
</div>
</BrowserRouter>
and on the server side I want to to use '/home' to get requests like so:
app.use('/home', require('./routes/home'))
where 'routes/home/' is an express router:
module.exports = router.get('/', (req, res) => {
res.send({ status: 200, data: 'Hello World!' })
})
The problem is that I got CORS error at first, so I added createProxyMiddleware in order to proxy the server responses:
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
const portPrefix = 'localhost:3000'
const options = {
target: 'http://localhost:5000',
router: {
'dev.localhost:3000': 'http://localhost:5000'
}
}
app.use([`/home`], createProxyMiddleware(options));
};
But now, when I make a request from the client (port 3000) to '/home' the request is redirected to port 5000 and I get the res.send({...}) immediately (instead of rendering the Home component that is using axios to make the request and handle the response..)
My Home component:
import React, { useState, useEffect } from 'react'
import axios from 'axios'
axios.defaults.baseURL = 'http://localhost:5000'
const Home = () => {
const [loading, setLoading] = useState(true)
const [data, setData] = useState("")
useEffect(() => {
async function makeRequest() {
const res = await axios.get('/home')
setData(res.status === 200 ? res.data.data : "test string")
setLoading(false)
}
makeRequest()
}, [])
return (
<div className="container">
{ !loading && <h1>{data}</h1> }
Home Page
</div>
)
}
export default Home
I saw that there's a solution to avoid createProxyMiddleware and just add headers to the response:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:3000"); // update to match the domain you will make the request from
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
My question are:
How will adding headers behave on production?
Is the headers solution the better solution for local development, since createProxyMiddleware is there to assist with that I guess.
If I decide to use createProxyMiddleware, how can I use the same routes for both client and server (e.g. '/home' to render Home component on FE and '/home' for get requests on BE)? because now it "skips" the client side and goes straight to the server.
Thanks a lot!
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))
})