Webmachine a practical executable model for HTTP Steve Vinoski - - PowerPoint PPT Presentation

webmachine
SMART_READER_LITE
LIVE PREVIEW

Webmachine a practical executable model for HTTP Steve Vinoski - - PowerPoint PPT Presentation

Webmachine a practical executable model for HTTP Steve Vinoski Architect, Basho Technologies QCon SF 2011 16 Nov 2011 @stevevinoski http://steve.vinoski.net/ vinoski@ieee.org 1 Webmachine a practical executable model for HTTP a toolkit


slide-1
SLIDE 1

Webmachine

a practical executable model for HTTP

Steve Vinoski

Architect, Basho Technologies

QCon SF 2011 16 Nov 2011 @stevevinoski http://steve.vinoski.net/

vinoski@ieee.org

1

slide-2
SLIDE 2

Webmachine

a practical executable model for HTTP

HTTP-based systems a toolkit for

2

slide-3
SLIDE 3

Webmachine

HTTP-based systems a toolkit for

a practical executable model for HTTP

3

slide-4
SLIDE 4

Webmachine

HTTP-based systems well-behaved easily creating a toolkit for

a practical executable model for HTTP

3

slide-5
SLIDE 5

Webmachine

HTTP-based systems well-behaved easily creating? a toolkit for

a practical executable model for HTTP

4

slide-6
SLIDE 6

Webmachine

HTTP-based systems well-behaved? easily creating a toolkit for

a practical executable model for HTTP

5

slide-7
SLIDE 7

HTTP is complicated.

(see http://webmachine.basho.com/)

6

slide-8
SLIDE 8

Webmachine makes HTTP easier.

7

slide-9
SLIDE 9
  • module(twohundred_resource).
  • export([init/1, to_html/2]).
  • include_lib("webmachine/include/webmachine.hrl").

init([]) -> {ok, undefined}. to_html(ReqData, State) -> {"Hello, Webmachine world", ReqData, State}.

(that’s it!)

8

slide-10
SLIDE 10

Want to get more interesting?

Just add generate_etag or last_modified...

9

slide-11
SLIDE 11

...and now you have conditional requests.

generate_etag(RD, State) -> {mochihex:to_hex(erlang:phash2(State)), RD, State}. last_modified(RD, State) -> {filelib:last_modified(State#s.fpath), RD, State}.

Just add generate_etag or last_modified...

10

slide-12
SLIDE 12

A resource family is just a set of functions.

to_html(ReqData,State) -> {Body,ReqData,State}. generate_etag(ReqData,State) -> {ETag,ReqData,State}. last_modified(ReqData,State) -> {Time,ReqData,State}. resource_exists(ReqData,State) -> {bool,ReqData,State}. is_authorized(ReqData,State) -> {bool,ReqData,State}. ... f(ReqData,State) -> {RetV,ReqData,State}.

11

slide-13
SLIDE 13

A resource family is just a set of functions.

f(ReqData,State) -> {RetV,ReqData,State}.

Resource functions are referentially transparent and have a uniform interface.

function behavior request/ response data process state + +

12

slide-14
SLIDE 14

A resource family is just a set of functions.

f(ReqData,State) -> {RetV,ReqData,State}.

Resource functions are referentially transparent and have a uniform interface.

function behavior request/ response data process state + +

12

slide-15
SLIDE 15

A resource family is just a set of functions.

f(ReqData,State) -> {RetV,ReqData,State}.

Resource functions are referentially transparent and have a uniform interface.

function behavior request/ response data process state + +

12

slide-16
SLIDE 16

A resource family is just a set of functions.

f(ReqData,State) -> {RetV,ReqData,State}.

Resource functions are referentially transparent and have a uniform interface.

function behavior request/ response data process state + +

12

slide-17
SLIDE 17

A resource family is just a set of functions.

f(ReqData,State) -> {RetV,ReqData,State}.

Resource functions are referentially transparent and have a uniform interface.

function behavior request/ response data process state + +

12

slide-18
SLIDE 18

Manipulating Request/Response Data

f(ReqData,State) -> {RetV,ReqData,State}.

The wrq module accesses and (nondestructively) modifies ReqData.

wrq:get_req_header(HdrName,ReqData) -> 'undefined' | HdrVal wrq:get_qs_value(Key,Default,ReqData) -> Value wrq:set_resp_header(HdrName,HdrVal,ReqData) -> NewReqData

13

slide-19
SLIDE 19

URL Dispatching = Pattern Matching

{["a"],some_resource,[]} pattern resource family args

14

slide-20
SLIDE 20

URL Dispatching = Pattern Matching

{["a"],some_resource,[]} http://myhost/a match! any other URL no match If no patterns match, then 404 Not Found. /a

15

slide-21
SLIDE 21

URL Dispatching = Pattern Matching

{["a"],some_resource,[]} /a wrq:disp_path wrq:path wrq:path_info wrq:path_tokens [] "/a" [] []

16

slide-22
SLIDE 22

URL Dispatching = Pattern Matching

{["a"],some_resource,[]} /a wrq:disp_path wrq:path wrq:path_info wrq:path_tokens [] "/a" [] [] {["a" ,some_resource,[]}

16

slide-23
SLIDE 23

URL Dispatching = Pattern Matching

/a wrq:disp_path wrq:path wrq:path_info wrq:path_tokens [] "/a" [] [] ,some_resource,[]} {["a"

17

slide-24
SLIDE 24

URL Dispatching = Pattern Matching

{["a", '*'],some_resource,[]} /a wrq:disp_path wrq:path wrq:path_info wrq:path_tokens [] "/a" [] [] (binds the remaining path) ,some_resource,[]} {["a"

17

slide-25
SLIDE 25

URL Dispatching = Pattern Matching

{["a", '*'],some_resource,[]} /a wrq:disp_path wrq:path wrq:path_info wrq:path_tokens “b/c” "/a/b/c" [] [“b”, “c”] /a/b/c {["a", ],some_resource,[]}

18

slide-26
SLIDE 26

URL Dispatching = Pattern Matching

{["a", foo],some_resource,[]} /a wrq:disp_path wrq:path wrq:path_info wrq:path_tokens “b/c” "/a/b/c" [] [“b”, “c”] /a/b/c (name-binds a path segment) 404 {["a", ],some_resource,[]}

19

slide-27
SLIDE 27

URL Dispatching = Pattern Matching

{["a", foo],some_resource,[]} /a wrq:disp_path wrq:path wrq:path_info wrq:path_tokens [] "/a/b" [{foo, “b”}] [] /a/b {["a", foo some_resource,[]}

20

slide-28
SLIDE 28

URL Dispatching = Pattern Matching

wrq:disp_path wrq:path wrq:path_info wrq:path_tokens [] "/a/b" [{foo, “b”}] [] /a/b {["a", foo some_resource,[]}

21

slide-29
SLIDE 29

URL Dispatching = Pattern Matching

{["a", foo, '*'],some_resource,[]} wrq:disp_path wrq:path wrq:path_info wrq:path_tokens [] "/a/b" [{foo, “b”}] [] /a/b {["a", foo some_resource,[]}

21

slide-30
SLIDE 30

URL Dispatching = Pattern Matching

{["a", foo, '*'],some_resource,[]} wrq:disp_path wrq:path wrq:path_info wrq:path_tokens “c/d” "/a/b/c/d" [{foo, “b”}] [“c”,”d”] /a/b/c/d /a/b

22

slide-31
SLIDE 31

URL Dispatching = Pattern Matching

{["a", foo, '*'],some_resource,[]} wrq:disp_path wrq:path wrq:path_info wrq:path_tokens “c/d” "/a/b/c/d" [{foo, “b”}] [“c”,”d”] /a/b/c/d

22

slide-32
SLIDE 32

URL Dispatching = Pattern Matching

{["a", foo, '*'],some_resource,[]} wrq:disp_path wrq:path wrq:path_info wrq:path_tokens “c/d” "/a/b/c/d" [{foo, “b”}] [“c”,”d”] /a/b/c/d

23

slide-33
SLIDE 33

URL Dispatching = Pattern Matching

{["a", foo, '*'],some_resource,[]} wrq:disp_path wrq:path wrq:path_info wrq:path_tokens “c/d” "/a/b/c/d" [{foo, “b”}] [“c”,”d”] /a/b/c/d query strings are easy too /a/b/c/d?fee=ah&fie=ha wrq:get_qs_value("fie","",ReqData) -> "ha"

23

slide-34
SLIDE 34

An Example: Wriaki

  • A wiki built on Webmachine and Riak
  • Written by Bryan Fink of Basho as a sample

application for Riak

  • Wriaki is simple and elegant
  • https://github.com/basho/wriaki

24

slide-35
SLIDE 35

Wriaki Web Resources

  • User resources represent wiki users
  • Articles represent wiki pages
  • Archives represent individual page versions
  • History represents a page’s history
  • Sessions track user logins

25

slide-36
SLIDE 36

Wriaki Dispatch Map

{["wiki"], redirect_resource, "/wiki/Welcome"}. {["wiki",'*'], wiki_resource, []}. {[], redirect_resource, "/wiki/Welcome"}. {["user"], login_form_resource, []}. {["user",name], user_resource, []}. {["user",name,session], session_resource, []}. {["static",'*'], static_resource, "www"}.

26

slide-37
SLIDE 37

Wriaki Dispatch Map

{["wiki"], redirect_resource, "/wiki/Welcome"}.

  • The pathspec declares the path we want

to match

27

slide-38
SLIDE 38

Wriaki Dispatch Map

{["wiki"], redirect_resource, "/wiki/..."}.

  • The resource module declares which Erlang

module implements the resource

28

slide-39
SLIDE 39

Wriaki Dispatch Map

{[...], redirect_resource, "/wiki/Welcome"}.

  • Args is a list that Webmachine provides as the

argument to the resource module’s init function upon dispatching

  • (In Erlang, a string is a list)

29

slide-40
SLIDE 40

Redirect Resource

  • Dispatch target for paths / and /wiki
  • Aliases those paths to /wiki/Welcome

{["wiki"], redirect_resource, "/wiki/Welcome"}. {[], redirect_resource, "/wiki/Welcome"}.

30

slide-41
SLIDE 41

Redirect Init

  • Called whenever a request is dispatched to

the redirect resource

  • Returns its argument as state for the

request handling process

  • Argument comes from dispatch map

init(Target) -> {ok, Target}.

31

slide-42
SLIDE 42

Redirection

  • Effects redirection (HTTP status 301)
  • Returns true with redirected path
  • Redirect path is the process state returned

from init

  • Location K5 on Webmachine flow diagram

moved_permanently(RD, Target) -> {{true, Target}, RD, Target}.

32

slide-43
SLIDE 43

Wiki Pages

  • Implemented by wiki_resource module
  • Pages must be readable (of course)
  • Must also accept POSTs for editing

33

slide-44
SLIDE 44

Wiki Page Init

  • Called whenever a request is dispatched to

a wiki page

  • Returns a #ctx record as process state
  • Record holds connection to Riak database

where page data, user info, etc. are stored

init([]) -> {ok, Client} = wrc:connect(), {ok, #ctx{client = Client}}.

34

slide-45
SLIDE 45

Allowed Methods

  • Tells Webmachine what methods a wiki

page allows

  • POST and PUT allow writes
  • Webmachine default allows only HEAD and

GET allowed_methods(RD, Ctx) -> {['HEAD','GET','POST','PUT'], RD, Ctx}.

35

slide-46
SLIDE 46

Accepted Content

  • Tells Webmachine what content (MIME

types) a wiki page allows

  • Also what function to call to process each

MIME type

  • Call accept_form to handle URL-encoded

data

content_types_accepted(RD, Ctx) -> MT = "application/x-www-form-urlencoded", {[{MT, accept_form}], RD, Ctx}.

36

slide-47
SLIDE 47

Simplicity

  • Identify the resource functions specific to

each resource module

  • Webmachine provides reasonable defaults

for all resource functions

  • Take advantage of Erlang’s “let it crash”

philosophy

  • avoid reams of (buggy, incomplete) error-

handling code

37

slide-48
SLIDE 48

The Webmachine Visual Debugger

38

slide-49
SLIDE 49

Hooray!

39

slide-50
SLIDE 50

But sometimes things don’t go as well.

40

slide-51
SLIDE 51

But sometimes things don’t go as well.

40

slide-52
SLIDE 52

It’s nice to know where your errors are.

41

slide-53
SLIDE 53

It’s nice to know where your errors are.

41

slide-54
SLIDE 54

wrq:path(RD) -> "/d/test?q=1.5" {{error,{error,badarg, [{erlang,list_to_integer,["1.5"]}, {some_resource,resource_exists,2}...

42

slide-55
SLIDE 55

malformed_request(ReqData, State) -> {case catch list_to_integer(wrq:get_qs_value("q","0",ReqData)) of {'EXIT', _} -> true; _ -> false end, ReqData, State}.

  • export([malformed_request/2]).

43

slide-56
SLIDE 56

malformed_request(ReqData, State) -> {case catch list_to_integer(wrq:get_qs_value("q","0",ReqData)) of {'EXIT', _} -> true; _ -> false end, ReqData, State}.

  • export([malformed_request/2]).

43

slide-57
SLIDE 57

Visual debugging helps you put the fixes in the right place.

44

slide-58
SLIDE 58

Visual debugging helps you put the fixes in the right place.

400 Bad Request

44

slide-59
SLIDE 59

Webmachine is a higher-level abstraction for HTTP .

45

slide-60
SLIDE 60

Webmachine is a higher-level abstraction for HTTP .

45

slide-61
SLIDE 61

Webmachine is not a “framework.”

No built-in templating, no ORM or built-in storage. Webmachine is a good component in a framework.

46

slide-62
SLIDE 62

Webmachine is not an all-purpose network server.

No support for arbitrary sockets, etc. Webmachine is shaped like HTTP .

47

slide-63
SLIDE 63

Webmachine is

A toolkit for easily creating well-behaved HTTP systems.

a resource server for the Web.

48

slide-64
SLIDE 64

Webmachine is sincerely flattered.

dj-webmachine: clothesline: lemmachine: nodemachine: webmachine-ruby: Django/Python Clojure Agda JavaScript Ruby

49

slide-65
SLIDE 65

Webmachine

a practical executable model for HTTP http://webmachine.basho.com/

Steve Vinoski

vinoski@ieee.org

50