Realtime updates in iOS Swift 5 using Socket.IO with MySQL and Node.js

Spiro Mifsud
8 min readNov 28, 2017

Many of the examples online demonstrate how great sockets are for real time chat rooms. While, this is a great application for Socket.IO, we can also use Socket.IO to signal a web or mobile application to update when data is changed via an API. This can be a great alternative to something like Realm or Firebase if you are looking for a solution that utilizes a relational database, that is not too abstracted, and allows you more flexibility.

In this example, we’ll be working on a simple iOS Swift 5 App that will be notified when data is changed in our relational database via a simple API. All the server and iOS code can be found here: https://github.com/smifsud/realtime

These are the steps we’ll go through:

  • Create a local Node and MySQL server with some sample content.
  • Create a simple API in Node.js that will accept a user identifier (token) and return the associated data
  • Capture a client token and the socket ID on the server by storing in an array*
  • Update table API. when any change happens. all connected tokens that belong to that newsgroup will get notified via a message emitted with a unique namespace (token), socketID, and event name
  • iOS updates. Capture an event and update the app.

In our hypothetical app, there are newsgroups that certain users have access to that contain headlines from different news outlets. In our iOS app, we’ll have a UITableView that contains the relevant headlines. When a change is made via our simple API, a server side functions will check the server to find a relationship with the changed data and, if there is a live connection (socket.IO connection) the server will emit an event to to that specific client connection and user token that is associated with a user ID.

*In our example we will want to be mindful of socket IDs. I’ve found that this point is absent from many tutorials, but should be accounted for. For instance, when using a command like socket.on Any, the application can still pick up messages emitted over the wire even if the a specific even it isn’t subscribed to it. In addition to specifying a namespace, we want to also specify the socket.IO ID that a message is being emitted over to be efficient with our calls — and to make sure that not every client is receiving a ping during any activity being transmitted that may be irrelevant to our specific user.

Server and Dependencies

The first step is to install the necessary dependencies. In this example we will use Node.js, Express, MySQL, and Socket.IO. I’ve written this geared towards a Mac user. Provided below are commands for convenience to install the dependencies needed via Terminal. Note: the Node.js MySQL driver needs to be installed in addition to MySQL.

MySQL (executable .pkg installer) https://dev.mysql.com/downloads/mysql/5.1.html#macosx-dmg

Node.js and NPM (from the Terminal)

$ brew install node

Express (from the Terminal)

$ npm install express --save

Node MySQL Driver (from the Terminal)

$ npm install mysql --save

Socket.IO (from the Terminal)

$ npm install socket.io --save

Database and Content (Server Side)

Assuming you are on a Mac, double-click/run the MySQL install package. At the end of the database install we’ll need to start and login to MySQL with the temporary password given in the final install window

Inside the Terminal window use the following command to login. Type in the temporary password when prompted

$ mysql -u root -p

After logging in, we’ll need to change the temporary password to something else. In this example, I’ve changed the password to ‘pwd123’. Note:This is a terrible password. In a real production environment you would never use the Root user and a weak password.

mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'pwd123';

Next, we will connect to the local MySQL instance and put in a simple database schema and content. The below tables include the headlines, newsgroups, and who has access to them based on a username and login token. I’ve left out the login process and assumed that there will be an identifier to be passed in our API to identify our user ID and also associate later with our Socket.IO id.

If you aren’t comfortable with the command line, Sequel Pro (https://sequelpro.com) is a great MySQL management app. You can quickly connect to the local MySQL instance using parameters like below and excute the SQL .sql file provided in project files located on GIT to create all the tables and content used in this example.

Database — ‘news’

To quickly create the tables and sample content. Import the contents of the .sql file into the Query window. Highlight and then select Run Selection.

The following tables should be created in a database called news

Node.js API (Server Side)

Now we’ll want to create a simple API to send back data with token and socketIO. We’ll also want to establish a Socket.IO connection so that we can send data back in ‘realtime’.

First, let’s establish our database connection. Check out the file connection.js.

The second file, app.js, will establish the simple GET API to retrieve all the headlines. Additionally, we will have an POST API call that will edit a headline and then notify relevant connected users of the change.

app.get ('/headlines', function (request, response)

If you’re following along with the database structure. the headlines API call will retrieve the headlines based on the user token with the following SQL command:

http://localhost:3000/headlines/?token=ABC438s

SELECT newsgroupID,newsgroup, headline from headlines JOIN newsgroups ON headlines.newsgroupID = newsgroups.id where newsgroupID = (SELECT newsgroup_id FROM user_newsgroups where user_id = (SELECT userID FROM users where token = ?))’ , [req.token]
JSON sent following the above headlines API call

Additionally we have a POST API call ‘headline’ that will insert a new headline into the database. This will take a newsgroup ID and a headline. Note: For simplicity, there is no token check on this command, but something that should be considered when altering data.

app.post ('/headlines', function (request, response)

which runs the following SQL

INSERT INTO headlines VALUES (null,?,?)' , [request.query.newsgroup,request.query.headline]

Following the INSERT statement we a function emitHeadlineEvent() that will loop through live socket connections stored in an array to make sure we broadcast our change event to a client that is in fact connected to the server via a socket. I’ve also added an additional check to make we are only broadcasting to users who are included in the headlines table. It wouldn’t make much sense to broadcast messages to sockets that didn’t have this feature or didn’t have data that was relevant. Also, remember we don’t want to just broadcast to a namespace, we want to broadcast to a namespace and a specific connected socket. To see step-by-step, follow the comments inside the app.js file.

Finally to get the server started, navigate to the server files via your Terminal and use the command

node app.js

Once we have our iOS app running we will insert a new headline for the app to update in realtime.

iOS App (Client Side)

Now, that our server is set up, we’re ready to start our iOS app. The complete project is located inside the project folder under xcode.

We’ll need to do the following steps:

  • Start new Project. Single View App
  • Install Cocoapods dependency Socket.IO client
  • Create a function to access the API and parse the JSON received
  • Create an eventHandler for when a subscribed to Socket.IO event is received
  • Redraw table

Let’s get started! I’ve named the iOS project realtime in the example files.

Next we’ll import the Socket.IO library via Cocoapods. If you need detailed instructions on how to do this, the Cocoapods site offers a complete step-by-step guide.

We’ll create a file in our project directory called PodFile, by calling

pod init

Inside the Podfile, we will edit to include the Socket.IO library.

After the file has been created, run the install from the Terminal

pod install

Now open the xcwordspace file. We’ll work in there.

Since we’ll be making server calls, we’ll need to allow permission via the info.plist. For simplicity, I’ve set Allow Arbitrary Loads to YES. Of course, this should contain the specific URLs you plan to call in a real production project.

For simplicity and this example ONLY.

Inside ViewController, we make a socket connection to the server and provide the server with our token. This way the server can capture that and associate it with an socket connection ID to emit events to this specific app.

Also, we need to add a Struct to use for Swift 5’s JSON functions.

In a real application you’d probably put this in seperate files

This will be used when we call the function getHeadlines(). Inside this function we make a call to the local server we have running and append a token. Again, this makes an assumption that the application will have a login/registration sorted out and supply a token. In this case, it’s hardcoded to the URL. After the data is loaded and placed into an Array for a tableView, it will reload the table with the new data.

And lastly, we have a function called setSocketEvents() that will handle connection events and a notification that the headlines have been updated. this will then call getHeadlines() and call the server for the new headlines information.

With the server running locally start up the iOS app in the iOS Simulator. you should see the headlines inside a tableview.

To see make sure the table is updating in realtime, we can call the POST headlines and add a new headline. Doing this, will add a new headline and then call the function to emit a notification to relevant connected clients.

An easy way to do this is using an application like Postman.

using the URL for our API along with parameters for newsgroup and headline we can insert a new headline.

*** be sure to use the newsgroupID 1, since our hardcoded token belongs to this group.

After hitting the POST API you should see the iOS app update almost instantaneously.

--

--