Building an App Series Part 6: HTTP and Forms

Launch Academy

By Launch Academy

February 1, 2022

Applied software development, at its core, charges software developers with managing the relationships between users and online beings. In order for users to take advantage of all the wonderful world wide web has to offer, we need a way to communicate with these entities.

Whenever we order something on Amazon, or pay our credit card bills, or unsubscribe from an email list, we are sending data we submit in forms to web servers. They process the information, creating a sales order, updating our credit card balance, or deleting our email address, in accordance with our intended actions.

In previous articles, we have covered essential Ruby functionality and discussed the meta behind software development processes. In this article, we will explore the HTTP protocol and discuss how web pages render HTML dynamically with the help of Ruby.

HTTP and the Web

HTTP (Hypertext Transfer Protocol) is the guideline that directs how information is retrieved from a server and rendered on a client’s browser. When you log onto Facebook, your browser issues a request to Facebook’s server to retrieve all of the information pertinent to your account. Facebook’s server, which is always waiting for incoming requests, subsequently sends a HTTP response for your browser to process.

If the request is valid, the HTTP response contains HTML with information pertaining to your account. Subsequent HTTP requests are issued for CSS stylesheets, JavaScript, and images. Your web browser renders these files as Facebook’s developers intend, allowing to you live vicariously through other people’s food pictures (just kidding).

Deconstructing HTTP Requests

In order to best explain a valid HTTP request, we will set up a basic Sinatra application. As discussed in Part 1, Sinatra is a highly configurable, barebones framework written in Ruby. Let’s use a Sinatra application to break down HTTP requests.

First, use your terminal to create a directory on your computer for this exercise.

$ mkdir sinatra-example
$ cd sinatra-example

Second, install the Sinatra gem.

$ gem install sinatra

Note: if you receive a (Gem::FilePermissionError) error, install Sinatra with the sudo gem install sinatracommand. You will be prompted to enter the password you use to log onto your machine.

After it is finished installing, create a server file in the root directory and a view named home.html in a views folder.

$ touch server.rb
$ touch public
$ cd public
$ touch home.html

Open your server.rb file and add the lines require ‘sinatra' and set :public_folder, File.dirname(__FILE__) + ‘/public' to the top. Next open your home.html file located in your public folderand add:

Hello blog readers!

To run the server, run ruby server.rb on the command line.

$ ruby server.rb

Puma 2.11.1 starting...
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://localhost:4567
== Sinatra (v1.4.6) has taken the stage on 4567 for development with backup from Puma

Note: When we start the server, all of the Ruby code is loaded into memory. Whenever we make changes to our server.rbfile, it is wise to restart the server. In order to restart it, we must stop and start the server again. Also, the above example uses the Puma for running a server. By default, sinatra applications use Webrick.

When we navigate to http://localhost:4567/home.html, you will see the text “Hello blog readers!” If you go back to the terminal, you will see:

::1 - - [23/Mar/2015:10:11:07 -0400] "GET /home.html HTTP/1.1" 200 29 0.0006

What does all of this mean?! Well, when we navigated to http://localhost:4567/home.html in our browser, we sent the web server a GET request to retrieve a certain page, specifically the home.html page in our public folder. GET requests retrieve information from web servers to be displayed on your web browser. When you log onto Facebook, your web browser sends aGET request to Facebook’s servers to retrieve your specific homepage.

POST Requests

POST requests are used to send information from your web browser to an application’s server. When we submit information to a website, whether it be a comment or our credit card information, we send POST requests to transmit user data to an application’s server. We are creating an entry on their database with the information we send. Let’s use our Sinatra application to deconstruct POST requests.

First, let’s add this form to our home.html file.

     

INSERT IMAGE HERE

The action="/home" assignment indicates the path we will want the form to follow. The method="post" assignment identifies what type of action the form needs to perform. We have to correlate these items with a definition in our server. Let’s add the following to our server.rb file.

post ‘/home' do

end

Note: restart the server.

This line tells our Sinatra application that when we submit information in our form, perform the actions within the do-endblock. Since we are not persisting information in a database, we will leave it empty for now.

When we send a POST request to the server, the request’s body contains user-submitted information in key-value hash pairs—for a primer on Ruby data structures, refer to Build an App Part 4: Variable Assignments and Data Structures.

The server logs contain all of the meta-level information pertaining to a given request.

::1 - - [25/Mar/2015:08:50:48 -0400] "POST /home HTTP/1.1" 200 - 32.8957

Additionally, modern web browsers have progress indicators, which tell us how long a request is going to take. Let’s explore one of the key-value pairs in an HTTP response that handles user-submitted information.

Note: For more information on working with HTML forms, check out the Mozilla Developer Network’s guide.

###The Params Hash
Say we fill in our form with “Hey buddy!” and click “Submit”. How will the server identify what information in our POST request to save?

::1 - - [25/Mar/2015:08:50:48 -0400] "POST /home HTTP/1.1" 200 - 32.8957

params
=> {"greeting"=>"Hey buddy!"}

The params hash contains all of the parameters we will eventually want to store in the database. In our example, our phrase “Hey buddy!” is assigned to "greeting", which directly correlates with what we assigned to the "name" variable in our form. How would we isolate our phrase “Hey buddy!”?

::1 - - [25/Mar/2015:08:50:48 -0400] "POST /home HTTP/1.1" 200 - 32.8957

params["greeting"]
=> "Hey buddy!"

We isolate elements by calling our desired parameter’s key, which correlates with the name variable on our form. When our applications become more complicated, the params hash will have a lot more parameters for our use.

For a more detailed explanation on the params hash, check out the Sinatra documentation for examples of different use cases.

HTTP Response Codes

::1 - - [25/Mar/2015:08:50:48 -0400] "POST /home HTTP/1.1" 200 - 32.8957

In the above example, you probably noticed the integer 200 towards the end of our request line. Every HTTP request has an associated status code. The 200 status code literally translates to, “OK. The request has succeeded.” Status codes, which live in the header of an HTTP response, are helpful for debugging issues that may come up during development, especially issues pertaining to server connections and data persistence.

For a complete list of all of the existing status codes, check out W3’s guide. You will probably be more apt to looking them up while debugging your web application.

In Summary

In order to optimize the user experience, it’s important to understand how HTML, Ruby code, and web protocols work together to retrieve and transmit data. Next time, we’ll discuss SQL and persisting data from a params hash in a PostgreSQL database.

Challenge

Pry is a Rubygem that is incredibly useful for debugging. Create a Sinatra application with a form containing 4 fields. Figure out how to use pry to access the params hash upon submitting the form.

Pry Github Repository

Build an App Part 5: Logic and Flow Control