---
title: 'Back to Basics: HTTP Requests in Rails Apps'
teaser: An in-depth look at HTTP requests and how Ajax works in Rails.
tags: web,back to basics,http,rails
author: Britt Ballard
published_on: 2014-02-05
---

The [Hypertext Transfer Protocol](https://datatracker.ietf.org/doc/html/rfc9110) specifies
how a client machine requests information or actions from servers. This protocol
specifies how two machines share information, which is called a request. These
requests are composed of several parts which I'll outline below.

The first line of an HTTP request is called the
[Request-Line](https://datatracker.ietf.org/doc/html/rfc9112#name-request-line).
It contains:

* [URI](https://datatracker.ietf.org/doc/html/rfc9110#name-http-related-uri-schemes)
* [Headers](https://datatracker.ietf.org/doc/html/rfc9110#name-header-fields)
* [Body](https://datatracker.ietf.org/doc/html/rfc9112#name-message-body)
* [Method](https://datatracker.ietf.org/doc/html/rfc9110#name-methods)

Let's take a closer look at these four elements.

## URI

A URI or Uniform Resource Identifier is how objects are identified. Clients use
URIs to tell the server what object to act on for a given request. In more
general terms a URI is nothing more than a web address.

## Request Header Fields

A client can communicate additional information to the server via a request's
headers. In addition to just communicating information about the client, ie.
what type of browser the request originated from, these values can modify how
the server responds to the request.  For example, the Content-Type header value
is used by the Rails framework to decode a request’s message body.

## Message Body

The message body is used to send information from the client to the server about
the entity the client wants to modify or create. The message can be communicated
using several different encoding mechanisms, some of which I'll discuss below.
It is important to note that not all of the requests I discuss below are allowed
to have message bodies.

## Method

The method, sometimes called "verb" or "action", tells the server what the
client wants it to do. There are many different methods available, but we're
going to limit this blog to the four that are most relevant to Rails developers.

* __GET__ - how a client machine tells a server that it wants information about
  the item identified by the URI. Because GET requests are all about asking for
  information, they are not permitted to have request bodies. You still have the
  URI query string available to you if you need to send data from the client to
  the server on a GET request.
* __POST__ - how a client tells a server to add an entity as a child of the
  object identified by the URI. The entity that the client expects the server to
  add is transmitted in the request body.
* __PATCH__ - how a client tells a server it wants to modify an object
  identified by the URI the request is sent to.
* __DELETE__ - as you might guess, how a client tells a server to remove an
  object identified by the URI the request is sent to.

## Let's make some requests

## cURL

[cURL](http://curl.haxx.se/) is a utility that makes it possible to send
requests from the command line. We'll use cURL to make some requests to a test
Rails app which responds with strings.

Routes:

```ruby
BackToBasics::Application.routes.draw do
  match '/curl_example' => 'request_example#curl_get_example', via: :get
  match '/curl_example' => 'request_example#curl_post_example', via: :post
end
```

Controller:

```ruby
class RequestExampleController < ActionController::Base
  def curl_get_example
    render text: 'Thanks for sending a GET request with cURL!'
  end

  def curl_post_example
    render text: "Thanks for sending a POST request with cURL! Payload: #{request.body.read}"
  end
end
```

First we'll make a GET request. We tell cURL to do a GET request (which is
actually the default) with the "X" option.

    % curl -X GET http://localhost:3000/curl_example
    Thanks for sending a GET request with cURL!

Rails server log:

    Started GET "/curl_example" for 127.0.0.1 at 2013-06-21 14:38:22 -0700
    Processing by RequestExampleController#curl_get_example as */*
      Rendered text template (0.0ms)
    Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.0ms)

As you can see, our Rails app receives the GET request we sent from the terminal
and then responds with the string we provided in the controller. The app uses
the request's URI and Method to figure out which controller and action to call.

Next we'll make a POST request with a data payload. Again, we use "X" to specify
the method. We also use "d" to specify the data to send in the payload.

    % curl -X POST -d "backToBasics=for the win" http://localhost:3000/curl_example
    Thanks for sending a POST request with cURL! Payload: backToBasics=for the win

Rails server log:

    Started POST "/curl_example" for 127.0.0.1 at 2013-06-21 14:47:37 -0700
    Processing by RequestExampleController#curl_post_example as */*
      Parameters: {"backToBasics"=>"for the win"}
      Rendered text template (0.0ms)
    Completed 200 OK in 0ms (Views: 0.3ms | ActiveRecord: 0.0ms)

The Rails app receives our request. This time, in addition to the <abbr
title="Uniform Resource Locator">URL</abbr>, it logs the data payload as hash of
parameters.

## Web Browsers

We're all familiar with surfing the web. I'm sure it comes as no surprise that
this experience is made up of a series of requests and responses. Let's take a
look at what's happening when we type a <abbr title="Uniform Resource
Locator">URL</abbr> into our browser's address bar and hit enter. We'll also
look at what happens when we enter data into a form and submit it.

Below is the demo controller we'll be sending requests to for this example.

Routes:

```ruby
BackToBasics::Application.routes.draw do
  root to: 'request_example#index'
  match '/request' => 'request_example#create', via: :post
  match '/request' => 'request_example#create', via: :get
end
```

Controller:

```ruby
class RequestExampleController < ActionController::Base
  def index
  end

  def create
    render json: params
  end
end
```

## Address Bar

Typing a <abbr title="Uniform Resource Locator">URL</abbr> into the address bar
of a web browser sends a GET request to the <abbr title="Uniform Resource
Locator">URL</abbr> specified. Sending a GET request in this fashion looks
identical to sending a GET request through the terminal with cURL.

If we set the root path of our demo app to the index action of our dummy
controller and navigate to `localhost:3000` the browser will send the GET
request.  If we take a look at the Rails console we'll notice the output is
almost identical to what we saw with cURL.

    Started GET "/" for 127.0.0.1 at 2014-01-31 15:09:53 -0800
    Processing by RequestExampleController#index as HTML
      Rendered request_example/index.html.erb (1.2ms)
    Completed 200 OK in 26ms (Views: 25.5ms | ActiveRecord: 0.0ms)

## Forms

A form is made up of several key parts (we'll look at several simple examples a
bit later). In the opening form tag we have the action attribute. This attribute
tells the form where to send the request. In addition to the action attribute we
have the method attribute. This tells the form what type of request to send to
the URI specified in the action attribute.

Request bodies are defined by a form's markup. In the form tag there is an
attribute called `enctype`, this attribute tells the browser how to encode the
form data.  There are several different values this attribute can have. The
default is `application/x-www-form-urlencoded`, which tells the browser to
encode all of the values. If a form includes a file upload an enctype of
`multipart/form-data` should be used. This encodes none of the values. Finally,
you can set the enctype to `text/plain` this converts spaces, but leaves all
other characters unencoded.  Inside the inside the form element we have input
elements. These elements will render as assorted input types in our website.
Each input element in the form should have a name attribute. This name attribute
tells the browser what to name the data specified in that input in the message
body. The type attribute tells the browser in what format to communicate the
data in the message body.

## GET

Let's take a look at how we could send a GET request with a form.

The simple form below is made up of one text field and that text field will have
the name `my_data`. The final input is the submit which tells the form we
actually want to send the request to the URI specified in the action attribute.

Let’s send a request. Assume a user has navigated to a page and the following
form has been rendered. In the text box named `my_data` a user has entered the
string “back to basics" and clicked the submit button.

```html
<form action="/request" method="GET">
  <input type="text" name="my_data">
  <input type=submit>
</form>
```

Rails server log:

```log
Started GET "/request?my_data=back+to+basics" for 127.0.0.1 at 2013-06-21 14:44:25 -0700
Processing by RequestExampleController#create as HTML
  Parameters: {"my_data"=>"back to basics"}
Completed 200 OK in 0ms (Views: 0.2ms | ActiveRecord: 0.0ms)
```

There are several interesting things about this request. You’ll notice that our
Rails app received the request, but the <abbr title="Uniform Resource
Locator">URL</abbr> includes a query parameter called `my_data`. This is the
result of our decision to use the GET method for this request. Because GET
requests have no payloads the data we collected with our form is added to the
URI. In addition, you’ll notice that our text input ends up with a name of
`my_data` in the payload, or the value we specified with the name attribute of
our text input.

We can open the Network tab in our developer tools (Firefox or Chrome) and see
that the data was added to the query string. This is because the action on the
form is GET.

![''](https://images.thoughtbot.com/requests/console-query-string.png)

## POST

The POST action works almost identically to the GET request with the exception
of the payload. Let's submit our form with the same text input and see what
happens this time.

```html
<form action="/request" method="POST">
  <input type="text" name="my_data">
  <input type=submit>
</form>
```

Rails server log:

    Started POST "/request" for 127.0.0.1 at 2013-06-21 14:49:11 -0700
    Processing by RequestExampleController#create as HTML
      Parameters: {"my_data"=>"back to basics"}
    Completed 200 OK in 0ms (Views: 0.2ms | ActiveRecord: 0.0ms)

The first thing to notice is that our <abbr title="Uniform Resource
Locator">URL</abbr> no longer contains the query parameter. It's also important
to note that our parameters hash looks identical.  Let's take a look at our
network tab and see if we can learn anything about the request.

![''](https://images.thoughtbot.com/requests/console-form-data.png)

Examining the request we see that our payload includes what's called form data.
Our input elements are converted to a request payload and sent to the server.
Again the name of our text input element is used as the name associated with
the user's text input.

## XMLHttpRequest

It’s also possible to send requests via JavaScript. There is nothing special
about these request from a mechanical perspective. They’re just requests like
the ones we’ve sent above.

Because these requests are sent with JavaScript, in order to see what happens
we'll have to provide a function that deals with the response. We'll use a
simple function that will write whatever response we get to the JavaScript
console.

```javascript
function callback () {
  console.log(this.responseText);
};
```

## Ajax Form Data

When sending our [Ajax](http://en.wikipedia.org/wiki/Ajax_(programming))
requests we have several different options as to how we want to send the data.
As we saw above there is a concept of form data. We can easily create a form
data payload using only JavaScript.

```javascript
var request = new XMLHttpRequest();
request.onload = callback;
request.open("post", "http://localhost:3000/request");
var formData = new FormData();
formData.append('my_data', 'back to basics')
request.send(formData);
```

Rails server log:

    Started POST "/request" for 127.0.0.1 at 2013-06-21 14:53:03 -0700
    Processing by RequestExampleController#create as */*
      Parameters: {"my_data"=>"back to basics"}
    Completed 200 OK in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms)

As is obvious from our log this request was handled no different than a “normal"
form submission by our Rails application. There is no special magic about an
Ajax request as far as our server is concerned.

## Ajax JSON Data

Another option we have is to use JSON. In order to do this we need to slightly
modify our request headers and tell our server that it needs to do something
slightly different to parse our payload.

```ruby
var request = new XMLHttpRequest();
request.onload = callback;
request.open("post", "http://localhost:3000/request");
request.setRequestHeader("Content-Type", "application/json");
request.send('{"my_data":"back to basics"}');
```

Rails server log:

```log
Started POST "/request" for 127.0.0.1 at 2013-06-21 14:55:55 -0700
Processing by RequestExampleController#create as */*
  Parameters: {"my_data"=>"back to basics", "request_example"=>{"my_data"=>"back to basics"}}
Completed 200 OK in 0ms (Views: 0.2ms | ActiveRecord: 0.0ms)
```

As you can see by simply modifying our request headers our Rails app is able to
appropriately parse our payload and we end up with our `my_data` value available
to our application.

Requests are one of the foundational elements of the internet as we know it.
Understanding the individual elements of a request can make it much easier to
debug issues with our Rails apps.
