cannot connect to socket.io server in client side using ngrok - javascript

I'm trying to connect to the socket server in react-native,
I'm using ngrok and it's the log when the mobile app running
HTTP Requests
-------------
POST /io/webrtc/ 400 Bad Request
GET /io/webrtc/ 200 OK
{
"code": 2,
"message": "Bad handshake method"
}
although the Web app, it works very well!
Code snippet
Server.js
const express = require('express');
let io = require('socket.io')({
path: '/io/webrtc',
});
const app = express();
const port = 8080;
//https://expressjs.com/en/guide/writing-middleware.html
app.use(express.static(__dirname + '/build'));
app.get('/', (req, res, next) => {
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
);
res.sendFile(__dirname + '/build/index.html');
});
const server = app.listen(port, () =>
console.log(`Example app listening on port ${port}!`)
);
io.listen(server);
const peers = io.of('/webrtcPeer');
let connectedPeers = new Map();
peers.on('connection', (socket) => {
console.log(socket.id);
socket.emit('connection-success', { success: socket.id });
connectedPeers.set(socket.id, socket);
socket.on('disconnect', () => {
console.log('disconnected!');
connectedPeers.delete(socket.id);
});
socket.on('offerOrAnswer', (data) => {
console.log('data-offer||Answer', data);
// send to other peers if any
for (const [socketID, socket] of connectedPeers.entries()) {
// don't send to self
if (socketID !== data.socketID) {
console.log('not-offerOrAnswer', socketID, data.payload.type);
socket.emit('offerOrAnswer', data.payload);
}
}
});
socket.on('candidate', (data) => {
// send candidate to the other peers if any
for (const [socketID, socket] of connectedPeers.entries()) {
// don't send to self
if (socketID !== data.socketID) {
console.log('dont_send_to_self-candidate', socketID, data.payload.type);
socket.emit('candidate', data.payload);
}
}
});
});
mobile App (React Native)
App.js
import React, {useRef, useState, useEffect} from 'react';
import {View, Dimensions, Text} from 'react-native';
import io from 'socket.io-client';
const {width, height} = Dimensions.get('window');
const App = () => {
...
const socket = useRef();
const serverIP = 'https://22997aecc45f.ngrok.io';
useEffect(() => {
socket.current = io.connect(`${serverIP}/webrtcPeer`, {
path: '/io/webrtc',
query: {},
});
socket.current.on('connection-success', (success) => {
console.log('success', success); // not logged :)
});
}, []);
return (
<View>
<Text>App</Text>
</View>
);
};
export default App;
package.json // React Native
"react": "16.13.1",
"react-native": "0.63.3",
"react-native-webrtc": "^1.84.1",
"socket.io-client": "2.3.0"
package.json // web App Reactjs
"dependencies": {
"#testing-library/jest-dom": "^5.11.4",
"#testing-library/react": "^11.1.0",
"#testing-library/user-event": "^12.1.10",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.0",
"socket.io-client": "^3.0.1",
"web-vitals": "^0.2.4"
},
"devDependencies": {
"express": "^4.17.1",
"socket.io": "^3.0.1"
}
#Edit
The issue solved after downgrade socket server and client to 2.3.0 :)

Related

Alert box displaying 'undefined' instead of success message

I'm building a server-side rendered website with Node. I want to display a green alert box upon successfully updating data in updateSettings.js. Even though the user data (name and email) is updated on Compass correctly, I get a red alert box (error) with undefined as the message. In the browser console, I get a 'bad request' error from bundle.js.
Also, no code seems to run after the Axios PATCH request code
updateSettings.js
/* eslint-disable */
import axios from 'axios';
import { showAlert } from './alerts';
export const updateData = async (name, email) => {
try {
const res = await axios({
method: 'PATCH',
url: 'http://127.0.0.1:3000/api/v1/users/updateMe',
data: {
name,
email,
},
});
if (res.data.status === 'success') {
showAlert('success', 'Data updated successfully!');
}
} catch (err) {
showAlert('error', err.response.data.message);
}
};
Alerts.js
/* eslint-disable */
export const hideAlert = () => {
const el = document.querySelector('.alert');
if (el) el.parentElement.removeChild(el);
};
// type is 'success' or 'error'
export const showAlert = (type, msg) => {
hideAlert();
const markup = `<div class="alert alert--${type}">${msg}</div>`;
document.querySelector('body').insertAdjacentHTML('afterbegin', markup);
window.setTimeout(hideAlert, 5000);
};
Index.js
`
/* eslint-disable */
import '#babel/polyfill';
import { login, logout } from './login';
import { displayMap } from './leaflet';
import { updateData } from './updateSettings';
// DOM ELEMENTS
const leaflet = document.getElementById('map');
const loginForm = document.querySelector('.form--login');
const logOutBtn = document.querySelector('.nav__el--logout');
const updateDataForm = document.querySelector('.form-user-data');
// DELEGATION
if (leaflet) {
const locations = JSON.parse(leaflet.dataset.locations);
displayMap(locations);
}
if (loginForm)
loginForm.addEventListener('submit', (e) => {
e.preventDefault();
const password = document.getElementById('password').value;
const email = document.getElementById('email').value;
login(email, password);
});
if (logOutBtn) logOutBtn.addEventListener('click', logout);
if (updateDataForm)
updateDataForm.addEventListener('submit', (e) => {
e.preventDefault();
const name = document.getElementById('name').value;
const email = document.getElementById('email').value;
updateData(name, email);
});
`
Running the node debugger indicates that process.env.NODE_ENV is undefined but I'm using dotenv for this so it should be working just fine. In any case, the login functionality which is quite similar and uses axios runs just fine.
App.js
const path = require('path');
const express = require('express');
const morgan = require('morgan');
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');
const mongoSanitize = require('express-mongo-sanitize');
const xss = require('xss-clean');
const hpp = require('hpp');
const cookieParser = require('cookie-parser');
// eslint-disable-next-line node/no-deprecated-api
const exp = require('constants');
const AppError = require('./utilities/appError');
const globalErrorHandler = require('./controllers/errrorController');
const tourRouter = require('./routes/tourRoutes');
const userRouter = require('./routes/userRoutes');
const reviewRouter = require('./routes/reviewRoutes');
const viewRouter = require('./routes/viewRoutes');
const app = express(); //express is a function which upon calling will add a bunch of methods to the app variable
app.set('view engine', 'pug');
app.set('views', path.join(__dirname, 'views'));
// 1.GLOBAL MIDDLEWARES
// Serving static files
// app.use(express.static(`${__dirname}/public`));
app.use(express.static(path.join(__dirname, 'public')));
// Set Security HTTP headers
app.use(helmet());
// Development logging
console.log(process.env.NODE_ENV);
if (process.env.NODE_ENV === 'development') {
// the readinng of the process only needs to happen once, and the process is the same no matter which file we're in
app.use(morgan('dev'));
}
// Limit requests from same API
const limiter = rateLimit({
max: 100,
windowMs: 60 * 60 * 1000,
message: 'Too many requests from this IP, please try again in an hour',
});
app.use('/api', limiter);
// Body parser: reading data from body into req.body
app.use(express.json({ limit: '10kb' })); //'express.json' here is middleware
app.use(express.urlencoded({ extended: true, limit: '10kb' }));
app.use(cookieParser());
// Data sanitization against NoSQL query injection
app.use(mongoSanitize());
// Data sanitization agains XSS
app.use(xss());
// Prevent parameter pollution
app.use(
hpp({
whitelist: [
'duration',
'ratingsAverage',
'ratingsQuantity',
'maxGroupSize',
'difficulty',
'price',
],
})
);
// Test middleware
app.use((req, res, next) => {
// we have access to the requestTime property; assuming we want to display the time of the request
req.requestTime = new Date().toISOString();
next();
console.log(req.cookies);
});
// 3. ROUTES: this is where we mount our routers
// these 3 routers are actually middlewares that we mount upon the paths
app.use('/', viewRouter); //mounted right on the root URL
app.use('/api/v1/tours', tourRouter); //we've created a sub-app with this
app.use('/api/v1/users', userRouter);
app.use('/api/v1/reviews', reviewRouter);
// this router is essentially a sub-app for each resource
// the request goes into middleware and when it hits the above line of code, it will match the url, and thus the tourRouter middleware function will run
app.all('*', (req, res, next) => {
next(new AppError(`Cant find ${req.originalUrl} on this server!`, 404));
});
app.use(globalErrorHandler);
module.exports = app;
/updateMe
exports.updateMe = catchAsync(async (req, res, next) => {
// 1) Create error if user POSTs password data
if (req.body.password || req.body.passwordConfirm) {
return next(
new AppError(
'This route is not for password updates. Please use /updateMyPassword',
400
)
);
}
// 2) Filter out unwanted field names that are not allowed to be updated
const filteredBody = filterObj(req.body, 'name', 'email');
// 3) Update user document
const updatedUser = await User.findByIdAndUpdate(req.user.id, filteredBody, {
new: true,
runValidators: true,
});
res.status(400).json({
status: 'success',
data: {
user: updatedUser,
},
});
});
package.json
"scripts": {
"start": "nodemon server.js",
"start:prod": "NODE_ENV=production nodemon server.js",
"debugger": "ndb server.js",
"watch:js": "parcel watch ./public/js/index.js --out-dir ./public/js --out-file bundle.js",
"build:js": "parcel watch ./public/js/index.js --out-dir ./public/js --out-file bundle.js"
},
"author": "Dave Odipo",
"license": "ISC",
"dependencies": {
"#babel/polyfill": "^7.12.1",
"axios": "^1.1.3",
"b": "^2.0.1",
"babel": "file:../../../../../../../../polyfill",
"bcryptjs": "^2.4.3",
"cookie-parser": "^1.4.6",
"dotenv": "^16.0.2",
"express": "^4.18.1",
"express-mongo-sanitize": "^2.2.0",
"express-rate-limit": "^6.6.0",
"helmet": "3.16",
"hpp": "^0.2.3",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.13.15",
"morgan": "^1.10.0",
"nodemailer": "^6.8.0",
"pug": "^3.0.2",
"slugify": "^1.6.5",
"validator": "^13.7.0",
"xss-clean": "^0.1.1"
},
"optionalDependencies": {
"win-node-env": "^0.6.1"
},
"devDependencies": {
"eslint": "^8.23.1",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.31.8",
"parcel-bundler": "^1.12.3",
"prettier": "^2.7.1"
},
"engines": {
"node": ">=8.0.0"
}
}
Please help
Try changing res.status(400).json({ to res.status(200).json({

Axios is not making any request after few tries

I'm using React for testing connection to the RDS database from my local client and local server. For first few tries, my demo application works perfectly but after few tries, it seems like my code fails to make connection to the database nor wants to make connection to each other. Can anybody tell me what I could've missed in my codes?
ps. I know my code isn't clean. There may exist some unnecessary codes but please ignore them.
I have been constantly testing and I figured out the not responding cycle is getting shorter which I think the problem is related to the cache data (if that makes sense - I'm completely new to react!).
Client
import React, {useState,useEffect} from 'react';
import './App.css';
import Axios from 'axios';
import DatePicker from 'react-datepicker';
import "react-datepicker/dist/react-datepicker.css";
function App() {
const [title, setTitle] = useState('');
const [sAuthor, setAuthor] = useState('');
const [dateTime, setDateTime] = useState('');
const [desc, setDesc] = useState([]);
const submitButton = () => {
console.log("submit")
Axios.post('http://localhost:3001/post', {
time: dateTime,
author: sAuthor,
})
.then((response)=>{
console.log("responsed");
});
Axios.get('http://localhost:3001/get').then((response)=>
{
console.log("got");
setDesc([]);
setDesc(response.data);
enlist();
});
}
const enlist = () => {
console.log("enlist");
console.log(desc)
desc.map((val)=>{
return <h2>"STOCK NAME:"</h2>
})
}
useEffect(()=>
{
Axios.get('http://localhost:3001/get').then((response)=>
{});
},[])
useEffect(()=>
{
console.log(desc);
})
return (
<div className="App">
<h1>CRUD APPLICATION</h1>
<div className="form">
<input type = "text" name = "AI_TITLE" onChange={(e)=>{
setTitle(e.target.value)}}/>
<h3>TITLE</h3>
<input type = "text" name = "AI_AUTHOR" onChange = {(e)=>{
setAuthor(e.target.value)}}/>
<h3>STOCK NAME</h3>
<DatePicker format={"yyyy-MM-DD"} selected={dateTime} onChange={(date) => setDateTime(date)} />
<button className = "button" onClick={submitButton} >submit</button>
{desc.map((val)=>{
return (
<h1>STOCK: {val.AI_STOCKCD}</h1>
)
})}
</div>
</div>
);
}
export default App;
Server
const express = require('express');//create express server
const app = express();
const bodyParser = require('body-parser');
const mysql = require('mysql');
const cors = require('cors');
app.use(cors());
const db = mysql.createPool({
host: 'somehost',
user: 'someuser',
password: 'somepassword',
port: 0000,
database: 'smms2'
})
app.use(express.json())
app.use(express.urlencoded({extended: true}));
var author = "";
var time = "";
// recieving request from client
app.post("/post",(req, res)=>{
author = req.body.author;
time = req.body.time;
console.log(1)
console.log(author)
console.log(time)
})
// sending request to db
app.get("/get",(req, rows, fields)=>{
const sqlSelect = "SELECT * FROM ai_board WHERE UPDATE_DT > '"+time+"' AND AI_AUTHOR = '" + author+ "';";
db.query(sqlSelect, (err, result) =>{
rows.send(result);
});
})
app.listen(3001, ()=>{
console.log("running on port 3001");
})
package.json
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"devStart": "nodemon index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"mariadb": "^2.5.3",
"mysql": "^2.18.1",
"nodemon": "^2.0.7"
}
}

Fetch call returns react index.html and chrome gives error Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0

I am trying to fetch data from my local express server, and display it with react, but it seems that the index.html of the react app is being returned. If I check the network tab in the console and it shows that there is a fetch request with the name "projects/" and when I hover over it it shows "http://localhost:3000/api/projects". The console indicates that the problem is in line 13 of the react file which is "fetch('/api/projects/')". I've been trying for a while to fix this but can't seem to get it right. Code below
Express:
const express = require("express");
const app = express();
app.use(express.json());
let projects = [
{
id: 1,
title: "project1",
description: "One - description",
url: "www.One.com"
},
{
id: 2,
title: "project2",
description: "Two - description",
url: "www.Two.com"
},
{
id: 3,
title: "project3",
description: "Three - description",
url: "www.Three.com"
}
];
app.get("/api/projects", (req, res) => {
res.json(projects);
});
const PORT = 5000;
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
});
React:
import React from "react";
import "./App.css";
class App extends React.Component {
constructor() {
super();
this.state = {
projects: []
};
}
componentDidMount() {
fetch("/api/projects/")
.then(res => res.json())
.then(projects =>
this.setState({ projects }, () =>
console.log("Projects fetched...", projects)
)
);
}
render() {
return (
<div className="App">
<h1>Projects</h1>
</div>
);
}
}
export default App;
React package.json:
{
"name": "my-full-stack-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"#testing-library/jest-dom": "^4.2.4",
"#testing-library/react": "^9.5.0",
"#testing-library/user-event": "^7.2.1",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "3.4.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:5000",
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [">0.2%", "not dead", "not op_mini all"],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Your server is running on port 5000 and the client on port 3000. So, you have to call the api request as
fetch('http://localhost:5000/api/projects/')
If you don't specify the full URL, the request will be sent to http://localhost:3000/api/projects
You can also store the base URL in a constant.
import React from 'react';
import './App.css';
const baseUrl = 'http://localhost:5000';
class App extends React.Component {
constructor() {
super();
this.state = {
projects: []
}
}
componentDidMount() {
fetch(`${baseUrl}/api/projects/`)
.then(res => res.json())
.then(projects => this.setState({ projects }, () => console.log('Projects fetched...', projects)));
}
render() {
return (
<div className="App">
<h1>Projects</h1>
</div>
);
}
}
export default App;
Seems it was a cross-origin request. I installed the cors middleware, following the steps in the expressjs documentation, and added it to my express file and used app.use(cors()). Everything works now!
Just throwing this in, I know this has been answered, but I encountered this problem and was spinning my wheels for a while on it, despite all the solutions. Here is how I figured out to make it work:
I was a bit confused about the ports to use, as the app opens in port 3000, even though I had specified 5000 for my Express server. So I changed all ports everywhere to 3000 to try it out.
then I restarted my server first, then my react app, and it asked me if I wanted to open it on another port because 3000 was already being used. I said yes, and viola, it works. It now opens on port 3001 and everything works beautifully.
Code below to help any who may come to this page later, like I did.
server.js (express):
const express = require('express');
const cors = require('cors');
const knex = require('knex');
const db = knex({
client: 'pg',
connection: {
host: "127.0.0.1",
user: "",
password: "",
database: "",
},
});
const app = express();
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
// CORS implemented so that we don't get errors when trying to access the server from a different server location
app.use(cors());
// GET: Fetch all movies from the database
app.get('/', (req, res) => {
db.select('*')
.from('cards')
.then((data) => {
console.log(data);
res.json(data);
})
.catch((err) => {
console.log(err);
});
});
const port = 3000;
app.listen(port, () => console.log(`Server running on port ${port}, http://localhost:${port}`));
React App.js:
import React, { useState, useEffect } from 'react';
import './App.css';
const App = () => {
useEffect(() => {
const getAPI = () => {
const API = 'http://127.0.0.1:3000';
fetch(API)
.then((response) => {
console.log(response);
return response.json();
})
.then((data) => {
console.log(data);
setLoading(false);
setApiData(data);
});
};
getAPI();
}, []);
const [apiData, setApiData] = useState([]);
const [loading, setLoading] = useState(true);
return (
..... react stuff here .....
);
};
export default App;

How to retrieve data from reactjs and API

I am trying to post form data from react to node backend, How to do thtat ?
my React code is :
import fetch from 'isomorphic-fetch';
export function createBio (data) {
console.log(data);
return fetch('http://localhost:3001/user/create', {
method: 'POST',
mode: 'no-cors',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
}
}).then(res => {
return res;
}).catch(err => console.log(err));
}
My NodeJs code
router.post('/create', (req,res,) => {
var user = new User({title: req.params.title || "Untitled Note", body: req.params.body});
user.save();
});
How to retrieve data
req.param() searches the url path, body, and query string of the request (in that order) for the specified parameter. If no parameter value exists anywhere in the request with the given name, it returns undefined, or the optional defaultValue if specified.
url path parameters (req.params)
e.g. a request /create/4 to route /create/:id has url path params req.params.id
:id this id you can change anything you want, but you should add ":" before your parameter
body parameters (req.body)
e.g. a request with a parseable body (e.g. JSON, url-encoded, or XML) has body parameters equal to its parsed value
if you want to get the title, you can write req.body.title
For your case, I recommend you use req.body
Your back-end API
//http://localhost:3001/user/create
router.post('/create', (req,res) => {
const user = new User(
{
title: req.body.title ===null ? 'Untitled Note' : req.body.title,
text: req.body.text
});
user.save();
});
You should determine what value your data include
data = {
title: '?',
text: '?'
};
Your Fetch
import fetch from 'isomorphic-fetch';
export function createBio (data) {
console.log(data);
fetch('http://localhost:3001/user/create', {
method: 'POST',
mode: 'no-cors',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
}
}).then(res => {
return res;
}).catch(err => console.log(err));
}
Make sure of your path is right
Any way, I use 'axios' to retrieve data
router.post('/'),
(req, res) => {
const newPost = new Post({
eventTitle: req.body.eventTitle,
eventText: req.body.eventText
});
newPost.save().then(post => res.json(post));
});
axios
const postData = {
title: '?',
text: '?'
};
axios
.post('/api/posts', postData)
.then(res => console.log(res))
.catch(err => console.log(err));
Get params
**!But this title should be assigned a value. not a null value**
router.post('/:title'),
(req, res) => {
const newPost = new Post({
eventTitle: req.params.title,
eventText: req.body.eventText
});
newPost.save().then(post => res.json(post));});
const postData = {
title: '?',
text: '?'
};
axios
.post(`/api/posts/${postData.title}`, postData.text)
.then(res => console.log(res))
.catch(err => console.log(err));
If you have any questions about fetch, you can use this https://developer.mozilla.org/en-US/.
I hope this is useful for you. Actually, I never used fetch, but axios is same with it.
PS: you should add this for your server.js to get value from the client side.
Node.js body parsing middleware. Parse incoming request bodies in a
middleware before your handlers, available under the req.body
property.
const bodyParser = require('body-parser');
// for parsing application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// for parsing application/json
app.use(bodyParser.json());
Last answer for your comment and your issue.
First, you should add proxy to your client side package.json
You cannpm I concurrently to run your server and client simultaneously
Your package.json should include --- I did't create a server json, this may a wrong format. But just a test. The part of ** should be written in the server package.json file! If you don't want to use it, you can just focus on the code, it will fix your problem.
{
"name": "react",
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^0.18.0",
"body-parser": "^1.18.3",
"concurrently": "^4.0.1",
"express": "^4.16.4",
"fetch": "^1.1.0",
"node-fetch": "^2.2.0",
"react": "^16.4.2",
"react-dom": "^16.4.2",
"react-scripts": "1.1.4",
"isomorphic-fetch": "^2.2.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
**"server": "node server.js",**
**"client": "npm start",**
**"dev": "concurrently \"npm run server\" \"npm run client\"",**
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:5000"
}
npm I node-fetch at client side
import React, {Component} from 'react';
//import axios from 'axios';
//import fetch from 'node-fetch';
import fetch from 'isomorphic-fetch';
class SendMessage extends Component {
constructor(props) {
super(props);
this.state = {
title: '',
text: ''
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onSubmit(e){
e.preventDefault();
const newUser = {
title: this.state.title,
text: this.state.text,
};
// axios.post('/users/create', newUser)
// .then(res => console.log(res))
// .catch(err => console.log(err));
fetch('/users/create', {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(newUser)
}).then(res=>res.json())
.then(res => console.log(res));
}
onChange(e){
this.setState({[e.target.name]:e.target.value})
}
render() {
return (
<div>
<form onSubmit={this.onSubmit}>
<input type="text" name='title' onChange={this.onChange} value={this.state.title} placeholder="title"/>
<input type="text" name='text' onChange={this.onChange} value={this.state.text} placeholder="text"/>
<input type="submit" value="Submit"/>
</form>
</div>
);
}
}
export default SendMessage;
Server side server.js
const express = require ('express');
const bodyParser = require('body-parser');
//import route
const users = require('./route');
var app = express();
//Body parser middleware
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
// Use routes
app.use('/users', users);
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server running on port ${port}`));
Server side route.js
const express = require('express');
const router = express.Router();
router.post('/create', (req,res) => {
console.log(req.body);
const user =
{
title: req.body.title ===null ? 'Untitled Note' : req.body.title,
text: req.body.text
};
res.status(200).json(user);
});
module.exports = router;
You're sending a request to '/user/create' when your Node.js server is listening on 'create'. Try changing
fetch('http://localhost:3001/user/create'
to
fetch('http://localhost:3001/create'
My best way, start create file api.js
import axios from "axios";
export default {
user: {
createBio: data => axios.post(`${process.env.API_HOST}/user/create`, {data}).then(res => res),
}
}
and then you can call function createBio from your component or action if you use redux,
if you get problem Access-Control-Allow-Origin use CORS
You can use body-parser middleware to parse the body of your request
in your server.js:
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json({limit: '10mb'}));
and supposing you send an object to the server like:
let data = {
myProp: 'myVal1'
}
You can then get it in the request:
router.post('/create', (req,res,) => {
let value = req.body.myProp;
console.log('value in body: ' + value);
// execute...
});
This will log:
value in body: myVal1
I would also strongly recommend using Axios for your requests instead of fetch, and read my answer in this post where I discuss some differences and how to implement axios if you are using fetch already. This way you don't need to stringify your data for example, and you solve other issues discussed there.
If you use Axios (with async/await), set your request object like so:
let reqObj = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8'
},
url: 'http://localhost:3001/user/create',
data: {
myProp: 'myVal1'
}
};
And send the request to axios with:
let response = await axios(reqObj);

Record all remote calls in a nodejs express app for testing

The goal is to have recored api tests. This test are kind of integration tests, they load the whole app with all its middlewares and intercepts the external http calls and records them.
In Python world exists "WebTest" and "VCRPY" for that.
The app:
'use strict';
const express = require('express');
const request = require('superagent');
var app = express();
app.get('/hammer/version', function(req, res) {
request
.get('http://httpbin.org/get')
.end(function(err, response) {
console.log(response.body);
res.status(200).json({
version: '0.1.0',
url: response.body.url
});
});
});
module.exports = app;
The test:
/* global describe, it */
'use strict';
const request = require('supertest');
const app = require('./app.js');
var path = require('path');
var tape = require('tape');
var tapeNock = require('tape-nock');
// call tapeNock with tape and an options object
var test = tapeNock(tape, {
fixtures: path.join(__dirname, 'fixtures')
});
describe('Version test', function() {
this.timeout(0);
it('test version', function(done) {
test('record_version.json', function(t) {
request(app)
.get('/hammer/version')
.expect(200, {
url: "http://httpbin.org/get",
version: '0.1.0'
})
.end(function(err, res) {
if (err) return done(err);
t.end();
done();
});
});
});
});
The "package.json":
{
"name": "remote_node_test",
"version": "1.0.0",
"description": "",
"main": "app.js",
"dependencies": {
"express": "^4.14.0",
"mocha": "^3.2.0",
"nock": "^9.0.2",
"superagent": "^3.3.1",
"supertest": "^2.0.1",
"tape": "^4.6.3",
"tape-nock": "^1.4.0"
},
"devDependencies": {
"mocha": "^3.2.0"
},
"scripts": {
"test": "mocha"
},
"author": "",
"license": "ISC"
}
The test are run with "mocha":
NOCK_BACK_MODE=record node_modules/mocha/bin/mocha
First run works, second run with "lockdown/record" does not work.
The error:
% NOCK_BACK_MODE=lockdown node_modules/mocha/bin/mocha test.js :(
Version test
TAP version 13
# details.json
1) return current version
0 passing (32ms)
1 failing
1) Version test return current version:
TypeError: Cannot read property 'status' of undefined
at Test._assertStatus (node_modules/supertest/lib/test.js:263:10)
at Test._assertFunction (node_modules/supertest/lib/test.js:281:11)
at Test.assert (node_modules/supertest/lib/test.js:171:18)
at Server.assert (node_modules/supertest/lib/test.js:131:12)
at emitCloseNT (net.js:1553:8)
at _combinedTickCallback (internal/process/next_tick.js:71:11)
at process._tickCallback (internal/process/next_tick.js:98:9)
Recorded are all requests, but i need only to record the "external" requests, and prevent "mocking/recording" my internal logic.
If you're using mocha, you may want to look for a similar nock/nockBack helpers that are mocha-specific (https://www.npmjs.com/search?q=mocha+nock)
That being said, you may also run into problems where the HTTP call supertest makes to the app gets picked up by nockBack.
I made a little example that uses only tape to do what you're trying to accomplish:
https://github.com/Flet/tape-nock-with-supertest-example
The afterRecord and before functions defined in setup-tape-nock.js are probably the secret sauce you would need even if using some other nockBack mocha helper.
Hope this helps!
One solution seems "replay" and configuring "passThrough" of requests to my local app.
/* global describe, it */
'use strict';
const request = require('supertest');
const app = require('./app.js');
var path = require('path');
const Replay = require('replay');
Replay.fixtures = __dirname + '/fixtures/replay';
Replay.passThrough('localhost', '127.0.0.1', '0.0.0.0');
describe('Version test', function() {
this.timeout(0);
it('test version', function(done) {
request(app)
.get('/hammer/version')
.expect(200, {
url: "http://httpbin.org/get",
version: '0.1.0'
})
.end(function(err, res) {
if (err) return done(err);
done();
});
});
});

Categories