flm01/server/api/webmachine/www/example_resources.html

251 lines
7.1 KiB
HTML
Raw Permalink Normal View History

2010-02-25 17:45:11 +00:00
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="author" content="Basho Technologies" />
<meta name="description" content="Webmachine examples" />
<meta name="keywords" content="webmachine http rest web" />
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<link rel="stylesheet" href="css/style-1c.css" type="text/css" />
<title>Webmachine examples</title>
</head>
<body>
<div id="content">
<h1><span class="hr"></span><a href="/">webmachine</a></h1>
<ul id="top">
<li><a href="/">Home</a></li>
<li><a href="http://bitbucket.org/justin/webmachine/">Source Code</a></li>
<li><a href="contact.html">Contact</a></li>
</ul>
<div id="left">
<h3>Webmachine examples</h3>
<p>
The simplest possible example is the one produced via the
<a href="quickstart.html">quickstart</a>.
</p>
<p>
For an example of a read/write filesystem server showing several
interesting features and supporting GET, PUT, DELETE, and POST, see
<a href="http://bitbucket.org/justin/webmachine/src/tip/demo/src/demo_fs_resource.erl">demo_fs_resource</a>.
</p>
<p>
For a very simple resource demonstrating content negotiation, basic
auth, and some caching headers, see
<a href="http://bitbucket.org/justin/webmachine/src/tip/demo/src/webmachine_demo_resource.erl">webmachine_demo_resource</a>.
</p>
<p>
Some example code based on webmachine_demo_resource follows.
</p>
<p>
The simplest working resource could export only one function in
addition to init/1:
</p>
<pre>
-module(webmachine_demo_resource).
-export([init/1, to_html/2]).
-include_lib("webmachine/include/webmachine.hrl").
init([]) -> {ok, undefined}.
to_html(ReqData, Context) -> {"<html><body>Hello, new world</body></html>", ReqData, Context}.
</pre>
<p>
That's really it -- a working webmachine resource. That resource will
respond to all valid GET requests with the exact same response.
</p>
<p>
Many interesting bits of HTTP are handled automatically by
Webmachine. For instance, if a client sends a request to that trivial
resource with an Accept header that does not allow for a text/html
response, they will receive a 406 Not Acceptable.
</p>
<p>
Suppose I wanted to serve a plaintext client as well. I could note
that I provide more than just HTML:
</p>
<pre>
content_types_provided(ReqData, Context) ->
{[{"text/html", to_html},{"text/plain",to_text}], ReqData, Context}.
</pre>
<p>
I already have my HTML representation produced, so I add a text one:
(and while I'm at it, I'll show that it's trivial to produce dynamic content as well)
</p>
<pre>
to_text(ReqData, Context) ->
Path = wrq:disp_path(ReqData),
Body = io_lib:format("Hello ~s from webmachine.~n", [Path]),
{Body, ReqData, Context}.
</pre>
<p>
Now that this resource provides multiple media types, it automatically performs conneg:
</p>
<pre>
$ telnet localhost 8000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET /demo/a/resource/path HTTP/1.1
Accept: text/plain
HTTP/1.1 200 OK
Vary: Accept
Server: MochiWeb/1.1 WebMachine/0.97
Date: Sun, 15 Mar 2009 02:54:02 GMT
Content-Type: text/plain
Content-Length: 39
Hello a/resource/path from webmachine.
</pre>
<p>
What about authorization? Webmachine resources default to assuming the
client is authorized, but that can easily be overridden. Here's an
overly simplistic but illustrative example:
</p>
<pre>
is_authorized(ReqData, Context) ->
case wrq:disp_path(ReqData) of
"authdemo" ->
case wrq:get_req_header("authorization", ReqData) of
"Basic "++Base64 ->
Str = base64:mime_decode_to_string(Base64),
case string:tokens(Str, ":") of
["authdemo", "demo1"] ->
{true, ReqData, Context};
_ ->
{"Basic realm=webmachine", ReqData, Context}
end;
_ ->
{"Basic realm=webmachine", ReqData, Context}
end;
_ -> {true, ReqData, Context}
end.
</pre>
<p>
With that function in the resource, all paths except
<code>/authdemo</code> from this resource's root are authorized.
For that one path,
the UA will be asked to do basic authorization with the user/pass of
authdemo/demo1. It should go without saying that this isn't quite the
same function that we use in our real apps, but it is nice and simple.
</p>
<p>
If you've generated the application from the
<a href="quickstart.html">quickstart</a>, make sure
you've added this line to your dispatch.conf file:
</p>
<pre>
{["demo", '*'], mywebdemo_resource, []}.
</pre>
<p>
Now you can point your browser at
<code>http://localhost:8000/demo/authdemo</code> with the demo app running:
</p>
<pre>
$ curl -v http://localhost:8000/demo/authdemo
&gt; GET /demo/authdemo HTTP/1.1
&gt; Host: localhost:8000
&gt; Accept: */*
&gt;
&lt; HTTP/1.1 401 Unauthorized
&lt; WWW-Authenticate: Basic realm=webmachine
&lt; Server: MochiWeb/1.1 WebMachine/0.97
&lt; Date: Sun, 15 Mar 2009 02:57:43 GMT
&lt; Content-Length: 0
&lt;
</pre>
<p></p>
<pre>
$ curl -v -u authdemo:demo1 http://localhost:8000/demo/authdemo
* Server auth using Basic with user 'authdemo'
&gt; GET /demo/authdemo HTTP/1.1
&gt; Authorization: Basic YXV0aGRlbW86ZGVtbzE=
&gt; Host: localhost:8000
&gt; Accept: */*
&gt;
&lt; HTTP/1.1 200 OK
&lt; Vary: Accept
&lt; Server: MochiWeb/1.1 WebMachine/0.97
&lt; Date: Sun, 15 Mar 2009 02:59:02 GMT
&lt; Content-Type: text/html
&lt; Content-Length: 59
&lt;
&lt;html&gt;&lt;body&gt;Hello authdemo from webmachine.
&lt;/body&gt;&lt;/html&gt;
</pre>
<p>
HTTP caching support is also quite easy, with functions allowing
resources to define (e.g.) <code>last_modified</code>,
<code>expires</code>, and <code>generate_etag.</code> For instance, since
representations of this resource vary only by URI Path, I could use an
extremely simple entity tag unfit for most real applications but
sufficient for this example:
</p>
<pre>
generate_etag(ReqData, Context) -> {wrq:raw_path(ReqData), ReqData, Context}.
</pre>
<p>Similarly, here's a trivial expires rule:</p>
<pre>
expires(ReqData, Context) -> {{{2021,1,1},{0,0,0}}, ReqData, Context}.
</pre>
<p>
And now the response from our earlier request is appropriately tagged:
</p>
<pre>
HTTP/1.1 200 OK
Vary: Accept
Server: MochiWeb/1.1 WebMachine/0.97
Expires: Fri, 01 Jan 2021 00:00:00 GMT
ETag: /demo/authdemo
Date: Sun, 15 Mar 2009 02:59:02 GMT
Content-Type: text/html
Content-Length: 59
&lt;html&gt;&lt;body&gt;Hello authdemo from webmachine.
&lt;/body&gt;&lt;/html&gt;
</pre>
<p>
For more details, read the source of the resources linked at the top
of this page.
</p>
</div>
<div id="footer">
</div>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-4979965-5");
pageTracker._trackPageview();
} catch(err) {}</script>
</body>
</html>