Request and Response Example
To save you the trouble of typing it, here’s the request we used in the video.
Request
request = """
GET /wildthings HTTP/1.1
Host: example.com
User-Agent: ExampleBrowser/1.0
Accept: _/_
"""Expected Response
expected_response = """
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 20
Bears, Lions, Tigers
"""High-Level Transformations
Finally, here are the three high-level transformations we used as a starting point.
### 1. Parse the Request
def parse(request) do
# TODO: Parse the request string into a map:
conv = %{ method: "GET", path: "/wildthings", resp_body: "" }
end`
### 2. Route the Request
`def route(conv) do
# TODO: Create a new map that also has the response body:
conv = %{ method: "GET", path: "/wildthings", resp_body: "Bears, Lions, Tigers" }
end`
### 3. Format the Response
def format_response(conv) do
# TODO: Use values in the map to create an HTTP response string:
"""
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 20
Bears, Lions, Tigers
"""
endHigh-Level Transformations in Elixir
Notes
Pipelines As Outlines
At this point, we have an outline for our program expressed as a pipeline of functions:
request
|> parse
|> route
|> format_responseThe program doesn’t do anything interesting yet since the functions simply return hard-coded data. But we like to start this way as it helps us think through the program as a series of data transformations. And it just so happens it’s also a to-do list! We’ll implement each of the functions in subsequent modules.
Nested Function Calls
In the video, we started by sequencing the three transformation functions in a traditional style using intermediate variables:
def handle(request) do
conv = parse(request)
conv = route(conv)
format_response(conv)
endYou could condense this a bit and remove the temporary variables by nesting the function calls like so:
format_response(route(parse(request)))But this is difficult to read as the functions resolve from the inside out.
Using the Pipe Operator
The pipe operator (|>) lets us unwind these nested calls by chaining the functions together in a more readable style:
request
|> parse
|> route
|> format_responseIt transforms the request by piping the result of each function into the next function. Here’s a fun fact: At compile time, this code is transformed to the nested call version.
A Piping Analogy
If you’ve ever piped multiple commands together in the Unix operating system, then Elixir’s pipe operator will be familiar. If not, think of it like the game where one person whispers a story to another person, who whispers it to the next person, and so on until the last
Code So Far
The code for this section is in the parse directory found within the video-code directory of the code bundle
Why always me?