- 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 and run the server.
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
This syntax here is using a regular expression to check if the path matches
items
:
if req.path.match(/items/)
So if a user visits localhost:9292/items
, that will evaluate to a truthy
value; for other routes, like localhost:9292/cart
, it will evaluate to nil
.
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