Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Socket.io with Next.js API Routes

Next.js provides serverless API routes. By creating a file under ./pages/api you can have your service running, and I want to have a Socket.io service by using this mechanism.

I have created a client:

./pages/client.js

import { useEffect } from 'react'; import io from 'socket.io-client';  export default () => {    useEffect(() => {     io('http://localhost:3000', { path: '/api/filename' });   }, []);    return <h1>Socket.io</h1>; } 

And an API route:

./pages/api/filename.js

const io = require('socket.io')({ path: '/api/filename' });  io.onconnection = () => {   console.log('onconnection'); }  io.on('connect', () => {   console.log('connect'); })  io.on('connection', () => {   console.log('connection'); })  export default (req, res) => {   console.log('endpoint'); } 

But I can't get the client to connect to the Socket.io server and succesfully see any of: 'onconnection', 'connect', or 'connection' printed.

like image 326
Aurelius Avatar asked Aug 15 '19 15:08

Aurelius


People also ask

Can I use Socket.IO with NextJS?

Socket.io architecture In order to establish dual-side communication, we need a server and a client. Since we're using NextJS our server-side will be placed in the NextJS API folder, while the client-side will be coded into each page that will need it.

Can Socket.IO connect to WebSocket?

Although Socket.IO indeed uses WebSocket for transport when possible, it adds additional metadata to each packet. That is why a WebSocket client will not be able to successfully connect to a Socket.IO server, and a Socket.IO client will not be able to connect to a plain WebSocket server either.

Does vercel support WebSockets?

Serverless Functions on Vercel are stateless and have a maximum execution duration. As a result, it is not possible to maintain a WebSocket connection to a Serverless Function.


2 Answers

The trick is to plug 'socket.io' into the http server only once, so checking every access to the api. Try something like this:

./pages/api/socketio.js

import { Server } from 'socket.io'  const ioHandler = (req, res) => {   if (!res.socket.server.io) {     console.log('*First use, starting socket.io')      const io = new Server(res.socket.server)      io.on('connection', socket => {       socket.broadcast.emit('a user connected')       socket.on('hello', msg => {         socket.emit('hello', 'world!')       })     })      res.socket.server.io = io   } else {     console.log('socket.io already running')   }   res.end() }  export const config = {   api: {     bodyParser: false   } }  export default ioHandler 

./pages/socketio.jsx

import { useEffect } from 'react' import io from 'socket.io-client'  export default () => {   useEffect(() => {     fetch('/api/socketio').finally(() => {       const socket = io()        socket.on('connect', () => {         console.log('connect')         socket.emit('hello')       })        socket.on('hello', data => {         console.log('hello', data)       })        socket.on('a user connected', () => {         console.log('a user connected')       })        socket.on('disconnect', () => {         console.log('disconnect')       })     })   }, []) // Added [] as useEffect filter so it will be executed only once, when component is mounted    return <h1>Socket.io</h1> } 
like image 89
rogeriojlle Avatar answered Sep 18 '22 17:09

rogeriojlle


You have to have the /api/pusher/auth to authenticate with pusher on the frontend. Then you use the key you get from that to communicate with pusher. It's for security purposes. You can do it all through the frontend, but depending on your app, if you're saving data (such as messages, or chats) then probably should authenticate.

like image 33
Alex Cory Avatar answered Sep 19 '22 17:09

Alex Cory