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
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"
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?
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}`,
}
}
},
})
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?
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.