Getting Started with Typescript and Socket.Io - Tutorial
Last Updated - 24th December, 2018
Welcome friends! In this tutorial, we are going to be looking at how you can build a websocket based server using both TypeScript and Socket.io.
We’ll be covering the following:
- What WebSockets are and why they are beneficial
- Building a Simple TypeScript WebSocket Server
- Building a Simple client to connect to our Server
- Two-way communication between our client and our server
WebSockets
WebSockets are an awesome technology and I absolutely love playing around with them and creating real-time applications. I’ve used them for quite a number of different applications now in combination with other frontend frameworks such as Angular and Vue.JS.
Socket.io makes dealing with WebSockets a pleasurable and easy experience and the library is generally well supported regardless of what frontend framework you tend to run with.
In this tutorial, we’ll be using ExpressJS
as the backend web framework that
our Websocket API will sit on top of.
The full source code for this repo can be found here: TutorialEdge/TypeScript
Introduction
We are going to start off by defining a really simple TypeScript based
Express.js server that will listen on port 3000. Whenever a user hits
http://localhost:3000/
our REST API it will return a very simple
hello world
.
Create a new file called server.ts
within a src/
directory and add the
following:
// src/server.ts
import * as express from "express";
const app = express();
app.set("port", process.env.PORT || 3000);
var http = require("http").Server(app);
// simple '/' endpoint sending a Hello World
// response
app.get("/", (req: any, res: any) => {
res.send("hello world");
});
// start our simple server up on localhost:3000
const server = http.listen(3000, function() {
console.log("listening on *:3000");
});
You’ll need to install express
and @types/express
in order for the above to
run successfully. Run yarn init
or npm init
to initialize our project and
then run the following:
$ yarn add express @types/express
Once you’ve installed these libraries, we will need to define our
tsconfig.json
file in order to tell our TypeScript compiler how we wish our
project should be built. Create this file in the root directory of your project:
// tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": false,
"target": "es6",
"noImplicitAny": true,
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist",
"baseUrl": ".",
"paths": {
"*": [
"node_modules/",
"src/types/*"
]
}
},
"include": [
"src/**/*"
]
}
Building our Project
Now that we’ve set up our tsconfig.json
file and we’ve got our src/server.ts
file, we can attempt to build and subsequently run this app:
$ tsc
$ node dist/server.js
Should there be no errors, this will kick off our server running on port 3000
.
Attempt to hit this now by navigating to http://localhost:3000
in your
browser.
Automatically Rebuilding and Re-running
Obviously, as we start to develop this out more, we don’t want to have to
perform the above commands every time we wish to test what we’ve done works.
Let’s install the concurrently
node_module as well as nodemon
to
concurrently run our tsc -w
and nodemon dist/server.js
commands:
$ yarn add concurrently nodemon
Now, within our package.json
we’ll wish to add the following scripts
:
{
"name": "socket-typescript-api",
"version": "1.0.0",
"main": "dist/server.js",
"license": "MIT",
"scripts": {
"build": "tsc",
"watch-ts": "tsc -w",
"watch-node": "nodemon dist/server.js",
"watch": "concurrently -k -p \"[{name}]\" -n \"TypeScript, Node\" -c \"yello.bold, cyan.bold\" \"yarn run watch-ts\" \"yarn run watch-node\"",
"test": "mocha -r ts-node/register src/**/*.spec.ts"
},
"dependencies": {
...
},
"devDependencies": {
...
}
}
Now, we can just run yarn run watch
and it will automatically rebuild and
rerun our TypeScript based project every time we make a change. This is
invaluable as it saves you a lot of time in the long run.
Implementing our Websocket Endpoint
Now that we have a basic express
server, let’s add the code we’ll need for our
socket.io
based endpoint.
We’ll first have to install socket.io
by calling:
$ yarn add socket.io @types/socket.io
Now that we’ve got the necessary dependencies, we can import socket.io
as
socketio
and do the following:
import * as express from "express";
import * as socketio from "socket.io";
import * as path from "path";
const app = express();
app.set("port", process.env.PORT || 3000);
let http = require("http").Server(app);
// set up socket.io and bind it to our
// http server.
let io = require("socket.io")(http);
app.get("/", (req: any, res: any) => {
res.sendFile(path.resolve("./client/index.html"));
});
// whenever a user connects on port 3000 via
// a websocket, log that a user has connected
io.on("connection", function(socket: any) {
console.log("a user connected");
});
const server = http.listen(3000, function() {
console.log("listening on *:3000");
});
Now, when we run our yarn run watch
command, it should start up our incredibly
simple websocket API.
Testing This Works
Now that we’ve implemented the server, let’s implement a really clean and simple
./client/index.html
page that we can serve. This will simply contain a single
<button />
element that, when hit, will emit
a new message
event to the
WebSocket connection which simply contains HELLO WORLD
:
<!-- ./client/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<button onClick="sendMsg()">Hit Me</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
<script>
const socket = io("http://localhost:3000");
function sendMsg() {
socket.emit("message", "HELLO WORLD");
}
</script>
</body>
</html>
When we try and hit http://localhost:3000
in our browser, we should see our
index.html
page rendering our button. We should see, in our server logs, that
a new user has connected as we’ve triggered the connection
event.
Listening for Messages
So, in the above index.html
we emit a message
of Hello World
. If we want
to listen to this within our server, we can add the following code:
import * as express from "express";
import * as socketio from "socket.io";
import * as path from "path";
const app = express();
app.set("port", process.env.PORT || 3000);
let http = require("http").Server(app);
// set up socket.io and bind it to our
// http server.
let io = require("socket.io")(http);
app.get("/", (req: any, res: any) => {
res.sendFile(path.resolve("./client/index.html"));
});
// whenever a user connects on port 3000 via
// a websocket, log that a user has connected
io.on("connection", function(socket: any) {
console.log("a user connected");
// whenever we receive a 'message' we log it out
socket.on("message", function(message: any) {
console.log(message);
});
});
const server = http.listen(3000, function() {
console.log("listening on *:3000");
});
If we kill our server and restart, we should see that whenever our client’s
<button/>
element is clicked, it will emit a message
that will be logged out
by our server side!
When we run this, and click the button a few times on our client-side, we should see the following log output on our server:
$ node dist/server.js
listening on *:3000
a user connected
HELLO WORLD
HELLO WORLD
HELLO WORLD
Awesome, we’ve managed to successfully send a message from our client to our WebSocket server using the socket-io package.
Two-Way Communication
Now that we’ve got basic one-way communication up and running, let’s try going back the way and send an echoed response from our server back to the client whenever it receives a message.
We’ll first have to add a listener on our client for new message events. Within
the <script/>
tag, let’s add a new listener:
<script>
const socket = io("http://localhost:3000");
// listen for new messages
socket.on("message", function(data) {
console.log(data);
});
// our sendMsg function...
</script>
We can then add a call to socket.emit()
in our socket.on('message')
callback
function that emit’s the received message back down the WebSocket connection:
// ...
io.on("connection", function(socket: any) {
console.log("a user connected");
socket.on("message", function(message: any) {
console.log(message);
// echo the message back down the
// websocket connection
socket.emit("message", message);
});
});
Perfect, now that we have that in place, we can test it out. Reload your browser page and make sure your server has recompiled/restarted successfully.
Notice how, whenever you click the button on your server, it now sends a message to our server, which is outputted in the logs. This message is then emitted back to the client and you should be able to see the same message outputted in the browser console.
Challenge - Try modifying the message sent from the server back to the client. You should see this newly modified message being printed out only in your client’s browser console.
Conclusion
In this tutorial, we’ve successfully managed to create a socket.io TypeScript server that can be connected to using a frontend in order to display any real-time events you wish.
Note - If you want to keep track of when new articles are posted to the site, then please feel free to follow me on twitter for all the latest news: @Elliot_F.