The purpose here is to go over some basic web stuff and get a server up and running, with maybe a web interface.

1. legend

1.1. terminal commands

A source block with a $ in front generally means this is a command you should run as your normal user from within a terminal or shell. Commands on your system are programs, and you should either only run commands you understand and/or originate from a trusted (by you) source. If the command is prefixed with a # it means to run the command with elevated permissions, such as the root user or as a sudoer using sudo. Generally commands that want elevated permissions should be treated with greater scrutiny.

$ ls -al

This means copy ls -al and paste it into your terminal (on MacOS, Terminal.app works just fine for this). Then press enter. You should see some output from the command, or a lack of error. Sometimes seeing it do nothing is okay. Once the command is complete, you’ll see the prompt displayed again (usually ending with $) which means the shell is ready for the next command.

Some instructions will also omit the $ entirely but provide some context that this is a command you should be running. Usually this means you run the command the same way you would as $, and NOT # (root).

Sometimes you’ll see what seems to be both $ and not $ in the same block. Generally this means that the $ is the command you run, and the text that follows that isn’t preceded by a $ is the output of the command(s).

For example:

$ ls
foo bar baz

Here we’re running ls and, as a contrived example, we’re seeing it print foo bar baz as its output.

1.2. shell

A terminal is a window that runs a shell. A shell is a program that lets you input commands and you can see the results. A good shell can provide lots of assistance in putting together commands, and has a means of composition of those commands. Composition is something we’ll get more into later. The commands themselves are too many to enumerate, and learning them is a place where you can spend indefinite amounts of time mastering. Focus on learning parts of the shell only a little bit at a time.

2. tools

We’ll need some tools installed to ease this along.

2.1. system software

2.1.1. homebrew

Homebrew is needed to install some basic stuff. Follow the link and follow it’s instructions. See the shell and terminal commands section for learning how to install Homebrew.

Once you have that, we’ll want to install Homebrew’s cask system, which allows us to install apps (which can be considered to be a little different from commands and utilities). We’ll want to use cask later in your system setup, so let’s install it now:

brew tap caskroom/cask

2.1.2. Node.js

Once Homebrew is installed, we can install a recent version of Node.JS, which we’ll need for running a server. The version we install isn’t terribly important right now. Run this command to install Node:

brew install node

2.1.3. yarn

yarn is a replacement for npm. You don’t need to know npm but understand there is a lot of legacy projects out there with their install instructions using npm. For the most part, any place you see npm you can substitute with yarn and the command will work fine. One notable exception is that npm install <package> maps to yarn add <package>. Here, <package> refers to the name of a package without the angle braces (<>). A package named foo would be installed with yarn add foo.

Install yarn with Homebrew using this command:

$ brew install yarn

2.1.4. git

git is a version control system. It’s a vital tool for software development as it performs incremental backups of your source code. It provides a rich history (provided you leave messages for yourself) and allows you to easily share your code with others.

I don’t recall if MacOS has a version pre-installed, but I do know that with Homebrew we can ensure we’re using it and also be on the latest version:

brew install git

2.2. editor

Atom is a plenty good starter editor. It’s basic. It’s a pretty Notepad with plugins and indentation. For now, this is fine.

You can install Atom via homebrew as well!

brew cask install atom

Once this is done, you can run Atom from your terminal using the atom command, or run it as an application from the /Applications directory. You can also open Spotlight by pressing Command-Space and typing “atom” without the quotes.

3. your development directory

Your development directory is a place where you can throw all of your software projects. It seems like everyone has their own convention and no two are alike. You can’t really get this wrong, but generally you might be typing it a bit so keeping it short and sweet is nice. For this doc we’re going to use dev but really you can use anything you like so long as you can remember it easily.

mkdir dev

mkdir creates the dev directory. Now we’ll enter the directory. mkdir is a program that will only print something if something goes wrong, so if it looks like nothing happened, that’s okay. No news is good news.

cd dev

After running this, you should see dev in your shell’s prompt.

4. take a break

Good job! Let’s take a minute to look around and not see a screen for a few minutes.

5. setting up your project

Let’s make sure your terminal is in your development directory.

$ pwd
/Users/logan/dev

Let’s make a directory for our project. This project will be about expressing our deep hatred of cats. Cats killed my parents, okay?

mkdir cat-hate

And enter the directory:

cd cat-hate

Now let’s let yarn initialize our project:

yarn init

It will prompt you with some questions. If you don’t know a good answer, or are fine with its guess, you can use the default (which is the value in the parenthesis ()). Enter default values by pressing enter.

Let’s also get git initialized.

git init

We’ll be running a Node server using a library called express. We can use yarn to install it.

yarn add express

6. creating your first node app

Now we’re going to open our editor. We can open it with a file (or even a blank file that doesn’t exist yet) by giving the atom command an argument. The argument is the name of the file we want to open or create. Let’s name it server.js.

atom server.js

We need to pull in express. In Node, we do that using require.

Put this into your editor:

const express = require('express')

express is a function that produces an “application” in their terms. Let’s create that now.

const app = express()

Now we’ll construct an endpoint by listening to GET requests. We’ll just listen to ones directed at the root of our webapp for now.

app.get('/', (req, res) => {
  res.send('ohai')
})

There’s a lot going on there, even for a very simple response handler. We’ll go over that in a bit, but let’s get it so we can run the server first, and then test that it works.

app.listen(3000, () => console.log('Example app listening on port 3000!'))

Okay, so all together this is what it should look like:

const express = require('express')

const app = express()

app.get('/', (req, res) => {
  res.send('ohai')
})

app.listen(3000, () => console.log('Example app listening on port 3000!'))

Let’s run the app:

$ node server.js
Example app listening on port 3000!

Now let’s make a new tab in your terminal (Command-T on MacOS). You might have to cd back to your project directory:

cd ~/dev/cat-hate

Now we’ll test that it works with curl, a powerful tool for using and debugging HTTP requests.

$ curl http://localhost:3000
ohai

7. what the hell just happened?

In short, thousands of little assumptions we make in the world of technology came together and something actually worked.

In the long, let’s talk about networking.

7.1. layers

Networked architecture exists as a series of abstract layers. We’ve heard so much about how computers are all about 1s and 0s but we need to derive meaning from those. Usually in the world of computing, we aren’t thinking about those individual bits. Instead we’re thinking in “abstract” terms. For our purposes, abstract means we’ve moved to a conceptual place where we can focus on only the things that matter about our topic. As we move between layers we can think about just the areas of focus for that layer, because we can assume other layers have done their jobs. This is a mental tool we use because the amount of things that need to happen for a web page to load is staggering. Breaking down these things into to tiny concepts that are easy to mentally digest is perhaps the hardest problem we have in computer engineering (and perhaps other forms of engineering as well).

Here we’ll go over the various network layers. You don’t need to memorize them, but knowing they are there is helpful. These are presented in order.

7.1.1. physical layer

This is the medium in which the communication happens. This could be radio waves, a fucking wire, or even study hall notes. Barbed wire was used to demo Ethernet, so I’m told.

7.1.3. network layer

Hey wait, aren’t we talking about networks already? Confusing! Well this specifically refers to routing of network traffic over multiple devices. This is how information from your computer travels over your wifi, goes through your router, and then goes out to the Internet. Most often the network layer you’ll be working with is IP (just IP) but there are others.

7.1.4. transport layer

This is primarily a layer about checking for errors and retransmission of lost data. TCP and UDP are transport layers. Sometimes you hear TCP referred to as TCP/IP but that’s mostly referring to how they typically go together.

7.1.5. session layer

This layer is about handshakes and establishing persistent connections. It also can handle forms of authentication and reconnection. TCP and UDP both span across this and the transport layer.

7.1.6. presentation layer

This is primarily about encryption but could be anything that converts data from one form to another. Encryption is generally handled at the OS level.

7.1.7. application layer

These aren’t applications themselves, but means to communicate with applications. How do you talk to a specific application on your computer? If I run a server on my computer, will it be the only one? No. You can run lots and lots of servers, and you’re probably running lots of them right now without realizing it. In the world of TCP and UDP, applications are denoted by something called a “port”. Some of them are reserved for specific kinds of applications, but there’s not necessarily a strict enforcement there.

7.2. the request and response model

HTTP (Hyper Text Transfer Proctocol) is an application layer protocol that we use for almost all of our web technology. The client (which is typically a web browser, but could also be virtually anything) sends something called a request to the server. The server processes this request, and sends back some kind of response.

7.2.1. how web pages work in http

When you go to a site like http://google.com, your browser sends a GET request to Google. There’s some additional meta data your browser will send along as well, such as saying automatically that you prefer US English, and that it wants HTML. Google’s servers see this request, and the server decides it will send you back a web page (in HTML) for the response. It will also ensure the web page is in US English.

Your browser will see that Google’s homepage has link tags to CSS files, so it will send additional requests to download those. If there are script tags that have src attributes, it will also send requests for those. The Google web servers will dutifully respond with the requested CSS and JavaScript files in kind.

request-response-html-example-01.svg

This is a sequence diagram that shows the communication process of doing something like visiting http://google.com.

7.2.2. what about curl?

curl is our command line HTTP tool. We can send requests with it like it was a browser, and we can get the response back. We can give curl “flags” that tell it to give us more information about what it’s sending and what it receives. In the instructions above, we tested our server using curl because it doesn’t tend to complicate things like the browser can easily do. We can use curl to automate communication to any web server as well, and since everyone has curl or can get it somehow, we can send curl commands (as text) to anyone else and they can run it and verify our results. This is handy when you need to get help with something and need to consistently produce the same results across machines.

8. next up

For our next trick, we’ll send some nice HTML.