At the time of writing this blog post, I am one week removed from graduating college. As a college student, the projects I undertook were always assigned by a professor as an exercise or group project. As a result, I haven’t launched a project that wasn’t under the supervision of some educational figure since I was in high school. And while some might say that all practice is good practice, I would argue that this consistent assignment process fails to exercise that most important muscle in a young developer’s brain: the creativity muscle. That being said, now that I can build a project without any regulatory background noise, I knew it was time to break down the creative barriers that had been under construction for the last four years.
My thought process for picking a project idea was simple — I wanted to be uncomfortable, and I wanted to learn something new and exciting.
For people reading this that don't understand why I’m taking on this project or are thinking this project was simply an idea that came to me in my sleep, some context might be needed. This project is an assessment for a job interview at a company that I would very much like to work for. Some readers might think that submitting a project that uses ideas and technologies that you have never previously used is somewhat irresponsible. Still, I say to those people, “fortune favors the brave.” The following blog post will give you a complete overview of how I built The Map Game, from the birth of the idea to the final build and everything in between. I hope you enjoy it!
Before I get into the project idea, it might first be helpful to understand the deliverables.
Build a project of your choice using the ShipEngine API. The complexity isn’t
important. It should demonstrate your ability to understand the ShipEngine API
documentation and make API calls.
What you build is up to you. It could be a CLI, a website, a mobile app, a chatbot,
a game, or anything else. You can also use other APIs or vendor products in
combination with ShipEngine in some interesting way.
Show us your creativity!
Here are some things I took away from the deliverables.
- The project must use the ShipEngine API
- A game
After reading this, the first step was to go over to the ShipEngine docs for some inspiration. And that's when I came across address validation.
Make a POST request with as little as a street, city, and state and get back a verified or unverified message. It's simple, yet it’s a very flexible tool in its use cases and, in my mind, had a wide variety of applications. And as I previously mentioned, I wanted this project to make me uncomfortable, and I wanted to learn something new and exciting. So, for me, the address validation tool gave a lot of creative space to think outside the box.
The next step was to nail down how I was going to use the address validation tool. I knew that I wanted to build a game, and I knew I would be validating addresses at some point, but I was struggling with how I was going to tie everything together.
And then it hit me. What is the one application I use nearly every day that requires an address? Google Maps.
A payload of addresses is sent to the ShipEngine API. Then, the verified addresses are stored in some data structure and iterated over. Finally, each address gets sent to the google maps API, and the user has to guess the location of the street view.
While this checks most boxes for the project requirements, it’s using ideas and technologies that I have previously used. It needs something else. It needs to be bigger than just a single-player web game.
In the long list of project ideas that might cause slight development discomfort, a multiplayer game is near the top.
So here is what we got so far.
The gameplay will be similar to the single-player idea. However, instead of hardcoded addresses, the connected clients will input addresses and send them to their opponents.
The gameplay timeline
- Two users join a game lobby through a WebSocket connection.
- One user inputs an address and sends it to their opponent.
- The address is validated using the ShipEngine API.
- The address is then sent to the Google Maps Street View API and displayed to the opponent.
- The Opponent then has to guess what state the street view is located in.
A brief Websocket overview
Let's rewind the clocks to the early days of the internet when life was simple. Tim Berners-Lee had just rolled out HTTP: a groundbreaking technology that would forever change the way we think about the internet.
People could now connect directly to servers rather than other people. They could make a GET request and, in turn, receive an HTML web page. Then, a couple of iterations later, we got an array of different requests: POST, PUT, and DELETE. But, there was a problem.
While it was amazing that we could ask a server for some information and a web page would appear, that initial connection is lost after the server responds. Every time the client wanted more information, a new connection had to be established. We needed something faster and more dynamic.
But, what if we wanted more? What if we wanted the data in real-time?
Enter Websockets. Websockets are an HTTP upgrade that allows for real-time data transfer. A client can make the same initial request and response in the form of the web page, but now if the server happens to get more data, the server immediately sends that data down to all connected clients. When you send a message in a chat application, the server receives it and immediately sends that message to all connected clients. To get technical, Websockets solve that inherent connection problem that HTTP has; they are full-duplex, bi-directional lines of communication.
The Build Agenda
- Connect to the server
- Create Game
- Join Game
Step 1: Connecting to the server
The client first needs to set up a connection. Once the client attempts to connect to the server, the HTTP server gets upgraded to a WebSocket connection. After the connection is established, the first response that the WebSocket makes will be to send a unique client identification number(ID). This ID will be used to identify each client throughout the game.
Step 2: Creating a game
After the client initializes a WebSocket connection, they will now have the ability to create a game. The client sends their client ID, and in return, they receive a game object. Within the game object, the client will receive a unique game ID and a client array. The game ID will be used to identify the current game uniquely. The client array will be used to store the connected opponent's ID.
Step 3: Joining a game
After the client has created a game, they can now choose to send the game ID to another client to join the newly created game—the client requests with their unique client ID and the game ID they received from their opponent. In response, the server sends back an updated version of the game object. The client's ID gets pushed onto the client array within the game object with some more important identification information: name and color. They also receive a score that will be updated every time they make a correct guess.
Step 4: Play
After the game has been created and both the clients have joined the game, it is now time to play. The game creator's job is to start the game by sending and an address to the server. There is a three-step process to getting the initial inputted address to display as a street view on the opponent's interface.
First, the US state the address is located in is saved in a game state variable to check the opponent's guess. Second, the address is validated using the ShipEngine API. The server makes a POST request and waits for a “verified” or “unverified” response. If the address is “unverified,” the server responds to the client with an “invalid address” response and waits for a new address to be submitted. If the address is verified, it gets sent to Google’s Geocode API to convert the address into longitude and latitude coordinates. Finally, the coordinates are packaged and sent to the opponent. Subsequently, the coordinates are plugged into the Google Street View API and displayed.
The client is now able to make a guess. They input their guess and send it to the server. Next, the server checks the guess against the correct state variable. If the guess is incorrect, the server responds with an incorrect message and the correct state. If the guess was correct, the client's score is incremented by one, and the updated game state is sent out to both clients. Finally, the turn is changed, and the game continues until a winner is crowned.
Step 5: Code!
Finally! We have made it to the best part.
Setting up the Node.js server
The first step is to get an express server set up to deal with all client-facing HTML pages. The port environment variable is there for Heroku, the cloud hosting service I am using. I also went ahead and got fetch ready to go for the ShipEngine and Google Maps APIs.
The next step is getting the Websocket server ready. Like I mentioned before, Websockets is an upgraded version of HTTP, but until the client and the server agree to upgrade, the server will remain as a primary HTTP server.
After everything is set up, the WebSocket waits for an on-request event to begin. And there it is, a beautiful full-duplex TCP connection.
Setting up the Client
From this point, setting up the client is very straightforward. First, turn on the Websocket and wait for an even to start sending data. Then, as an example, we will walk through when a client submits an address.
After the client has input all the necessary fields, the data is packaged into JSON payload and sent to the server.
Upon receiving the data, the server sends the data to be validated by ShipEngine and subsequently sends the data to be converted to longitude and latitude coordinates. Finally, the coordinates are sent to the opponent.
Upon receiving a message from the server, the client takes the coordinates and plugs them into the Street View API.
That’s all there is to it!
Thanks for reading — if you made it this far, you might want to check out the finished product on Git Hub.