‘Iacta alea est’
After reading my post on HTTPoison a friend pointed out that the Finch library exhibited many of the same characteristics relating to operations as data.
Finch is a relatively recent, performance focused HTTP client written in Elixir. It can be used as an alternative to HTTPoison.
It has also opted to use an intermediate data structure for encoding the request in an almost identical fashion to HTTPoison:
# HTTPoison
%Finch.Request{
body: term(), # body
headers: term(), # headers
host: term(), # url
method: term(), # method
path: term(), # url
port: term(), # url
query: term(), # params
scheme: term() # url
}
It does two things slightly differently. Firstly, instead of a generic URL, it breaks the URL down into its constituent parts: scheme, host, port and path. Secondly, it removes the options keyword list from the request struct, opting to keep the options distinct from the request itself.
(Separating out the options makes sense to me, as they often govern the behaviour of the client when making the request rather than relating specifically to the request itself. I guess you could see this as another essential-accidental split.)
Again, the %Finch.Request{}
struct can be created manually or via a helper function (Finch.build/4
), similar to HTTPoison’s convenience functions.
And importantly, the building of a request struct is handled as a separate and distinct step to actually executing the request. The HTTP operation is first modeled or encoded as data. Then the request is made.
Finch.build(:get, "https://hex.pm") # 1. Build request struct
|> Finch.request(MyFinch) # 2. Make a one-off request
One of the interesting things about this is that if you want to stream the request rather than doing it all in one go, you could use the same request struct, but just pass it to a different function.
Finch.build(:get, "https://hex.pm") # 1. Build request struct (identical)
|> Finch.stream(MyFinch, acc, fun) # 2. Open a persistent, streaming connection
Another benefit of having these operations as data is that the the request struct abstraction can function as a primitive adapter. If, for example, you wanted to switch your HTTP client from HTTPoison to Finch then there is a built in seam requiring only a few changes rather than having to rip out a large part of your code and deal with the resulting trauma.
Thursday 21st January 2021.