Summarized using AI

Resources, For Real This Time (with Webmachine)

Sean Cribbs • September 29, 2011 • New Orleans, Louisiana • Talk

The video titled "Resources, For Real This Time" by Sean Cribbs, presented at RubyConf 2011, delves into the evolving practices of building HTTP applications using Ruby. Cribbs argues for a paradigm shift where applications are designed around the HTTP protocol rather than forcing HTTP into application architectures like MVC.

Key Points Discussed:

- Background on Cribbs' Experience:

- Cribbs introduces himself and discusses his background in Ruby and Erlang, linking it to his understanding of HTTP.

  • Evolution of Ruby HTTP Applications:

    • He traces the historical progression of web technologies from CGI to Webrick, Rails, and Sinatra, highlighting how each step simplified the web application development process.
  • Limitations of Rack:

    • Cribbs critiques Rack's architecture, emphasizing that its reliance on an environment hash for passing data leads to coupling and limits flexibility. He points out that Rack's middleware stack can create complexities in HTTP behavior handling.
  • Proposing a Better Approach:

    • He introduces Webmachine as a toolkit that better aligns Ruby applications with HTTP principles.
    • Webmachine encapsulates HTTP behaviors, allowing developers to focus on defining resources rather than actions, leading to a clearer and more structured application design.
  • Key Features of Webmachine:

    • Declarative resource definition, sensible defaults for HTTP behaviors, and a design that encourages correct HTTP responses based on specifications without intensive boilerplate code.
  • Demonstrations:

    • Throughout his talk, Cribbs illustrates the power of Webmachine with live coding demonstrations, showcasing how easily JSON media types and conditional requests can be implemented, stressing the toolkit's efficiency and usability.
  • Final Thoughts:

    • Cribbs concludes by encouraging the Ruby community to rethink application design in terms of HTTP principles and suggests that Webmachine’s philosophy could improve existing frameworks like Rails and Sinatra.

Main Takeaways:

- HTTP is a complex protocol that, when better understood and implemented, can lead to more robust Ruby applications.

- Webmachine provides a powerful alternative to traditional methods by promoting a resource-based approach that aligns better with HTTP standards, offering a more organized structure for web application development.

Resources, For Real This Time (with Webmachine)
Sean Cribbs • New Orleans, Louisiana • Talk

Date: September 29, 2011
Published: December 13, 2011
Announced: unknown

Over the past 5-6 years we have seen a lot of changes in the way that Ruby apps speak HTTP -- from Rails' "REST" conventions, to the brilliantly simple Sinatra, to the modular Rack abstraction -- but we haven't yet unlocked the entire subtle power of HTTP. We know HTTP is so much more than verbs and URLs that correspond to CRUD, and yet it's still too hard to do conditional requests, content negotiation, and then return the right type of response. What if, instead of forcing HTTP into our MVC-shaped applications, we shaped our applications like HTTP? Instead of forcing a resource into seven controller actions or verb/URL-specific methods, what if the resource itself was the abstraction? A whole world of subtle and powerful programming patterns emerge. This is the world of Webmachine, a toolkit for building HTTP applications and a port of the Erlang toolkit of the same name. I will introduce Webmachine's unique programming model and demonstrate how to easily expose rich HTTP behavior in a few short lines of Ruby code.

RubyConf 2011

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
Explore all talks recorded at RubyConf 2011
+55