An overview and a demo of the Farwest project
Loïc Hoguin, Nine Nines
HATEOAS
Standards based (whenever possible)
Built on top of cowboy_rest
One library per language/platform
Build on top of existing HTTP clients
Don't write a separate client per API
git clone https://github.com/ninenines/farwest_demo
cd farwest_demo
make run
curl -i http://localhost:8080
describe() → #{
uri ⇒ "/",
media_types ⇒ #{
html ⇒ ["text/html"],
bed ⇒ ["application/x-bed"]
},
operations ⇒ #{
get ⇒ #{output ⇒ [html, bed]}
}
}.
links(Req) →
{ok, [
{child, fwd_processes_r},
{child, fwd_tables_r}
], Req}.
$ curl -I http://localhost:8080
HTTP/1.1 200 OK
content-length: 2398
content-type: text/html
date: Mon, 27 Jan 2020 11:56:23 GMT
link: </processes>; rel="child";
variants-06="accept=(\"text/html\" \"application/x-bed\")",
</tables>; rel="child"; variants-06="accept=(\"text/html\")"
server: Cowboy
variant-key-06: ("text/html")
variants-06: accept=("text/html" "application/x-bed")
vary: accept
get(Req) →
Info = observer_backend:sys_info(),
Data = #{
«"System Version"» ⇒ g(otp_release, Info),
...
},
{ok, Data, Req}.
to_representation(Req, html, Data) →
{ok, farwest_html:from_term(Req, Data), Req};
to_representation(Req, bed, Data) →
{ok, farwest_bed:from_term(Req, Data), Req}.
$ curl -I http://localhost:8080/tables
HTTP/1.1 200 OK
content-length: 7052
content-type: text/html
date: Mon, 27 Jan 2020 11:56:10 GMT
farwest-link-templates: </tables/{name}>; rel="child";
variants-06="accept=(\"text/html\")"
link: </>; rel="parent"; variants-06="accept=
(\"text/html\" \"application/x-bed\")"
server: Cowboy
{'$fw_link', child,
farwest:link_to(fwd_table_r, #{«"name"» ⇒ TableName}),
TableName}
describe() → #{
uri ⇒ "/tables/{name}/{key}",
media_types ⇒ #{
html ⇒ ["text/html"],
term ⇒ ["text/plain+erlang-term"]
},
operations ⇒ #{
get ⇒ #{output ⇒ [html]},
put ⇒ #{input ⇒ [term]},
delete ⇒ #{}
}
}.
put(Req0=#{bindings := #{name := Name0}}) →
Name = binary_to_atom(Name0, utf8),
{ok, Body, Req} = cowboy_req:read_body(Req0),
{ok, Tuple} = parse_string(
unicode:characters_to_list(Body) ++ "."),
ets:delete_object(Name, Tuple),
ets:insert(Name, Tuple),
{ok, Req}.
delete(Req=#{bindings := #{name := Name0, key := Key0}}) →
Name = binary_to_atom(Name0, utf8),
{ok, Key} = parse_string(
unicode:characters_to_list(Key0) ++ "."),
ets:delete(Name, Key),
{ok, Req}.
Automatic sitemap?
External resources?
Link relation resources?
Better discovery of operations
Cache metadata (etag, cache-control...)
Template-based HTML generation
Replace/insert your own templates
Automatic JSON/JSON-LD/... generation
Type "objects" first, then their values
Schemas (schema.org or other)
Better forms using schemas
Read data and expand URI Templates
More functions
Client-side cache for Gun HTTP client
Non-Erlang client libraries
github.com/ninenines/farwest_demo
Looking for early adopters!