Cannot Established connection to Express Websocket Server from Nuxt JS using nuxt-socket-io - express

I have this following problem where I cannot establish connection from nuxt js app to express websocket
Here's my following code :
Server Side (websocket server) at index.js
const express = require('express');
const app = express();
const http = require('http').createServer(app);
const io = require('socket.io')(http, {
cors: {
origin: '*'
}
});
const port = 4000;
http.listen(port, () => {
console.log('server is up');
io.on('connection', (socket) => {
console.log('Connection established');
console.log(socket.id);
})
})
Client Side (nuxt js)
In nuxt.config.js
...
modules: [
...
'nuxt-socket-io'
]
...
io: {
sockets: [{
name: 'arena',
default: true,
url: 'http://localhost:4000',
}]
}
In component that uses websocket :
<template></template>
<script>
export default {
data() {
return {
socket: {},
};
},
mounted() {
this.socket = this.$nuxtSocket({
name: "arena",
channel: "/index",
reconnection: false,
});
this.socket.emit('connection')
},
};
</script>
The error I got from console log is :
GET http://localhost:4000/socket.io/?EIO=4&transport=polling&t=OMPZ7YZ&sid=WOhe-UjXtVOJoPlIAAAG 400 (Bad Request)
And the console.log from the server does not produce any output
What did I missed?

Related

Why can I not set/see the cookie in my browser dev tools?

I am following Ben Awads Reddit Clone Tutorial and have a problem with setting a cookie.
I have an express app and I am trying to set a cookie if the user provides a correct username and password to my GraphQL mutation. When I use Apollo GraphQLs Sandbox to send a login request. I can see in the Network Tab, that there is a Set-Cookie Header with the correct data. But when I send a request to see if there is another query and check for req.session.userId it is undefined.
Here is my index.ts file:
import 'reflect-metadata';
import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import { PrismaClient } from '#prisma/client';
import { buildSchema } from 'type-graphql';
import { PostResolver } from './resolvers/post';
import { UserResolver } from './resolvers/user';
import { __prod__ } from './constants';
import { MyContext } from './types';
import session from 'express-session';
import connectRedis from 'connect-redis';
import { createClient } from 'redis';
const prisma = new PrismaClient();
const main = async () => {
const app = express();
const RedisStore = connectRedis(session);
const redisClient = createClient({ legacyMode: true });
redisClient.connect().catch(console.error);
app.use(
session({
name: 'qid',
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 10, // 10 years
httpOnly: true,
sameSite: 'lax', // lax fรผr csrf
secure: __prod__, // cookie only works in https
},
secret: 'keyboard cat',
store: new RedisStore({ client: redisClient }),
saveUninitialized: false,
resave: false,
})
);
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [PostResolver, UserResolver],
validate: false,
}),
context: ({ req, res }): MyContext => ({ prisma, req, res }),
});
await apolloServer.start();
apolloServer.applyMiddleware({ app });
app.listen(4000, () => {
console.log('Server is running on http://localhost:4000');
});
};
And here is my users resolver:
#Resolver()
export class UserResolver {
// create a me query
#Query(() => UserType, { nullable: true })
async me(#Ctx() { prisma, req }: MyContext) {
// you are not logged in
if (!req.session.userId) {
return null;
}
const user = await prisma.user.findUnique({
where: {
id: req.session.userId,
},
});
return user;
}
#Mutation(() => UserResponse)
async login(
#Arg('options') options: UsernamePasswordInput,
#Ctx() { prisma, req }: MyContext
): Promise<UserResponse> {
const user = await prisma.user.findUnique({
where: {
username: options.username,
},
});
if (!user) {
return {
errors: [
{
field: 'username',
message: 'That username does not exist',
},
],
};
}
if (!(await argon2.verify(user.password, options.password))) {
return {
errors: [
{
field: 'password',
message: 'Incorrect password',
},
],
};
}
req.session.userId = user.id;
return {
user,
};
}
}
I tried using different versions of the dependencies "connect-redis", "redis" and "express-session"

Vue 3, Socket IO - not listening to event

For server side I have following code:
const path = require("path");
const http = require("http");
const express = require("express");
const {instrument} = require('#socket.io/admin-ui')
const app = express()
const server = http.createServer(app)
const io = require("socket.io")(server, {
cors: {
origin: ["https://admin.socket.io", "http://localhost:3001"],
credentials: true
},
});
instrument(io, { auth: false });
server.listen(3000, () =>
console.log('connected')
)
io.on('connection', socket => {
console.log("user connected");
socket.on("join", function (room) {
console.log(room);
socket.join(room);
});
socket.on('newOrder', function (data) {
socket.emit('this', data)
console.log(data);
})
socket.on("thisNew", function (data) {
console.log('this new');
});
socket.on('disconnect', () => {
console.log('user disconnected');
});
})
and in the Vue (client side) I have following:
import VueSocketIO from 'vue-3-socket.io'
import SocketIO from 'socket.io-client'
export const useSocketIO = () => {
const socket = new VueSocketIO({
debug: true,
connection: SocketIO('http://localhost:3000')
})
return {
socket,
}
}
And in the component:
<script setup>
import { useSocketIO } from "#/services/socketio"
const { socket } = useSocketIO()
onMounted(async () =>
{
await socket.io.emit('join', 'servant')
socket.io.on('this', () =>
{
console.log('event this fired')
})
})
</script>
Event this is emitted from the server, but nothing is happening on the client side. What am I doing wrong here?

Failing to setup Websocket link

Been trying to get a Subscription working with Hasura and Vue Apollo with a websocket link with Vue Apollo with Vue3. Have it all seemingly setup.
The subscription works in Hasura so thatโ€™s right.
The query version worked with the HTTP link.
So the WS Link for some reason is just not working it. It seems like it might be authentication Iโ€™m not passing in correctly for some reason?
import './tailwind.css'
import App from './App.vue'
import { routes } from './routes.js'
import { createRouter, createWebHistory } from 'vue-router'
import { ApolloClient, createHttpLink, InMemoryCache } from '#apollo/client/core'
import { DefaultApolloClient } from '#vue/apollo-composable'
import { createAuth0 } from '#auth0/auth0-vue';
import { split } from 'apollo-link'
import { WebSocketLink } from 'apollo-link-ws'
import { getMainDefinition } from 'apollo-utilities'
import { HttpLink } from 'apollo-link-http'
const token = localStorage.getItem('Auth_token')
// HTTP connection to the API
const httpLink = new HttpLink({
// You should use an absolute URL here
uri: 'https://XXXXXXXXXXX.hasura.app/v1/graphql',
headers: {
"content-type": "application/json",
"x-hasura-admin-secret": "XXXXXXXXXXX",
"Authorization": `Bearer ${token}`,
}
})
// Create the subscription websocket link
const wsLink = new WebSocketLink({
uri: 'ws://XXXXXXXXXXX.hasura.app/v1/graphql',
options: {
reconnect: true,
timeout: 30000,
inactivityTimeout: 30000,
lazy: true,
},
connectionParams: {
headers: {
"content-type": "application/json",
// "x-hasura-admin-secret": "XXXXXXXXXXX",
"Authorization": `Bearer ${token}`,
}
}
})
// using the ability to split links, you can send data to each link
// depending on what kind of operation is being sent
const link = split(
// split based on operation type
({ query }) => {
const definition = getMainDefinition(query)
return definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
},
wsLink,
httpLink
)
// Cache implementation
const cache = new InMemoryCache()
// Create the apollo client
const apolloClient = new ApolloClient({
link,
cache,
connectToDevTools: true,
})
const app = createApp({
setup () {
provide(DefaultApolloClient, apolloClient)
},
render: () => h(App),
})
const router = createRouter({
history: createWebHistory(),
routes,
})
// router.beforeEach(async (to, from) => {
// console.log("it's here", this.$auth0)
// // if (
// // // make sure the user is authenticated
// // ) {
// // // redirect the user to the login page
// // }
// })
app.use(router)
app.use(
createAuth0({
domain: "XXXXXXXXXXX",
client_id: "JgajoigAywNqoIyvQWNJjpq6TS3g5Ljn",
// redirect_uri: "http://localhost:3000/the-clouds"
redirect_uri: window.location.origin
})
);
app.mount('#app')
Main.JS file
subscription working
subscription in vue apollo front end
error 1
error 2
Figured it out! Was headers setup wrong. Wooh!
// Create the subscription websocket link
const wsLink = new WebSocketLink({
uri: 'ws://XXXXX-backend.hasura.app/v1/graphql',
options: {
reconnect: true,
timeout: 30000,
inactivityTimeout: 30000,
lazy: true,
connectionParams: {
headers: {
"content-type": "application/json",
"x-hasura-admin-secret": "XXXXX",
"Authorization": `Bearer ${token}`,
}
}
},
})

How do I make Heroku to listen to multiple ports?

I am trying to host my application on Heroku but I get the below error from the logs:
Error: listen EADDRINUSE: address already in use :::27427
Apollo Server:
const { ApolloServer } = require("apollo-server");
const typeDefs = require("./server/graphql/typedefs");
const resolvers = require("./server/graphql/resolvers");
const server = new ApolloServer({ typeDefs, resolvers });
server.listen({ port: process.env.PORT || 4000 }).then(({ url }) => {
console.log(`๐Ÿš€ Apollo Server ready at ${url} ๐Ÿš€`);
});
// Express server
const express = require("express");
const app = express();
const cors = require("cors");
app.use(express.json());
app.use(
cors({
origin: "http://localhost:3000",
})
);
const stripe = require("stripe")("sk_test_51Kv9RvGa9sOwxIsovOU0IliCRkL4Qrvi0F1dis4M4Slk1TvEzcuYrx4zBuLZH1iU76ygkDtoXA3Gky6RJEdaBTDa00fDh2Oh1g");
app.post("/create-checkout-session", async (req, res) => {
try {
const session = await stripe.checkout.sessions.create({
customer_email: req.body.email ? req.body.email : undefined,
payment_method_types: ["card"],
mode: "payment",
line_items: req.body.items.map((item) => {
return {
price_data: {
currency: "usd",
product_data: {
name: item.name,
},
unit_amount: item.price * 100,
},
quantity: item.quantity,
};
}),
success_url: `http://localhost:3000/paymentsuccess/${req.body.secret}`,
cancel_url: `http://localhost:3000/paymentfailed/${req.body.secret}`,
});
res.json({ url: session.url });
} catch (e) {
res.status(500).json({ error: e.message });
}
});
app.listen({ port: process.env.PORT || 5001 }, () => {
console.log("๐Ÿš€ Express server ready at http://localhost:5001 ๐Ÿš€");
});
I think the issue is that I am using both Apollo Server and Express Server in my app. But I need the express for my stripe application. Is there a way so that Heroku can listen to both of my ports?

Computed object is undefined when post requesting via axios (Vuex)

I've set up a node express server with post method on localhost/send and vue app on localhost.
Vue app is working perfect, even on remote machine.
Post request requires json object and it sends an mail via nodemailer.
It works when I make post request via postman app.
Problem appears when I want to send email making post request via Vue app (axios). I store whole email data in Vuex and use "computed" to use it in my component. I can render data, but in my email whole data is undefined.
What am I doing wrong?
Code below:
node server
const express = require('express');
const bodyParser = require('body-parser');
const nodemailer = require('nodemailer');
const path = require('path');
const app = express();
app.use('/', express.static(path.join(__dirname, 'render')));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname+'/render/index.html'));
});
app.post('/send', (req, res) => {
const email = {
name: req.body.name,
email: req.body.email,
phone: req.body.phone,
startPoint: req.body.startPoint,
endPoint: req.body.endPoint,
dateTime: req.body.dateTime
};
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: 'mail.advertidea.pl',
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: 'emailIsCorrect', // generated ethereal user
pass: 'passIsCorrect' // generated ethereal password
},
tls:{
rejectUnauthorized:false
}
});
// mail for admin
// setup email data with unicode symbols
let adminMailOptions = {
from: '"GoodTransfer" <test#advertidea.pl>', // sender address
to: 'kamil.grzaba#gmail.com', // list of receivers
subject: 'New transfer request', // Subject line
html: `<p>${email.name}, asks for transfer.<p><br>
<p>Transfer details:</p><br><br>
<p>starting point: ${email.startPoint}</p>
<p>ending point: ${email.endPoint}</p>
<p>date and time: ${email.dateTime}</p><br><br>
<p>clients email: ${email.email}</p>
<p>phone number: ${email.phone}</p>` // html body
};
// send mail with defined transport object
transporter.sendMail(adminMailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log('Message sent: %s', info.messageId);
console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info));
});
Vuex store
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
email: {
name: '',
email: 'test#test.pl',
phone: '',
startPoint: '',
endPoint: '',
date: new Date().toISOString().substr(0, 10),
},
},
getters: {
email: state => state.email,
},
mutations: {
updateEmail(state, email) {
this.state.email = email;
},
},
actions: {
},
});
Vue component
import axios from 'axios';
export default {
name: 'Book',
data() {
return {
newEmail: '',
valid: false,
emailRules: [
v => !!v || 'E-mail is required',
v => /.+#.+/.test(v) || 'E-mail must be valid',
],
};
},
computed: {
email: {
get() {
return this.$store.state.email;
},
set(value) {
this.$store.commit('updateMessage', value);
},
/* return this.$store.getters.email; */
},
},
methods: {
submitForm() {
console.log(JSON.stringify(this.email));
axios.post('http://goodtransfer.pixelart.pl/send', JSON.stringify(this.email), 'json')
.then((res) => {
console.log(res);
console.log(res.data);
});
},
},
};
Ok, I just found out what was the problem. When You make request via axios You should use object as a payload, not already strigified data.