00:00:17.359
for coming Hi Uh I'm Sean Cribs Uh uh this I've been a longtime Rubist but
00:00:23.600
this is my first Ruby comp and it was really awesome so far So way to go everybody Um and today I'm going to talk
00:00:31.679
about resources resources for real this time I'm totally seriously okay you guys
00:00:37.280
Everybody ready okay So a little bit background about me Um I work at uh
00:00:44.079
Bastro Technologies We make this esoterically awesome database called RIO Um and it's built in Erlang And so while
00:00:53.280
I do mostly Ruby every day uh this experience has really informed the talk
00:00:58.399
I'm about to give and uh all the things I've been thinking about with respect to HTTP And you're going to hear me say
00:01:04.559
that a lot So um the HTTP bit So I'm going to start with a little
00:01:10.799
story And um I want to make sure that uh uh everyone realizes when I tell this
00:01:17.520
story that uh I'm not intending to attack anyone specific but rather make us think about how we do things a little
00:01:24.640
bit differently So uh five months ago I posed this question on Twitter and it
00:01:31.200
ended up on a thread on Convore as well And I basically said uh rack and whiskey
00:01:37.520
is broken right um and uh I didn't
00:01:42.960
really say why I was like do you think it is why do you think it is why do you not think it is and I was really trying
00:01:49.520
to elicit answers like well okay here's how we did something really interesting
00:01:54.640
for HTTP with rack or with whiskey or with ring which happens to be the closure port Um or here's how we tried
00:02:03.360
to do this one thing that's very HTTP specific but our code ended up being brittle and and coupled and it just
00:02:10.000
didn't work right But instead I got answers like this Rack
00:02:15.720
works Lots of people make it work So it ain't broke
00:02:21.280
So I want to take us uh on a little tour um in a very uh selective fashion of uh
00:02:29.840
how we've done HTTP programs HTTP applications of Ruby in the past Uh so if we flash back to uh
00:02:39.680
the late '9s uh there was this invention of CGI And CGI was really kind of the
00:02:44.879
first way to build uh dynamic web applications that uh weren't actually
00:02:50.800
compiled into the web server So the way it worked was that the web server would actually uh fork itself or shell out um
00:02:59.519
set some environment variables and then exec your program Uh those are all system calls basically Um and so your
00:03:06.959
program received information about the request that came to the web server uh through the environment variables It's a
00:03:13.040
really simple way to uh create an application without uh a whole lot of uh
00:03:19.040
needing to abstract or provide an extra API inside the the web server and then
00:03:24.879
uh if the request included uh some uh body some entity uh you receive that on
00:03:30.319
standard input and you would send your response back to the web server on standard output It's a really simple model And so you might do something like
00:03:37.440
this This is a Ruby CGI program Notice I didn't even require CGI at the time Uh
00:03:42.640
but you could just uh write some headers uh writing to standard out and then write write the body and then that would
00:03:49.280
be passed back to the client Um if you wanted to get fancy you
00:03:54.319
would require CGI and CGI would actually do some HTML generation stuff like uh
00:04:00.000
for you You could tell it like HTML 3 or HTML 4 How many people did CGI in Ruby i
00:04:06.640
Yeah quite a few All right So this was kind of cool Uh we had a nice Ruby DSL
00:04:12.000
around CGI Uh but it's still CGI So then we got
00:04:17.040
uh WebRick And notice these events are not necessarily in any particular order so take that with a grain of salt Uh web
00:04:24.080
is cool because it's actually a standalone server we're not uh acting as a subprocess of like Apache or uh some
00:04:30.880
other web server you might have used IIS I don't know um so it had this nice
00:04:36.560
little serlet interface which is kind of maybe influenced by uh a lot of how Java
00:04:42.160
uh web application development was done in the late 90s early ops which is you
00:04:47.360
create a class which uh inherits from a serlet and then provides some methods
00:04:53.040
that will produce a response given a specific specific HTTP method So in this case we you know you send a get to this
00:04:59.919
serlet and it's going to set the status to 200 and the body to hello world Uh this is a really contrived example but
00:05:06.000
that's basically how you would structure a web application And then holy crap we have
00:05:13.919
Rails And I put exclamation points on on everything like this because Rails was awesome You guys remember when Rails
00:05:20.320
came out yeah So holy cow we have MVC We don't have to muck with the lower level
00:05:25.680
details We can make really awesome dynamic web applications Now Ruby's cool
00:05:31.520
Okay so what did Rails look like you could write a route uh that would point
00:05:36.800
a specific URL to a controller and an action and then like down in your controller you could you know do some
00:05:42.880
stuff and then render a template automatically And reals is really cool because you didn't have to do uh too
00:05:49.440
much work to get it up and running And then uh in 2006 David blew our minds
00:05:56.000
again We had zoomg rest Every remember everybody remember when rest came out we
00:06:01.840
had this world of resources Uh we had easy APIs You can directly map your URLs
00:06:07.120
to your models It was really awesome You can actually provide multiple uh
00:06:12.400
multiple media types with this respond to thing which is kind of cool And then you didn't have to like create some
00:06:18.479
custom routing uh to all these crazy actions that you might have created in your controller You only had no seven
00:06:25.600
only seven Okay So that's cool Um so in your routes you'd like do something like resources widgets All right I don't have
00:06:32.319
to write widgets index widgets edit Um all of those uh went away And then you
00:06:38.960
might do something like uh provide XML to your uh to your client if they
00:06:45.039
request it Uh so you you know in and the default would be to render a template So
00:06:50.960
this is really cool Um and amongst all this excitement I wanted to point out uh
00:06:56.639
in a brief digression two voices in the wilderness And the first one is uh in
00:07:02.000
2007 Scott Raymond gave a talk Uh this is kind of a follow-up to David Hannah Hansen's talk about resources which is
00:07:09.360
doing rest right And in this talk he talked about what Rails said rest was and what
00:07:17.280
actually Roy Fielding's the thesis said rest was And I'm not going to go into the details but um it's really
00:07:23.360
interesting that this uh talk didn't get more attention later on in the years And
00:07:28.880
then um and maybe this is just uh a little bit of sheamus brown-nosing to Ben because he's a nice guy but uh in
00:07:35.759
2008 at Ruby Comp Ben Scoffield gave this talk All I really need to know I learned by writing my own web framework
00:07:42.800
And Ben proposed the idea that actually what we should do is separate the concept of working with collections of
00:07:49.840
things with working of on individual items of things because a collection is a thing as well Mhm Um so keep these two
00:07:57.840
things in mind Uh if you've seen these presentations before keep these in mind as I as I go
00:08:03.960
forward So then you know we we started building a lot of Rails applications and
00:08:09.919
uh and then along came this thing called Sinatra um that decided that Rails was
00:08:15.520
too heavy So let's make it lower level Let's make it really simple Let's make a beautiful DSL It's built on top of rack
00:08:22.800
Um and the way that it worked was that you would have URLs that uh combined
00:08:28.240
with the HTTP method and that points to some action that your application should perform So Sinatra with the little wrath
00:08:36.320
mixed in this is what the code might look like Uh we put a middleware on top to say all of my responses are J
00:08:42.240
application JSON content type and then if I get bar I return some JSON log as
00:08:48.000
the response So I want to take uh a deeper look at
00:08:53.440
rack And here's probably where I'm going to make some people mad So beware Uh
00:08:58.880
rack is structured in an interesting way Uh at the top layer facing your uh
00:09:05.680
facing your client facing your web server are these handlers and your web server thing And what that does is it
00:09:12.480
takes the web server handles the bare uh HTTP transport and understanding the messages and parsing it and producing
00:09:19.920
messages on the way out Uh and they have various handlers You can plug all kinds
00:09:25.680
of different uh web servers into rack And it's partly why we have so many Ruby web servers is because rack provides
00:09:32.240
this very uh consistent interface And then you would have a stack of middleware and middleware do
00:09:38.560
various things along the way uh to change the input to your actual
00:09:44.720
application or modify things that are in the response on the way out And then at the very bottom of this stack you have
00:09:51.279
your actual application So uh rack simp has a really simple
00:09:57.120
interface and it's when you want to uh make a request to an application rack
00:10:02.800
does appall and passes this hash called the em and then uh all the the contract of
00:10:11.360
your application is to return an array of of three elements that includes the
00:10:16.480
status which is an integer headers which is a hash of uh response headers and then the body which is some kind of
00:10:22.480
innumerable thing that can be written now uh in the
00:10:27.560
response So um it's you know a really simple interface It's simple to understand and
00:10:34.000
it promises a lot of things Uh one of the things that it promises is composability because you've isolated
00:10:40.079
these things into different strata You build uh middleware to uh wrap new kinds
00:10:46.640
of behavior around your application Uh and again it has a simple
00:10:51.680
interface This is really uh really beautiful to write things in a really compact form and you always know what to
00:10:58.800
do to invoke the application you always know that you're going to receive an environment
00:11:04.360
hash and there's the potential there for the separation of concerns and I'm actually going to challenge all of these
00:11:10.320
things in a moment but um so let's take a look at racks primary mantra is if you
00:11:18.880
like this thing put a middleware on it right okay so you want this behavior write a middleware and this might be some
00:11:25.040
middleware we wrote and it like calls in and it adds a header to the response on
00:11:30.320
the way So that's pretty cool right
00:11:36.279
um so put that back up there That's great
00:11:42.160
Um I was looking for an opportunity to use that in a presentation So okay So I want to
00:11:49.040
actually look at why um at my original premise which is the uh unasserted
00:11:55.519
assertion the un uh un um
00:12:00.680
unsubstantiated assertion I made back in May that rack is broken And I want to talk about individual problems that I
00:12:07.839
started to run into when I was building uh lightweight uh web services for
00:12:13.920
automation of the work that I do at Basho and various other things that um
00:12:19.680
that uh you know I wanted to make my life easier So I think the biggest problem with rack
00:12:27.839
is that when you build a middleware stack and you've got your application at the bottom and you've got this stack of
00:12:34.120
middleware the only tool that you have is the environment hash going down the
00:12:40.480
stack and the three tuple essentially going back up the stack Your application
00:12:47.360
does not know what comes above it and your middleware doesn't know what
00:12:53.519
comes below it and so you have a bunch of of problems uh when you are trying to
00:13:00.399
do interesting HTTP behavior and what this results in is actually the environment hash becomes a
00:13:06.680
dumpster So um the environment hash actually comes from the idea of environment variables in CGI This is not
00:13:13.519
a new idea This is not a revolutionary idea Um but uh with the environment if that's
00:13:21.680
the only thing you have that you can pass down the stack you'll throw everything in it that your application
00:13:27.839
down below needs Um and so it becomes this kind of ugly ball of mud that flows
00:13:34.320
through your application And your applications down below don't necessarily know what's coming in It's
00:13:39.760
not just information about the request It's also like hey what do I log to um what's my session store those kinds of
00:13:46.880
things um are actually tangential to the concern of uh how uh HTTP
00:13:54.360
works rather or probably orthogonal is probably the better word for that The other thing is that you so you in this
00:14:00.160
dumpster of the invite env you tend to communicate by convention Your app starts to realize oh yeah I have this
00:14:06.720
rack.logger key that I can get the logger and log some messages the console um or I have this uh rack session or
00:14:14.079
rack.input which I can read the input from and it's not actually saying your your your middleware stack and rack is
00:14:20.639
not actually passing these things explicitly to you in a form that you can understand unless you know what's in
00:14:26.480
that environment h cache The other aspect is middleware order matters So a good example is uh the HTTP spec says uh
00:14:35.040
let's say you want you want to use a transfer not a transfer encoding excuse me uh content encoding of gzip because
00:14:41.680
you want to make your responses smaller Um however the spec says that your the
00:14:47.760
length of that response needs to the content length header needs to match the actual length of the response So if you
00:14:55.199
by mistake put the content length uh middleware that you've created to figure
00:15:00.399
out what the length of your bo response body is if you put that below the gzip you're breaking the spec and your
00:15:06.959
client's probably going to go this thing's corrupted I don't know what to do with it so middleware order is really
00:15:12.480
significant probably more significant than it should be and the other issue is because we have this uh you know the
00:15:19.600
environment is a dumpster it's blind up line down um you end end up not separating concerns the way you intended
00:15:26.480
to You end up actually introducing coupling between components in your application because you can't separate
00:15:32.560
what the middleware does to the environment from what your application is trying to do with that So um the you
00:15:40.240
you introduce a lot of coupling So that's that's enough about that I've bashed it enough I want to make this
00:15:45.760
better So what can we do to make make rack and building HTTP applications on Ruby better
00:15:54.560
this is a big graph You're not supposed to be able to read it but I think the first thing we can do is realize that
00:16:00.720
HTTP is hard Um this is a flowchart that was
00:16:07.279
developed by a few people um who I know um and they went through the RFC for
00:16:14.079
HTTP 1.1 and said here are all these assertions these musts these shoulds these should nots these may uh that
00:16:22.240
happen in the spec and let's turn that into a logical model of given these
00:16:29.040
constraints what response code should the server return Um I don't know about you but if
00:16:36.320
you look at this flowchart it doesn't look like a composable stack of things
00:16:41.600
It branches Um it it actually doesn't look like a stack at all It looks like a state machine It has various transitions
00:16:49.519
and various end states and a start state with the black dot there on the
00:16:55.079
left So we have a lot of hard questions to answer um you know is this request
00:17:03.360
method given by the client allowed what kind of media types does my my application provide what it what should
00:17:10.000
it return given this client request is the response cachable uh did they send a conditional request how can I determine
00:17:16.799
whether the response should be a three or four not modified or not did the resource move is this a redirect um all
00:17:23.360
these questions are really hard to a answer with rack because the question becomes where do you put this logic can
00:17:30.640
your middleware answer these questions can your application answer these questions and usually I found when
00:17:36.080
putting these things these rack applications together I was pushed in either direction I either put most of my
00:17:42.240
things in the application which means that I have a lot of this logic that I'm
00:17:47.280
rewriting every time or I pushed it in the middleware and I'm introduced coupling uh down the stack
00:17:54.000
So I think what we can realize from this and especially that flowchart even without understanding what's on it is
00:18:01.400
that the HTTP RFC has been around for a good 10 years or so HTTP doesn't change
00:18:08.320
What changes is our applications the resources in your applications So what
00:18:13.679
we can do is we can encapsulate those hard decisions and then reuse them for every application There's no reason why
00:18:20.160
uh your application has to pick and choose uh which behaviors of HTTP it wants to use That logic is separate from
00:18:27.440
what your application actually is So let's think about shaping our applications like HTTP Let's use
00:18:35.080
resources What is the spec say a resource is and this is paraphrased Uh you can find this uh if you go to the
00:18:41.520
IETF uh site Um and uh sorry just a quick digression Don't ever try to argue
00:18:48.080
with something about uh with someone about RFC 2616 because it will go on
00:18:53.400
forever Um so and and here I am starting this argument so feel free to hit me up
00:18:59.200
later Um a resource is essentially uh a data object like a file um or uh some
00:19:07.440
piece of bytes or some service that is uh being provided to a client
00:19:14.640
resources are identified by URIs So not so there's this duel of between a
00:19:20.880
resource its data its uh the service that it provides and what its URI is And
00:19:26.320
so these are the most the two most important concepts with respect to uh understanding resources And then there's
00:19:33.200
also the idea of representations uh a URI I'm sorry a resource may have some
00:19:38.720
uh multiple internal representations multiple representations it exposes to
00:19:43.760
the client uh and when I say representations I mean things like the media type content type um things like
00:19:51.120
uh the encoding is it gzip is it deflate is it just bear uh and also things like
00:19:56.720
the language um lots of people want to do multilingual applications representations uh allow you to do
00:20:04.880
And then there are other variances and properties which uh determine the behavior of of a resource when a request
00:20:12.400
is made So I want to um introduce web
00:20:18.320
machine to you guys and how it helps us do HTTP
00:20:23.400
better So uh what web what is web machine web machine is a toolkit
00:20:29.520
uh for easily creating well- behaved HTTP applications And I want I broke those out so I could address those
00:20:35.440
points individually Uh web machine is not a framework It's a toolkit All it does is encapsulate HTTP
00:20:44.120
behavior and expose it to you in a way that is just leaky enough to get your work done
00:20:50.880
It is for easily creating these applications because it encodes a lot of
00:20:56.440
defaults sensible defaults about what you want to do in your application uh without you having to write a huge
00:21:02.960
configuration file or a lot of code And when I say well behaved uh what I mean
00:21:08.240
is these are uh your resources that you create with
00:21:13.600
web machine address all of the constraints in that spec uh very carefully and the
00:21:21.919
logic of addressing those constraints of the HTTP spec is separate from what your
00:21:27.120
resources are and they're HTTP applications and this is a little bit more subtle but you don't use web
00:21:33.600
machine uh or any of the the um aspects of web machine to write a websocket
00:21:39.919
server We're talking about applications that are spec specifically focused on the request response cycle of
00:21:47.720
HTTP Another way to think about it is web machine is an executable model of
00:21:53.240
HTTP Uh do you remember this graph I showed a minute ago this graph actually
00:21:59.360
uh is code in web machine Each of those little diamonds on the flowchart is a
00:22:05.039
single uh state of a finite state machine uh each of the boxes is a
00:22:10.159
response code that web machine will return when a given branch points to that that end
00:22:16.360
state So uh this is all uh wrapped up in code The spec is executable in that
00:22:24.200
sense So web machine is shaped like HTTP which means that instead of defining
00:22:29.760
what action your your application should take it has you declare resources So um
00:22:35.679
it's a lot more declarative than imperative And then because it encapsulates all those constraints of
00:22:41.840
the HTTP spec it will negotiate those hard decisions that we talked about before
00:22:48.360
transparently and then it will respond with the right status code And of course it uses sensible
00:22:55.200
default behaviors so that you don't have to write everything every little decision that your resource exposes
00:23:01.520
every little property you don't have to write it up front There's a lot of sensible defaults and I can't emphasize this
00:23:07.919
enough Road machine is not a framework It has no OM It has no templating system You can hook one in if you want It has
00:23:15.120
no plugins It has no asset pipeline I knew that one would get get
00:23:20.480
some some uh some response So um it's just a resource server for writing web
00:23:28.159
applications uh I might gloss over this a little bit
00:23:33.520
It's resource focused So this means that resources are the core building block of the application Resources are grouped by
00:23:39.760
common behavior into classes which I call tend to call resource families Um and those are subclass from the uh the
00:23:47.280
web machine resource class Um and these these resources have a well-defined uh
00:23:53.760
consistent interface to the HTTP logic that is in encapsulated in that state machine
00:24:00.080
And then you take uh you take a step out of your resource and you actually map
00:24:05.280
your URIs patterns of URIs to those resource families that you want to provide So uh again the code is a little
00:24:13.120
small but there are 36 resource callbacks that you can define and I'll show in a minute excuse
00:24:20.080
me with some code that you really only have to define one if you just want to produce an HTML response with 200 Okay
00:24:27.600
But you can do a lot of stuff like uh you can uh provide different representations uh you can provide
00:24:34.000
different languages You can tell when the resource was last modified These are all kind of declarative
00:24:40.720
uh properties of your resource There are a few of these callbacks that are actually here take an action Um but
00:24:48.480
those are very constrained and limited in number So uh it has a very simple
00:24:54.320
dispatching It doesn't use any rack routing or anything like that Um I didn't even copy any code Uh but
00:25:00.400
basically it'll take the path of the URI break it into segments and then if you put uh in your segment in your uh your
00:25:08.159
route pattern uh symbols in the pattern it'll bind those segments of the path to
00:25:13.600
symbols So this is similar to what you did in Rails where you did like slash and you colon something you slash colon
00:25:19.520
something else Uh you can bind path segments to symbols Um you can also have a trailing wild
00:25:25.440
card on your route which will match any number of segments in the URL So this is kind of like the splat URL you might
00:25:30.720
have done in Rails as well Um and those will be available as an array of segments uh to your resource And then
00:25:38.000
there's also um in addition to binding portions of the path to a symbol you can
00:25:43.840
also bind arbitrary data to a symbol So um that will be injected into this uh
00:25:49.919
path binding information uh when when you your resource uh receives a request
00:25:55.039
And this is not entirely clear from this slide We'll see a bit more of this later So I really want to get into an example
00:26:01.679
You know I've talked about the highle stuff We talked about um the model Let's actually do something for real And I'm
00:26:08.559
going to attempt the presentation guys by doing a live demo So uh let's start by first creating a
00:26:15.919
very basic resource Uh you just require web web machine and you define a class which
00:26:22.880
inherits from web machine resource And the only call back the initial call back that you have to provide to produce a
00:26:29.520
200 okay with HTML is just this two HTML method and all it does is return a
00:26:36.720
string which is the body That's pretty simple right i said easily creating right okay that's not too bad Now that
00:26:43.279
we've got a resource let's hook it up um and actually add a route So I'm adding a
00:26:49.760
route to the dispatcher which and this this API will probably change in uh in a
00:26:54.960
next release probably but I'm basically just saying at the root URL there's no path segments just the root I want to
00:27:02.720
map that to the page resource and then I'm going to run the server So uh here's where I attempt the
00:27:08.000
demo uh switch to terminal Okay So um I've provide I've
00:27:16.080
created a bunch of these examples actually in Ruby files and we're going to run them
00:27:33.720
individually Oh I broke it I'm sorry I did temp the demo
00:27:47.159
guns Let's try it again There we go So uh it spun up Web
00:27:54.720
Rick Um there are actually two uh web server adapters available right now for
00:28:00.640
Web Machine The first one I wrote is WebRick because it's really easy to understand and get hooked up Uh we also
00:28:05.840
have Mongrel 1.2 two pre whatever Um and I'm working on more as as we go So we've
00:28:12.640
got this uh web server running Uh let's flip back over to our
00:28:18.520
browser Let's see if I can't get it up and let's go to there's my mouse Let's local port
00:28:26.960
localhost port 8080 And there Okay So this is not really revolutionary but um
00:28:33.679
there's some content that we produced Okay that's not not really um
00:28:40.320
that interesting All right content Who likes content okay you're ready for VC yeah All right
00:28:47.600
man Start my my uh startup now Okay so uh we
00:28:53.919
want to do more than just send a static stream to the browser every time So let's add an ERB layout and render some
00:29:01.440
stuff in this template So we made a really simple uh simple ERB template and
00:29:08.080
it kind of refers to this page thing So we're talking about a page resource Maybe in my application I'm going to put
00:29:13.600
a page model in there somewhere Um and then it'll have a title and content and I'll just put that in each one and and
00:29:20.480
be done with it So uh here's the interesting part Um we're going to start implementing some more
00:29:26.919
callbacks And I've created the page model for now as a little strruct uh that has a title and content And uh then
00:29:34.640
I'm going to implement this resource exists callback Now it's not really that interesting um in this example but we'll
00:29:41.600
see how it becomes more interesting in a minute Um so we just created a new page object from that uh page struck really
00:29:48.240
and we say yes this resource exists So I'm going to return true Um if I return false do you get a
00:29:55.880
404 it's pretty clear Okay And then I've changed my two HTML method to take that
00:30:01.039
ERB layout that I that template that I did and uh evaluate it against the
00:30:06.559
binding of the local object which has the page instance variable So uh let's switch back to my
00:30:15.120
terminal briefly Okay So I'm going to I'm going to kill this example
00:30:22.960
Crl + C And we're going to run example two which has our
00:30:35.960
layout Okay And let's refresh that Okay Now I have an H1 and it says hello world
00:30:42.559
Okay That's not very exciting but let's let's uh let's add some more interesting
00:30:47.600
behavior to it So we could actually use a real model for that And um I create this uh sort of
00:30:55.840
OM document mapper thing for RIO Um it's called riffle and it kind of looks a
00:31:01.760
little bit like data mapper a little bit like mapper Um so we make a real model that reads something out of a data
00:31:07.679
store Um and it has title content and it has updated created app timestamps on it
00:31:13.679
That's no big deal So here's where that resource exists gets interesting Let's see if we
00:31:19.679
can't find that model to be rendered in our resource And then if we don't find
00:31:25.279
it we can say you know if the the p pagefind call returns nil so there's no object there then we can say well is the
00:31:32.399
page present and if it's not there you can return a 404 Oops Um so in order to
00:31:38.720
support this we need to add a route And uh notice I'm asked I mentioned the path bindings that's part of the request
00:31:45.760
object you have available on your resource Um and it's just a hash of all the bindings that your the router
00:31:52.000
created for your resource when it matched the path Um and so in this case I'm using a simple path segment that's a
00:31:58.200
slug And remember I said you can have static bindings on your routes So in the case of the root route we want to say
00:32:04.559
well the slug is some magic uh name This is not really interesting CMS sorry Uh
00:32:10.320
but the uh so we always have a binding for that slug in the path information
00:32:16.480
that we can use to try to find the model that we uh want to present to the
00:32:22.519
client Okay let's let's go back to our our terminal and run that
00:32:29.240
one Sample
00:32:35.960
three Yeah Yeah it's complaining about uh running active model 3.1 and my
00:32:42.320
ripple is not up to date So if we switch back to here and we refresh and oh hey
00:32:51.360
before this presentation I put a root page in there So we have another page
00:32:56.399
and actually if we um go up here and put in some other URL
00:33:02.240
like foo Okay we got 404 not found because it didn't find that document in
00:33:07.760
the reop database when it tried to request it We haven't written much code yet have
00:33:13.880
we okay so uh we're still okay Let's go another step You
00:33:21.519
know we want cool APIs Uh so let's implement JSON as a
00:33:27.440
media type Okay well this is pretty simple actually All you do is you implement the content types provided
00:33:32.880
callback And this is actually one that was a default and the default was that first array in the nested array which
00:33:39.279
was I want to return text HTML and call the two HTML method to produce the body So we're going to call we want to
00:33:45.279
provide application JSON media type and call to JSON to produce the body And all
00:33:50.880
we have to do in that twojson method is uh take the page object that we've got
00:33:56.720
already and get its attributes and call it tojson So um this one I'm going to have
00:34:04.399
to do in the terminal So I'm going to flip over here Uh first let's fire up
00:34:11.520
our next example and then I'll flip over here
00:34:26.480
Okay so the interesting thing about web machine is it doesn't actually use
00:34:31.760
portions of the URL to tell you what media type to return That's actually in some ways an anti-attern and a but a
00:34:39.440
workaround for browsers so you can see your JSON or XML right um so actually the proper way to do it with HTTP is to
00:34:46.240
send an accept header say I want this media type or I want these possible media types So um without going into too much
00:34:55.119
detail about it I'm going to use curl and set an accept header of application
00:35:00.880
JSON saying I don't want the HTML format I want the JSON format and uh and request it and hey I
00:35:08.560
got JSON back instead of HTML That was pretty easy Look it even said hey you
00:35:14.240
can vary what you get back by changing your accept header Okay
00:35:23.240
so let's add conditional requests This is pretty simple too
00:35:28.320
Remember we add those timestamps to our model We can say oh last modified is last time that the model was updated And
00:35:34.240
then uh incidental to the implementation of ripple is that there's actually an object underneath uh the model that uh
00:35:42.480
has some properties that were received from the reop database including an E tag So we can just kind of you reuse
00:35:47.520
that E tag um as the E tag for our uh for our resource
00:35:55.040
So if we flip back here and run the next
00:36:07.800
example Okay And let's go back to our browser this time
00:36:17.280
And in order to get this to make sense uh I'm gonna have to pop up the web
00:36:25.720
inspector and go to the network tab So um if I go back to the root
00:36:33.320
URL uh which I knew had a page before you see we have a 200 response down here
00:36:39.119
What if I navigate to it again oh Chrome cached it I got a 304 not modified How
00:36:46.079
easy was that how many times have you tried to do people done tried to do expires or fresh or any of that stuff in
00:36:52.800
Rails remember how hard it is i think this is lots easier Okay enough straw
00:36:59.119
man Let's get back to the other one Okay so we made conditional requests Now we actually want to make kind of a CMS like
00:37:05.520
thing So let's receive uh representations as well as producing them So we have to actually add a couple
00:37:12.000
more callbacks here Um one of them is the allowed methods So if I before had
00:37:17.200
sent a request to this resource and said here I'm going to put a representation it would have said sorry that method's
00:37:23.280
not allowed because the default is like GitHub options Um so let's add put as a valid
00:37:30.599
method And then you can specify what content types do you accept So you can actually say I don't want to accept HTML
00:37:38.480
Um you know I want this kind of fine grain JSON thing So if somebody posted HTML or like a web form it's going to
00:37:44.800
say 415 uh media type not recognized or something like that Sorry I don't
00:37:51.200
remember the exact one Um but so in again like the content types provided we
00:37:56.880
send a call back which is uh store page we say when you receive this content
00:38:02.160
type run this method and in this case uh when we
00:38:07.839
receive a a page representation um as JSON in a request we don't know
00:38:14.720
necessarily where that re whether that resource existed before so maybe we we looked it up excuse me maybe we looked
00:38:22.160
it up in the database but uh it wasn't there and we normally would have returned a four not four not found it's
00:38:28.640
actually okay to send a put request to a resource that doesn't exist You're telling it here here's a representation
00:38:35.040
of something new Um so in this case we're going to take the slug out of the the path info that we bound earlier
00:38:41.599
remember and set it as the key of this this uh the primary key of this object
00:38:46.800
And then we'll parse the body response body as JSON and run update attributes
00:38:52.400
That's pretty simple So let's run that example
00:39:01.599
example six And again here because I'm only putting JSON um I have to do this with
00:39:09.680
Pearl So bear with me on
00:39:21.000
that So here's what we're going to do with Pearl Uh and let me fix that too So
00:39:27.920
we're going to say uh content type of what I'm posting is application JSON Um I'm going to receive
00:39:34.560
the data on standard in That's what the at dash means Uh we're posting it to the root URL So we're going to change the
00:39:40.839
homepage And then we're going to use the uh the put
00:39:46.200
method And here I'm going to paste in my response or my uh request
00:39:52.520
body and send it and it said okay four or 20 four no content which basically means I
00:39:59.760
received the put nothing went wrong So let's actually see what happened in our
00:40:05.880
browser Let's refresh that Oh hey I changed the homepage That's pretty
00:40:11.800
cool But you know you're building a web application You kind of want to secure the edges of it So
00:40:19.079
um maybe you want to authenticate puts So let's add basic authentication to this Now this this code is a little bit
00:40:25.680
more squirly than what what I've shown before Um that's probably because I didn't encapsulate this basic
00:40:31.040
authentication um into something else And I actually have intentions to do that in the next release of Web Machine
00:40:36.960
Um but basically what we're doing is just defining another callback Is this request authorized and what that call
00:40:43.359
back gets passed is the header the authorization header or authentication
00:40:49.040
header Um and so in this case if the method is put if it's not put yes it's
00:40:55.599
authorized Go ahead If it is put let's check what actually what the
00:41:00.960
authorization they gave me was And the stuff down at the bottom is really just let's decode the base 64 and split the
00:41:08.160
username and password and make sure that it's this credentials Um I could done this more elegantly but I figured it was
00:41:14.720
a pretty simple example So let's actually see what happens when
00:41:21.440
uh we authenticate our codes This is my final
00:41:29.079
example Okay So if I try this one
00:41:37.560
again and I post that I get 401 unauthorized It says "Hey you need to
00:41:45.200
authenticate using HTTP basic." You look that authenticate WW
00:41:50.319
authenticate header That's where it's you see that And now actually um why don't I go ahead and put in there the
00:41:57.119
username and password which is another little curl flag
00:42:02.800
and try the post again or the put rather says okay cool for no content I actually
00:42:10.160
updated it again let's let's let's run this again and uh whoops and change this
00:42:16.160
a little bit
00:42:24.200
website okay so it accepted it we go back to the browser
00:42:31.040
refresh it website So this is not really revolutionary stuff but I hope what you
00:42:37.680
see is that get back to right browser I hope
00:42:44.560
what you see is that you've actually started thinking about your application in terms of how HTTP sees it rather than
00:42:52.160
in terms of it being like MVC or um or this wrapped middleware stack that
00:42:58.720
doesn't know anything about HTTP You're you're constructing your application in the shape of HTTP So you can get Web
00:43:06.560
Machine on GitHub It's also available as a Ruby gem Um my slides are in that second link Uh that's the the uh actual
00:43:15.520
uh repository for it or you can go uh veroku.com this is using showoff and
00:43:21.359
review the slides there I do want to give a few acknowledgements uh my co-workers um and some really awesome
00:43:28.000
people Justin GT Brian Frink and Gross uh who created the original web machine Um I'm I'm not that creative or smart Uh
00:43:37.359
they figured out that flowchart um and they encoded it first it was an Erling Um so if you want to see the original
00:43:44.560
source um and how much the Ruby part the Ruby counterpart deviates from it go
00:43:49.839
there And then I have a couple committers who've helped me move it along in the past month or two Um Ian
00:43:55.520
Postcer is a co-orker of mine and Baron Dollars who's just some guy who kind of thinks web machine is cool So um I would
00:44:02.160
be happy to take questions I know I was going to run long um but uh you know in
00:44:07.280
any format but these languages anybody
00:44:12.720
yeah in the back I can see how it's a really nice
00:44:19.760
abstraction around but do you see there being an advantage
00:44:25.440
to doing something like a layer on top like that of
00:44:37.000
So I think my the the question was do you see a layer going on top of web
00:44:44.800
machine um that is uh more abstract more friendly um my contention is actually
00:44:51.680
this is really simple and I'll show you if I have the example up I'll show you the final
00:45:01.760
uh version of this application that we just built
00:45:07.319
Um I guess my point is um that
00:45:13.079
we when we do something like Sinatra you're focusing on the action the server
00:45:18.480
should perform not what the resource is And HTTP except in a few very narrow
00:45:23.839
cases like a post request is not about performing an action It's about transferring representations um in an
00:45:30.640
essentially stateless protocol Um so the other thing about focusing on uh an
00:45:38.400
application as actions rather than a resource is that you're encouraged to introduce side effects where the
00:45:44.400
protocol says this should be side effect free Um and so I'm not saying that web
00:45:50.640
machine will replace anything we already have because obviously you know as people said in that first question uh
00:45:56.560
that I posed It works uh it works for a lot of people and I don't expect this to
00:46:02.000
replace Rails or Sinatra or any of those things But what I would like this to do is actually get us thinking about how
00:46:09.040
can we do HTTP better um and how might we evolve the other things that we like
00:46:14.160
to use from day to day Um and is there a question still over here and then I'll be to council uh
00:46:21.000
yeah first of all a few things to that Um there is there are plans by there are at least
00:46:30.319
three court team members of rack here We had a meeting and there are plans to
00:46:35.680
write a replacement for rack and have future rails and Sinatra versions run on
00:46:41.760
top of that But it still will not be declarative And I totally agree with
00:46:48.079
most of what he said See Andrew I saw you in the front row I
00:46:53.680
was like I'm I'm I'm probably going to piss him off
00:46:59.440
No actually um I had some of my thoughts similar to that with the resource
00:47:05.040
oriented and so on Talk to people about that Um there are a few things
00:47:13.000
though Uh first of all a comment on No I'm not sure how much I should go to
00:47:19.319
detail Um I should do that at first Uh but how do you deal with you
00:47:26.040
like how do you deal with for instance web browsers treating HTTP like
00:47:32.400
crap so um in this case I would say the question was how do you deal with uh bad
00:47:39.119
browsers treating HTTP like crap and I think that this is a real
00:47:44.280
problem we as developers should start addressing We need to start you could
00:47:49.839
not use that CMS with the browser because no brow no uh most webkit
00:47:55.359
browsers and internet explorer do not set do not do proper content negotiation I agree they do not do proper content
00:48:02.000
negotiation I and my point is that what we should be doing is providing for pressure against browser I mean how many
00:48:09.599
times have we had that uh that extra query string thing to override the
00:48:14.880
method Uh how many years have we had that it's been a long time I think we should be putting pressure against
00:48:20.240
browser implementers to say your you know your HTML form should be able to have a put method Um and I understand
00:48:27.200
the accept thing Um and I don't think that that is going to change anytime soon but I think the times that you want
00:48:34.079
to uh provide different uh formats to a browser um you're not going to be doing
00:48:42.559
an API type thing So you know I mentioned that I don't think that web machine is going to replace or its model
00:48:48.160
is going to replace rack or rails or Sinatra And part of that is that uh
00:48:53.680
Rails especially encodes a lot of information about how to deal with bad browsers Yeah Also um another question
00:49:00.400
is are you planning on implementing the complete HTTP SP
00:49:05.520
so that's a very loaded question Um so the question was are are you planning on
00:49:10.800
implementing the entire HTTP spec like um for instance you're not dealing
00:49:16.800
correctly with optimistic looking with the modified insiders at the moment
00:49:22.160
because you have no notion of a resource being existing
00:49:28.240
That is actually incorrect Uh what the flowchart does is if the resource does not exist then you never enter
00:49:35.440
conditional requests negotiation Um so because there's no way
00:49:42.280
so it will actually see if if you pass an if match
00:49:47.920
if match or if match if nonmatch star you will actually get a 412 uh precondition failed response if you if
00:49:54.400
the resource does not exist So the context is you could do an HTTP request basically saying only only
00:50:02.400
update this page if it already exists or only create this page if it doesn't exist and there is some traffic in there
00:50:10.480
There are ways we can improve that for sure Um and in fact it's been a a couple years since that flowchart was designed
00:50:17.280
and I know there are some additions that uh Justin and my other colleagues will want to do Um and I'll be sure to encode
00:50:23.440
that in the Ruby version as soon as I can Okay Uh one we're way over but one
00:50:28.960
last question Oh I'm sorry My question was very similar I just said do you make any allowances for the fact that
00:50:34.480
browsers can't submit anything other than get and focus yeah So the
00:50:39.680
interesting thing is we actually um in the Erlang version uh resources
00:50:45.440
we've written um we will actually allow post for clients that don't know put
00:50:52.559
don't understand put and then kind of uh through a little bit of inspecting the
00:50:58.000
request closely um kind of upcycle it to a put Um so there there are ways to do
00:51:04.960
that um they're not the pretty declarative way You have to look at it a
00:51:10.000
little bit more closely So reality yeah it's reality sucks This is an
00:51:18.359
ideal Thank you so much for listening to me