When connecting keeps returning 404 not found becasue Socket.io adds a slash after route.
http://localhost:3000/api/route/?EIO=3&transport=polling
Whereas Next.js would only accept something like this apparently:
http://localhost:3000/api/route?EIO=3&transport=polling
./pages/api/route.js
const http = require('http');
const micro = require('micro');
const server = micro((req, res) => {
console.log('endpoint connection')
});
const options = { path: '/api/route', cookie: false };
const io = require('socket.io')(new http.Server(server), options);
function connection(socket) {
console.log('socket.io connection');
}
io.on('connection', connection);
export default server;
./pages/index.js
[...]
const socket = io('http://localhost:3000', { path: '/api/route' });
[...]
By adding a question mark to the path: { path: '/api/route?' } the error goes away but the on.('connection' event of Socket.io still doesn't fires.
I expect my Socket.it client to connect to the serveless API route on which the Socket.io server is mounted, ideally without other packages besides Socket.io, but otherwise is not a problem of course.
http and/or [email protected] or any other version of it (without that at all)?I'm trying to setup too a socketio server/client in my next.js project.
I checked a lot articles talking about "react socketio express" and they all set the socketio server with the express instance like:
// server.js
const app = require('express')();
const server = require('http').Server(app);
const io = require('socket.io')(server);
io.on('connection', socket => {
// your stuff
});
In our case, we do not have access directly to the express instance.
According to the blog post of the version 9, express is used under the hood to allow the developper to have File system-Based Dynamic Routing and API Routes.
API Routes are used
to retrieve data from a database or to process data provided by your users (e.g. a contact form).
That's why I think, @sorleone, it's not the right place to setup a socketio server.
In 2017, we could do it like this but I don't think it's a good idea now, with the actual state of nextjs.
I'm looking to for the "right way" to doing it 😃
I'm trying to setup too a socketio server/client in my next.js project.
I checked a lot articles talking about "react socketio express" and they all set the socketio server with the express instance like:
// server.js const app = require('express')(); const server = require('http').Server(app); const io = require('socket.io')(server); io.on('connection', socket => { // your stuff });In our case, we do not have access directly to the express instance.
According to the blog post of the version 9, express is used under the hood to allow the developper to have File system-Based Dynamic Routing and API Routes.
API Routes are used
to retrieve data from a database or to process data provided by your users (e.g. a contact form).
That's why I think, @sorleone, it's not the right place to setup a socketio server.
In 2017, we could do it like this but I don't think it's a good idea now, with the actual state of nextjs.
I'm looking to for the "right way" to doing it smiley
Thank you so much for your contribution! Are you sure that Next.js uses Express for API routes (I have read the article)? I thought it uses ZEIT Micro and in fact they need to add the various "helpers" that otherwise Express would already provide. Do you also have the problem with the trailing slash?
I'm not 100% percent sure. It's just that, in version 9, they released File system-Based Dynamic Routing, which was done manually by the users (thanks to Express as far as I saw on stackoverflow or in different blog posts) before.
They mentionned Express in their official release note.
Moreover they have express in their dependencies.
Should we run a separate server (running on a different port ?) or is there an elegant way to setting up socketio with nextjs ?
In my case I also wanted to keep Next api routing. Using Express would break that without adding more custom code. This is the solution I came up with based on the Next and Socket.io docs.
const next = require('next');
const app = next({ dev: process.env.NODE_ENV !== 'production' });
const handler = app.getRequestHandler();
const { createServer } = require('http');
const { parse } = require('url');
app.prepare().then(() => {
const server = createServer((req, res) => {
const parsedUrl = parse(req.url, true);
handler(req, res, parsedUrl);
});
server.listen(3000, err => {
if (err) throw err;
console.log('> Ready on http://localhost:3000');
});
const io = require('socket.io')(server);
io.on('connection', socket => {
// your stuff
});
});
To get access to the socket.io instance in my api routes I ended up putting it in the global scope. (Would love a better solution for this if someone knows a better way.)
global._io = require('socket.io')(server);
and in my route:
const io = global._io;
io.on();
I'm also curious to what extent Express is being used in Next. ZEIT makes Micro, I assume in large part for this project, but Express does show up as a dependency. And interestingly, micro is not a dependency. 🤷♂️
Anyways, it's possible to create a custom server without using Express, and keeping some of the Next magic.
Edit: I just dug through Next's code and the only usage of Express I found was in Examples and Tests.
@KolbySisk I have the same issue, and as a solution for not using a global object I'm passing the io instance into each request as context, so it can only be accessed from an API handler:
import { parse } from 'url'
import next from 'next'
import socketIO from 'socket.io'
import { createServer } from 'http'
const context = {
io: null
}
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
const requestListener = (req: any, res: any) => {
// Be sure to pass `true` as the second argument to `url.parse`.
// This tells it to parse the query portion of the URL.
const parsedUrl = parse(req.url, true)
req.context = context
handle(req, res, parsedUrl)
}
app.prepare().then(() => {
const port = parseInt(process.env.PORT || '3000', 10)
const server = createServer(requestListener)
context.io = socketIO(server)
context.io.on('connection', client => {
console.log(client.id, 'connected')
client.on('disconnect', () => {
console.log(client.id, 'disconnected')
})
})
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`)
})
})
@franky47 @KolbySisk these are all very nice solutions, but how do we do this by using the serverless API routes provided by Next.js in the /pages/api folder?
@sorleone Your original issue could be related to lifetime, where the serverless function would exit before your Socket.io clients have time to connect.
In the end, serverless functions are short-lived, and Socket.io connections are long-lived, so unless you manage to keep the Socket.io server alive between serverless calls (in some sort of context/state shared across invocations), I don't see how these two solutions could work together.
@franky47 Woo, thanks for that. I was trying to find a way to avoid adding it globally. Didn't think to add it to the request.
@sorleone My solution works (and so should franky's, but I haven't tested) with api routes. It does require a custom server to persist the socket server, but you can still use the Next api routes and all the auto-config magic that comes with them.
Since @sorleone was talking about serverless, I took it as using Zeit Now (or a similar serverless service) to invoke those routes:
Documentation: https://nextjs.org/docs#serverless-deployment
Example: https://github.com/zeit/now-examples/tree/master/nextjs
My comment above is related to such a deployment style, which seems incompatible with the nature of Socket.io IMHO.
It's currently not possible to export a server as the API route are tailored to serverless functions and websockets require a running server deployment etc.
this is working for me (in development)
@timneutkens Will this ever be supported? I want to add subscriptions to my API route running apollo-server-micro
Most helpful comment
In my case I also wanted to keep Next api routing. Using Express would break that without adding more custom code. This is the solution I came up with based on the Next and Socket.io docs.
To get access to the socket.io instance in my api routes I ended up putting it in the global scope. (Would love a better solution for this if someone knows a better way.)
global._io = require('socket.io')(server);and in my route:
I'm also curious to what extent Express is being used in Next. ZEIT makes Micro, I assume in large part for this project, but Express does show up as a dependency. And interestingly, micro is not a dependency. 🤷♂️
Anyways, it's possible to create a custom server without using Express, and keeping some of the Next magic.
Edit: I just dug through Next's code and the only usage of Express I found was in Examples and Tests.