Because Lisp Flavored Erlang is 100% compatible with Erlang Core, it has access to all the Erlang libraries, OTP, and many third-party modules, etc. Naturally, this includes the Erlang HTTP client, httpc. Today we're going to be taking a look at how to use httpc from LFE. Do note, however that this post is only going to provide a taste, just enough to give you a sense of the flavor, as it were.
If you would like more details, be sure to not only give the official docs a thorough reading, but to take a look at the HTTP Client section of the inets Reference Manual.
Note that for the returned values below, I elide large data structures. If you run them in the LFE REPL yourself, you can view them in all of the line-consuming glory.
Synchronous GET
Let's get started with a simple example. The first thing we need to do is start the inets application. With that done, we'll then be able to make client requests:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> (: inets start) | |
> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> (set | |
(tuple 'ok result) | |
(: httpc request '"http://lfe.github.io")) | |
#(ok | |
#(#("HTTP... | |
> |
- HTTP version
- status code
- reason phrase
- headers
- body
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> (set | |
(tuple 'ok | |
(tuple (tuple http-version status-code reason-phrase) | |
headers body)) | |
(: httpc request '"http://lfe.github.io")) | |
... | |
> |
- the return value of the function we're going to call is going to be a tuple composed of an atom ('ok) and another tuple
- the nested tuple is going to be composed of a tuple, some headers, and a body
- the next nested tuple is going to be composed of the HTTP version, status code, and status code phrase
Once the request returns, we can check out the variables we set in the pattern:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> http-version | |
"HTTP/1.1" | |
> status-code | |
200 | |
> reason-phrase | |
"OK" | |
> headers | |
(#("cache-control" "max-age=600") | |
#("connection" "keep-alive") | |
#("date" "Sun, 14 Apr 2013 03:43:17 GMT") | |
#("accept-ranges" "bytes") | |
#("server" "GitHub.com") | |
#("vary" "Accept-Encoding") | |
#("content-length" "13430") | |
#("content-type" "text/html") | |
#("expires" "Sun, 14 Apr 2013 03:53:17 GMT") | |
#("last-modified" "Sat, 13 Apr 2013 18:28:49 GMT")) | |
> (: string len body) | |
13430 | |
> |
That's great if everything goes as expected and we get a response from the server. What happens if we don't?
Well, errors don't have the same nested data structure that the non-error results have, so we're going to have to make some changes to our pattern if we want to extract parts of the error reason. Pattern matching for just the 'error atom and the error reason, we can get a sense of what that data structure looks like:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> (set | |
(tuple 'error reason) | |
(: httpc request '"http://localhost:8000")) | |
#(error | |
... | |
> |
Looking at just the data stored in the reason variable, we see:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> reason | |
#(failed_connect | |
(#(to_address #("localhost" 8000)) #(inet (inet) econnrefused))) | |
> |
- a tuple of connect_failed and additional data
- a tuple of send_failed and additional data
- or just unspecified additional data
Async GET
Now that we've taken a quick look at the synchronous example, let's make a foray into async. We'll still be using httpc's request function, but we'll need to use one of the longer forms were extra options need to be passed, since that's how you tell the request function to perform the request asynchronously and not synchronously.
For clarity of introducing the additional options, we're going to define some variables first:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> (set method 'get) | |
> (set url '"http://lfe.github.io") | |
> (set headers ()) | |
> (set request-data (tuple url headers)) | |
> (set http-options ()) | |
> (set request-options (list (tuple 'sync 'false))) | |
> |
With the variables defined, let's make our async call:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> (set (tuple 'ok request-id-sender) | |
(: httpc request method request-data http-options request-options)) | |
#(ok #Ref<0.0.0.230>) | |
> request-id-sender | |
#Ref<0.0.0.230> | |
> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> (receive ((tuple 'http (tuple request-id-receiver result)) | |
(: io format '"data: ~p~n" (list result)))) | |
data: {{"HTTP/1.1",200,"OK"}, | |
... | |
> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> (set (tuple 'ok request-id-sender) | |
(: httpc request method request-data http-options request-options)) | |
#(ok #Ref<0.0.0.242>) | |
> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> (receive ((tuple 'http | |
(tuple request-id-receiver | |
(tuple (tuple http-version status-code reason-phrase) | |
headers body))) | |
(: io format '"data: ~p ~p ~p ~n" | |
(list http-version status-code reason-phrase)))) | |
data: "HTTP/1.1" 200 "OK" | |
ok | |
> |
Well, that about sums it up for an intro to the HTTP client in LFE! But one last thing, for the sake of completeness. Once we're done, we can shut down inets:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> (: inets stop) | |
ok | |
> |
No comments:
Post a Comment