- Define the path in an HTTP request
- Define the
env
variable in an HTTP request - Use the
path
method to filter HTTP requests - Describe
GET
parameters and how they allow web applications to handle user queries
An HTTP Request that our browser sends to the server contains two main sections of information. One is headers and the other section is the resource or path requested (for example, /search
or /profile_name
). Let's break down the second section since there's a lot of information that can be stored in it!
The path that is requested is the resource that the client wants. Since your server can contain a lot of functionality, the path signifies which specific part of your server it wants. If we were creating a simple shopping cart application, for example, we can think of a few different paths that are required:
Path | Description |
---|---|
/items | List all items available |
/cart | List items in cart |
How would we implement this in our Rack app? The path lives in the HTTP request, and to get to it we have to inspect the env
part of our #call
function. In the env
variable is all of the information contained in the request. Thankfully, Rack has a great way of parsing all this information for us. It looks like this:
class Application
def call(env)
resp = Rack::Response.new
req = Rack::Request.new(env)
resp.finish
end
end
This Rack::Request instance now has a ton of useful methods. If we look through the documentation, it has a method called #path
. This will return the path that was requested.
Before we inspect the #path
, let's set up what we would do if someone wanted to see all of our items:
class Application
@@items = ["Apples","Carrots","Pears"]
def call(env)
resp = Rack::Response.new
req = Rack::Request.new(env)
@@items.each do |item|
resp.write "#{item}\n"
end
resp.finish
end
end
If you're on a local environment, you can take it a step further and customize the response based on which specific path you enter. For example, right now the code above will list all of your items no matter what path you put in. You can give it a try by using the code to create your Rack file. Type localhost:9292/items
, localhost:9292/cart
, localhost:9292/flatiron/is/awesome
. All of those URLs work since we're not filtering for path. No matter what the request is, we end up sending the same response. Let's filter so that this only works for the /items
path using the #path
method of our Rack::Request
object:
class Application
@@items = ["Apples","Carrots","Pears"]
def call(env)
resp = Rack::Response.new
req = Rack::Request.new(env)
if req.path.match(/items/)
@@items.each do |item|
resp.write "#{item}\n"
end
else
resp.write "Path Not Found"
end
resp.finish
end
end
Great! With this we can now do different things depending on the path.
What if users wanted to check and see if we have Apples
available in our list of items? How do other websites handle getting user queries? If we go to GitHub and type in "apples" in the search query, we get a URL that looks like this: https://github.com/search?q=apples
. We have a domain of github.com
, path of search
, and then a ?
character. After that character comes q=apples
. There is our search!
The section after the ?
is called the GET
parameters. If you notice in the above example, GET
params come in key/value pairs. The key in GitHub's case would be q
and the value is apples
. The matching Ruby data structure that is also a key/value store would be a Hash
! Thankfully, Rack provides the mechanism to parse the GET
params and return them to us in a standard Hash
. If we wanted to implement a /search
route that accepted a GET
param with the key q
it would look something like this:
class Application
@@items = ["Apples","Carrots","Pears"]
def call(env)
resp = Rack::Response.new
req = Rack::Request.new(env)
if req.path.match(/items/)
@@items.each do |item|
resp.write "#{item}\n"
end
elsif req.path.match(/search/)
search_term = req.params["q"]
if @@items.include?(search_term)
resp.write "#{search_term} is one of our items"
else
resp.write "Couldn't find #{search_term}"
end
else
resp.write "Path Not Found"
end
resp.finish
end
end