I have an existing API project in express js. Socket js is also implemented here. I want to Implement a new module in nest js and run express, socket, and nest on the same server, where express and socket-based APIs will remain unchanged. I could successfully run express and nest on the same server but the socket is not working.
Bellow app.js creates an express server and exports the server.
App.js
const express = require("express");
const app = express();
app.get("/hello", (req, res) => {
res.json({
success: true
})
});
module.exports = {
expressApp: app
};
In the entry point of the nest project, the expressApp will be Imported and will be adapted with nest by ExpressAdapter function
main.ts
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
import { expressApp } from "../../app.js";
import { ExpressAdapter } from '#nestjs/platform-express';
async function bootstrap() {
const app = await NestFactory.create(AppModule, new ExpressAdapter(expressApp));
return await app.listen(3000);
}
bootstrap();
This works fine. The express route and the nest controller return success.
If I initiate the socket to App.js
const io = require('socket.io')(app);
io.on('connection', () => { console.log("connected") });
then it returns an error as the app is not an http.Server instance.
Error: You are trying to attach socket.io to an express request handler function. Please pass a http.Server instance.
at Server.attach (C:\Users\yotech20\Desktop\combine\node_modules\socket.io\dist\index.js:167:19)
at new Server (C:\Users\yotech20\Desktop\combine\node_modules\socket.io\dist\index.js:75:18)
at module.exports (C:\Users\yotech20\Desktop\combine\node_modules\socket.io\dist\index.js:599:33)
at Object.<anonymous> (C:\Users\yotech20\Desktop\combine\app.js:31:30)
at Module._compile (internal/modules/cjs/loader.js:1085:14)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
at Module.load (internal/modules/cjs/loader.js:950:32)
at Function.Module._load (internal/modules/cjs/loader.js:790:12)
at Module.require (internal/modules/cjs/loader.js:974:19)
at require (internal/modules/cjs/helpers.js:101:18)
I cannot create a server instance in App.js
const server = require('http').createServer(app);
const io = require('socket.io')(server);
io.on('connection', () => { console.log("connected") });
and pass that instance in the socket as the nest doesn't allow it.
Now, How Can I run this socket server with express and nest?
Related
I have an express app that uses MongoDB, and I'm trying to deploy it to Heroku.
After deployment, it seems to work, but after a few minutes, it crashes. Before it crashes if I try to make a request to the API I get the following error.
"message": "Operation `users.findOne()` buffering timed out after 10000ms",
When it does crash, these are the message that i get from heroku cli
These are the main files
server.js
import express from 'express'
import connectDb from './config/db.js'
import router from './routes/userRoutes.js'
import { errorHandler } from './middleware/errorMiddleware.js'
import cors from 'cors'
const port = process.env.PORT || 5000
connectDb()
const app = express()
app.use(cors())
app.use(express.json())
app.use(express.urlencoded({extended: false}))
app.use('/api/user', router)
app.use(errorHandler)
app.listen(port, () => console.log(`server started on ${port}`))
db.js
import mongoose from "mongoose";
const connectDb = async () => {
try{
const conn = await mongoose.connect(process.env.URL)
console.log(`MonngoDb Connected: ${conn.connection.host}`)
} catch(error){
console.log(error)
process.exit(1)
}
}
export default connectDb
Procfile
web: node backend/server.js
The App works fine on my local machine but just crashes when deployed.
How can I fix this
Fixed: Just needed to whitelist Heroku on network access
I am running into issues when testing my express application. All tutorials use app.listen instead of https.createServer and I don't know how to properly use testing frameworks with the latter. The code:
test_node/app.js
var express = require("express");
const app = express();
app.set('port', process.env.SERVER_PORT || 443);
app.get('/', function(req, res){
res.status(200).send('OK');
});
module.exports = {
app: app
}
test_node/server.js
var https = require('https');
var fs = require('fs');
const app = require('./app');
let serverOptions = {
key: fs.readFileSync('./cert/server.key'),
cert: fs.readFileSync('./cert/server.cert')
}
const server = https.createServer(serverOptions, app)
server.listen(app.get('port'), function () {
console.log(`Express HTTPS server listening on port ${app.get('port')}`);
});
async function handleSignal(signal) {
console.log(`Received ${signal}`);
server.close();
process.exit();
}
process.on('SIGINT', handleSignal);
process.on('SIGTERM', handleSignal);
process.on('uncaughtException', handleSignal);
test_node/test/test.js
const request = require('supertest')
describe("Test the root path", () => {
let server;
beforeAll(function () {
server = require('../app');
});
afterAll(function () {
server.close();
});
test("It should respond to the GET method", async () => {
const response = await request(server).get("/");
expect(response.statusCode).toBe(200);
});
});
test_node/package.json
{
"name": "test_node",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "node server.js",
"test": "jest"
},
"author": "",
"license": "ISC",
"devDependencies": {
"jest": "^26.6.3",
"supertest": "^6.1.3"
},
"dependencies": {
"express": "^4.17.1"
}
}
The error I get when I test the above code with jest (jest --runInBand test.js):
TypeError: app.address is not a function
at Test.Object.<anonymous>.Test.serverAddress (C:\code\test_node\node_modules\supertest\lib\test.js:57:18)
at new Test (C:\code\test_node\node_modules\supertest\lib\test.js:38:12)
at Object.get (C:\code\test_node\node_modules\supertest\index.js:27:14)
at Object.<anonymous> (C:\code\test_node\test\test.js:13:48)
at Object.asyncJestTest (C:\code\test_node\node_modules\jest-jasmine2\build\jasmineAsyncInstall.js:106:37)
at C:\code\test_node\node_modules\jest-jasmine2\build\queueRunner.js:45:12
at new Promise (<anonymous>)
at mapper (C:\code\test_node\node_modules\jest-jasmine2\build\queueRunner.js:28:19)
at C:\code\test_node\node_modules\jest-jasmine2\build\queueRunner.js:75:41
This is obviously a stripped down version of my code. I also create MongoDB connections at start, but I removed them for simplicity. Ideally I want to use async/await instead of promises for creating my server (and MongoDB connections) before my tests start. I also need to close those connections after tests end or fail. In your answer you can safely assume I'm JS beginner :).
Additional info
I'm using node '14.15.4' on Windows 10 x64. Webstorm IDE.
Tried various combinations of the following:
combining app and server in one file (see below)
creating the server in a separate function and exporting it
using mocha/chai instead of jest
testing a stripped down version of the app
Errors I get depending on the combinations I tried:
TypeError: app.address is not a function
TypeError: app.get is not a function
EADDRINUSE: address already in use ::::443
various other errors with timeouts, wrong arguments, etc.
Relevant topics that didn't help (or I overlooked something):
Simple node http server unit test
Is it possible to create an Express.js server in my Jest test suite?
TypeError: app.get is not a function
Mocha API Testing: getting 'TypeError: app.address is not a function'
Getting "TypeError: "listener" argument must be a function" in Node.Js
Jest/Supertest errors with TypeError: app.address is not a function
https://blog.campvanilla.com/jest-expressjs-and-the-eaddrinuse-error-bac39356c33a
https://glebbahmutov.com/blog/how-to-correctly-unit-test-express-server/
https://rahmanfadhil.com/test-express-with-supertest/
https://zellwk.com/blog/endpoint-testing/
https://taylor.fausak.me/2013/02/17/testing-a-node-js-http-server-with-mocha/
https://www.albertgao.xyz/2017/05/24/how-to-test-expressjs-with-jest-and-supertest/
Context
I included the server.js file above, although the test doesn't use it, because my server application should also be able to start normally when I run node server.js. With the above code it doesn't start and I get the following error:
events.js:112
throw new ERR_INVALID_ARG_TYPE('listener', 'Function', listener);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "listener" argument must be of type function. Received an instance of Object
at checkListener (events.js:112:11)
at _addListener (events.js:348:3)
at Server.addListener (events.js:406:10)
at new Server (https.js:71:10)
at Object.createServer (https.js:91:10)
at Object.<anonymous> (C:\code\test_node\server.js:9:22)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14) {
code: 'ERR_INVALID_ARG_TYPE'
}
However, if I put all code in the same app.js file and I run node app.js, then the app starts fine, although the test produces the same error.
test_node/app.js
var https = require('https');
var fs = require('fs');
var express = require("express");
var server;
const app = express();
app.set('port', process.env.SERVER_PORT || 443);
app.get('/', function(req, res){
res.status(200).send('OK');
});
async function handleSignal(signal) {
console.log(`Received ${signal}`);
server.close();
process.exit();
}
process.on('SIGINT', handleSignal);
process.on('SIGTERM', handleSignal);
process.on('uncaughtException', handleSignal);
let serverOptions = {
key: fs.readFileSync('./cert/server.key'),
cert: fs.readFileSync('./cert/server.cert')
}
server = https.createServer(serverOptions, app).listen(app.get('port'), function () {
console.log(`Express HTTPS server listening on port ${app.get('port')}`);
});
module.exports = {
app: app,
server: server
}
To clarify, my question is how to fix the error from the jest test and not about the error when I run node server.js - the latter is just for context.
As #jonrsharpe pointed out in the comments, I was assuming that with module.exports I export the app itself, but in fact I export an object containing the app. Therefore to fix the test error, I had to simply write in my test.js:
server = require('../app').app;
instead of server = require('../app');. Similarly, in server.js I had to write:
const app = require('./app').app;
This fixes both errors I mentioned in my question (TypeError: app.address is not a function).
Credits to #jonrsharpe for helping me find the solution!
I am building a simple chat application using Socket.io, Node.js, and React.js.
The server on the backend connects fine at first.
However when trying to make requests to the server from my front end the server keeps on crashing. Anyone understand why?
Here is the error..
[nodemon] 2.0.4
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node index.js`
server started on port 4000
new connection
events.js:109
throw new ERR_INVALID_ARG_TYPE('listener', 'Function', listener);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "listener" argument must be of type function. Received undefined
at checkListener (events.js:109:11)
at _addListener (events.js:344:3)
at Socket.addListener (events.js:402:10)
at Namespace.<anonymous> (/Users/macbook/Projects/chat-react/server/index.js:16:10)
at Namespace.emit (events.js:311:20)
at Namespace.emit (/Users/macbook/Projects/chat-react/server/node_modules/socket.io/lib/namespace.js:213:10)
at /Users/macbook/Projects/chat-react/server/node_modules/socket.io/lib/namespace.js:181:14
at processTicksAndRejections (internal/process/task_queues.js:79:11) {
code: 'ERR_INVALID_ARG_TYPE'
}
[nodemon] app crashed - waiting for file changes before starting...
currently my server looks like this
index.js
const express = require ('express');
const socketio = require('socket.io');
const http = require('http');
const PORT = process.env.PORT || 4000;
const router = require('./router');
const app = express();
const server = http.createServer(app);
const io = socketio(server);
io.on('connection', (socket) => {
console.log('new connection');
socket.on('disconnect'), () => {
console.log('User has left!!');
}
});
app.use(router);
server.listen(PORT, () => console.log(`server started on port ${PORT}`));
and my client looks like this
Chat.js
import React, { useState, useEffect } from 'react';
import quertString from 'query-string';
import io from 'socket.io-client';
let socket;
const Chat = ({ location }) => {
const [name, setUserName] = useState('');
const [room, setRoomID] = useState('');
const ENDPOINT = 'localhost:4000';
useEffect(() => {
const { name, room } = quertString.parse(location.search);
socket = io(ENDPOINT);
setUserName(name);
setRoomID(room);
console.log(socket)
});
return (
<h1>Chat</h1>
)
};
export default Chat;
any help would be great.
You have an error with your code. Look here:
socket.on('disconnect'), () => {
console.log('User has left!!');
}
Notice something? Yes, the function you wanted to call is not in the parentheses. Even though that wouldn't cause a syntax error, you probably didn't want to do that. Instead, you need to put the function inside the parentheses, like so:
socket.on('disconnect', () => {
console.log('User has left!!');
});
Note: to learn more about the comma operator, refer to these sites:
https://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator.
JS statement separator with commas
I have a native C++ module that is spun up by a worker thread from node.js, which works great. From within that node module, I can call my native methods like "AddToLog()" and it works great.
I also need to service web requests, which is my dilemma. So I used express and included a file to start it up on a worker thread. That also works fine - both my native code and the express web server are working at the same time.
However, when I try to 'require' my native module in the file that starts the web server, I get an error that the native module could not be registered.
Have I hit a fundamental limitation where node.js cannot load the same native module on two different worker threads? Or this is as simple as a syntax issue?
My hunch is that I can fix this by making the module context aware, but I'm too new to this to know for sure!
I need the express thread to be able to access the module in order to draw its content. So one thread is running a lighting server that collects data and the other services web requests that describe the current state... if it worked!
// SCRIPT 1
'use strict'
const nightdriver = require('./build/Release/nightdriver.node')
const { Worker } = require('worker_threads');
function startserver()
{
nightdriver.addtolog("[index.js] Starting NightDriver Server");
//nightdriver.startserver();
}
const worker = new Worker("./startweb.js");
nightdriver.addtolog("[index.js] Starting Web Server...");
startserver();
// SCRIPT 2
'use strict'
const nightdriver = require('./build/Release/nightdriver.node')
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello World');
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
events.js:167
throw er; // Unhandled 'error' event
^
Error: Module did not self-register.
at Object.Module._extensions..node (internal/modules/cjs/loader.js:736:18)
at Module.load (internal/modules/cjs/loader.js:605:32)
at tryModuleLoad (internal/modules/cjs/loader.js:544:12)
at Function.Module._load (internal/modules/cjs/loader.js:536:3)
at Module.require (internal/modules/cjs/loader.js:643:17)
at require (internal/modules/cjs/helpers.js:22:18)
at Object.<anonymous> (/Users/dave/OneDrive/Source/Node/nightdriver/startweb.js:2:21)
at Module._compile (internal/modules/cjs/loader.js:707:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:718:10)
at Module.load (internal/modules/cjs/loader.js:605:32)
Emitted 'error' event at:
at Worker.[kOnErrorMessage] (internal/worker.js:332:10)
at Worker.[kOnMessage] (internal/worker.js:342:37)
at MessagePort.Worker.(anonymous function).on (internal/worker.js:279:57)
at MessagePort.emit (events.js:182:13)
at MessagePort.onmessage (internal/worker.js:84:8)
This question already has answers here:
Pass options to ES6 module imports
(9 answers)
Closed 4 years ago.
I am writing a sample code to handle socket connections in node.js using es6 script, on importing socket.io it raises an error
import {
PORT
} from './config';
import express from 'express';
import io from 'socket.io';
var app = express();
// respond with "hello world" when a GET request is made to the homepage
app.get('/', function(req, res) {
res.send('hello world')
});
io.on('connection', function(socket) {
console.log('a user connected');
});
app.listen(PORT, () => console.log(`Example app listening on port ${PORT}!`));
The error is
/index.js:17
_socket.default.on('connection', function (socket) {
^
TypeError: _socket.default.on is not a function
at Object.on (/Users/digvijay.upadhyay/digvijayu/websocket_with_node/src/index.js:15:4)
at Module._compile (module.js:643:30)
at Module._compile (/Users/digvijay.upadhyay/digvijayu/websocket_with_node/node_modules/pirates/lib/index.js:83:24)
at Module._extensions..js (module.js:654:10)
at Object.newLoader [as .js] (/Users/digvijay.upadhyay/digvijayu/websocket_with_node/node_modules/pirates/lib/index.js:88:7)
at Module.load (module.js:556:32)
at tryModuleLoad (module.js:499:12)
at Function.Module._load (module.js:491:3)
at Function.Module.runMain (module.js:684:10)
at Object. (/Users/digvijay.upadhyay/digvijayu/websocket_with_node/node_modules/#babel/node/lib/_babel-node.js:224:23)
[nodemon] app crashed - waiting for file changes before starting...
Successfully compiled 2 files with Babel. Successfully compiled 2
files with Babel.
You need to invoke function require('socket.io')() and pass there an express instance.
Please look at added code example:
const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const app = express();
const server = http.createServer(app);
// this line \/
const io = socketIO(server);
// this line /\
io.on('connection', (socket) => {
//...
});
server.listen(port, () => {
//...
});