We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Rack ‘em, Stack ‘em Web Apps

00:00

Formal Metadata

Title
Rack ‘em, Stack ‘em Web Apps
Title of Series
Part Number
55
Number of Parts
86
Author
License
CC Attribution - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
While Rails is the most common Ruby web framework, it’s not the only option. Rack is a simple, elegant HTTP library, ideal for microservices and high performance applications. In this talk, you’ll see Rack from top to bottom. Starting from the simplest app, we’ll grow our code into a RESTful HTTP API. We’ll test our code, write reusable middleware, and dig through what Rack provides out of the box. Throughout, we’ll balance when Rack is a good fit, and when larger tools are needed. If you’ve heard of Rack but wondered where it fits in the Ruby web stack, here’s your chance!
Link (knot theory)Cartesian coordinate systemWeb 2.0Software frameworkServer (computing)MereologyDirection (geometry)CodeRoboticsFitness functionBookmark (World Wide Web)Interface (computing)Writing2 (number)Stack (abstract data type)Web applicationGoodness of fitSystem callWebsiteQuicksortWeb serviceCommunications protocolHash functionInternetworkingSlide ruleLibrary (computing)Degree (graph theory)NeuroinformatikComplex (psychology)Connectivity (graph theory)GenderAxiom of choicePresentation of a groupWeb browserInteractive televisionStaff (military)LogicAbstractionFrame problemArray data structureDisk read-and-write headComa BerenicesGame controllerRuby on RailsComputer animation
Parameter (computer programming)Dependent and independent variablesRadical (chemistry)Client (computing)QuicksortComputer fileHash functionSocial classEmailCodeCartesian coordinate systemContent (media)String (computer science)Instance (computer science)Type theoryWeb browserLevel (video gaming)Communications protocolNumberFlagWeb 2.0BitRevision controlObject (grammar)Physical systemExpected valueEnumerated typeCASE <Informatik>MereologySystem callServer (computing)Slide ruleWeb applicationAddress spaceSet (mathematics)Configuration spaceComputer animation
Social classParameter (computer programming)Software testingComputer fileQuicksortPoint (geometry)Mobile appMiddlewareObject (grammar)Cartesian coordinate systemCycle (graph theory)MereologyDependent and independent variablesWeb applicationUnit testingInheritance (object-oriented programming)Instance (computer science)Content (media)Validity (statistics)String (computer science)Open setBasis <Mathematik>Configuration spaceExpected valueWorld Wide Web ConsortiumDirection (geometry)RootLevel (video gaming)CodeEmailKey (cryptography)CASE <Informatik>Computer animation
Web 2.0CodeKey (cryptography)Computer architectureSoftware frameworkType theoryMessage passingCartesian coordinate systemDomain nameSingle-precision floating-point format1 (number)Mobile appoutputHash functionQuicksortDifferent (Kate Ryan album)InformationFundamental theorem of algebraBitUniform resource locatorProcess (computing)Web browserWorld Wide Web ConsortiumLetterpress printingSource codeCASE <Informatik>Computer animation
BitDependent and independent variablesLevel (video gaming)Object (grammar)Single-precision floating-point formatSystem callInstance (computer science)String (computer science)Statement (computer science)Social classPersonal digital assistantCASE <Informatik>Cartesian coordinate systemMobile appUniform resource locatorSoftware testingAbstractionSoftware frameworkConfiguration spaceFlow separationRoutingQuicksortNumberLatent heatScaling (geometry)Online helpHash functionMassInteractive televisionComputer animation
Hash functionSocial classInverter (logic gate)Existential quantificationInformationCellular automaton
DatabaseType theoryQuicksortString (computer science)RoutingCartesian coordinate systemCASE <Informatik>Regulärer Ausdruck <Textverarbeitung>InformationReal numberSystem callBitParameter (computer programming)RobotSocial classRepresentational state transferData structureCodeMultiplication signFunction (mathematics)Pointer (computer programming)Object (grammar)Error messageLine (geometry)Query languageMotion captureDependent and independent variablesArea2 (number)RoboticsHash functionInverter (logic gate)Software frameworkReading (process)Uniform resource locatorEmailData storage deviceMatching (graph theory)Ruby on RailsSlide ruleOnline helpXMLComputer animation
File formatPoint (geometry)Gastropod shellDependent and independent variablesWeb 2.0Client (computing)Radical (chemistry)Row (database)Web applicationForm (programming)Multiplication signQuicksortString (computer science)Moment (mathematics)Content (media)Object (grammar)Pattern languageBeta functionControl flowInformationMessage passingBitEmailCodeWritingUniform resource locatorComputer fileDatabaseCycle (graph theory)Line (geometry)Video gameSystem callDynamical systemBuildingWeb browserMatching (graph theory)DataflowBranch (computer science)MereologyClosed setSoftware frameworkSocial classParameter (computer programming)Wave packetType theoryProcess (computing)Right angleState of matterLink (knot theory)Different (Kate Ryan album)LengthValidity (statistics)RobotRepresentational state transferStreaming media
Mobile appSoftware frameworkPoint (geometry)Pattern languageConnectivity (graph theory)Dependent and independent variablesMiddlewareVideo gameBuildingStack (abstract data type)Real numberMereologyMathematicsChainMultiplication signGame controllerCuboidAuthenticationForm (programming)DiagramCartesian coordinate systemArithmetic meanLine (geometry)QuicksortKey (cryptography)Message passingHTTP cookieString (computer science)System callFile formatOnline helpStatement (computer science)Validity (statistics)Server (computing)Web pageNumberException handlingFitness functionSoftware developerConfiguration spaceObject (grammar)Integrated development environmentRoutingFluid staticsLevel (video gaming)Computer fileSequenceTouch typingSource codeInstallation artEmailDigital electronicsInsertion lossCycle (graph theory)CodeView (database)FreewareSurfaceToken ringWeb 2.0VolumenvisualisierungEmbedded systemInstance (computer science)Cache (computing)Computer animation
XML
Transcript: English(auto-generated)
Welcome everyone. Thank you for coming this afternoon. I hope you've had a good first day of RailsConf so far. My name is Jason Clark.
I worked for New Relic previously on the Ruby agent, now I'm working with some other teams on some backend services. Today I'm here to talk to you about Rack. Rack is a library that you may have heard a little bit about, but before we dig in about it, I've got a couple of links for you. The first one is the slides for this presentation,
so if it's easier for you to follow along on your computer or you want to reference it, that link will take you there. And then the second link is just a fun little Rack application that I built to demonstrate a few of the principles that are going on here. It lets you post text-based robots that'll fight each other. We're probably not gonna get down to demoing it,
but if you're like me and you kind of drift a little here and there during the presentation, feel free to go hit fight.robotlikes.com. You know, this is RailsConf, we have a code of conduct, keep it clean, keep it professional, but go have fun with that if you'd like. All right, so let's get down to the meat of what we're here to talk about today.
So if you've been around in Ruby and in Rails, you've probably heard Rack mentioned before. But what is it? It's a little ambiguous until you dig in where this fits in the ecosystem and what part it plays. Well, the easy answer is that Rack is a gem, like so many other things in Ruby.
This is a gem that provides a minimal modular adaptable interface for developing web applications. If you're like me, that doesn't really tell you a whole lot though, but we can draw a picture that kind of demonstrates what Rack is about and where it fits in our stack. So when a user comes to a website from a browser,
they make a request. That request goes across the internet and gets handled by some sort of web server, typically something like Unicorn or Puma. That web server then has to figure out what to do with that request. And that is where Rack comes into play. Rack is the interface that those web servers talk to to communicate that a web request just happened.
Rack then in turn is able to turn around and pass that request along generally to a web framework of your choice, something like Rails or Sinatra. So Rack is sort of the glue that sits between your web server and your application code. Now this is really cool because this is the principle by which you can swap out your web servers
without changing your application code. You can change Puma to Unicorn and back and forth. You could even run on Webrick. And all of that is fine because everybody talks through this common interface of Rack. But Rack is also available for you to use directly.
There's no reason that you can't leverage what it provides to write your own code against it instead of relying on a framework to take care of that for you. Now why would you wanna do a crazy thing like that? I mean I'm here at RailsConf and I'm telling you, hey, you can do things other than use Rails. But there's a couple of places where I feel like knowledge of Rack really plays in and it's a good fit.
The first is when you need the absolute uttermost speed out of your Ruby code. Because the web server is making one method call into Rack to hand you a web request that just happened, there's nothing else in between. There's no logic, there's no abstractions, there's nothing happening to take time.
So if you have something that you need it to be as fast as possible for Ruby to be handling it, getting down to the Rack layer takes everything else out of the way. The second reason I'd put forward is simplicity. And I gotta put an asterisk on this. This is a certain sort of simplicity.
It makes something simpler. The protocol for how you communicate in Rack, as we'll see in a few minutes, is really basic. It's method calls, arrays, and hashes. Things that you're very familiar with. But you're trading that for other sorts of complexity that then you have to handle yourself. So it's a trade-off. And it might make some things more simple,
might make other things a little harder and we'll talk about where that's true. The other piece that's nice about Rack is like I alluded to, there's a high degree of reuse to some of these components. Because Rack is such a standard part of the Ruby web ecosystem, things that are written to work with one Rack-based application can often work with another application
or often with applications that are written against entirely different frameworks. So that's a nice part that you might be able to use code that you write if you're writing against Rack that if you wrote it as a before filter in your controller, you wouldn't be able to share as easily. All right, so that's a lot of yammering
about what Rack is. Let's take a look at some code. And this is one of my favorite snippets of Ruby, actually pretty much in the world, is this. This is a fully functioning Rack web application. Now you put this conventionally in a config.ru file.
Don't let the .ru fool you at all, that's still just a Ruby file, it stands for Rack up. We define a class called application and in that class we define one method. The entirety of Rack's protocol is a single method. This method is called call and it takes one parameter called env.
It's a hash and we'll look closer at what's in that hash in a little bit. On the response side, Rack's expectation of a call method is that it will return back an array that has three parts. The first value in that array is the status code, the HTTP status code to return back.
And so in this case we're saying 200, everything's all good. The second parameter in this array is a hash of HTTP headers that will be fed back to the client browser. Now I've left this empty in this case. More often you would have something like the content type or at least some basic values
that you would set in it. I've excluded those in a lot of these slides just to keep the amount of text down. But any HTTP header that you need to communicate back to the client, you just put in that hash. And then the last thing in this three part array is an array of the content that you're wanting to send back.
Now this is slightly different than you might expect. You might think, oh I just want to hand a string back, my HTML or my text that I'm sending back across the wire, the JSON. But Rack expects that the content object in the last place is something that will respond to each. And so the array is the easiest way to accomplish that, to give it a thing
that it will be able to enumerate across. And then it takes whatever it gets out of that enumeration and that's what it sends down the wire to clients. So that's it. That's the protocol for how the web server communicates to Rack the request that's coming in
and then gets the response back from that Rack application. Now in config.ru, you've got to get the thing started. And so there is a run method that Rack makes available at that level. And you hand it an instance of a Rack application, an instance that responds to this call method. And now when we go to our terminal, we can say rack up.
That is a executable that's installed by the Rack gem. And it will spit out a little bit of front matter here, tell us about some versions, tell us what port number it's running on. And now it's ready to receive requests. We can get a request to it in the simplest possible way just by going to our browser, going to localhost 9292 and it tells us
that this is good enough. There are other ways of accessing this though. And I like to play with them because some of the later cases that we'll look at are a little easier with some of the other tools. And one of them is cURL. So cURL is a command line tool that's readily available across most Unix-based systems.
And you can, in the most basic setting, say cURL and then the same address that you would have typed into your browser and it will spit back onto your terminal the text that it received. There's all sorts of flags. We're only gonna look at a couple of them. But this will come in useful a little later when we look at things that aren't as easy to just type into our browser.
So we're Rubyists. A big part of Ruby culture is testing. So we have an app here already. Let's see what it would take to get some tests wrapped around that. And fortunately, as you might expect, the Ruby community provides through a gem called racktest. You include this into your gem file
just like any other gem. You would require racktest to then make that available and that pulls in the classes that you're gonna use. In these examples, I'm gonna be showing many tests because that's kind of my flavor for things. This all works perfectly well with RSpec and is super well supported across that.
So a test would look something like this. So we have our application test derives from many test test. The first thing that we do is we include the racktest method. So what this does is makes available a whole bunch of helpers that you can then have access to throughout the rest of your test class. You can actually do things like open up the many test base class and do this for everything
if you know that you're using it everywhere or do it on a point by point basis like we're doing here. One expectation that racktest has of your test class, though, is that it will provide a method called app and that app method will return an instance of your rack application. So this allows us to control what we are actually testing.
The methods and helpers that racktest provides will interact with this app method to figure things out. And as we'll see later, this plays nicely because you can also do things like middleware instantiation or configure this however you want to in returning a valid rack application that you want to test.
The tests then are pretty basic. It gives you methods where you can invoke all of the typical HTTP verbs that you would expect. So in our case, we just wanted to get what was at the root, so we just get slash. Once that's executed, it will run against our rack app and racktest will put the responses from that,
what happened, what it got back, into an object called last response. We'll look a little closer at what this response object is later but we can interrogate it for things like was it a successful status code? What was the content that was in it? What sort of headers? And so you can see how you can get into a nice unit testing cycle here of being able to feed various things in,
feed URLs, make requests against your rack app and then see what it's gonna respond back to you with. All right, so that's all well and good. I'm sure somebody would pay you tons of money to make a web app that just returns a static string but most of us will need to have
some sort of more dynamic interactive thing going on and that if parameter that we looked at is the key to all of the dynamic behavior that you're gonna put into your application. Everything that you need to know about the incoming web request is in that in. As I mentioned, it's a hash
and let's take a look at a little bit of what's in there. There's a lot of values and you can have it print these out or do whatever to be able to dig deeper but some of the important ones that you should know about are that it includes the HTTP request method. So in our case, this is a get. As we referred to, that's when you type something into your browser and just hit go,
that's the method that's gonna get sent there. It gives us a lot of different path information so we can know what got requested and where and then it also wraps up any input that's coming in. So with a get, there's no real input that gets sent along. You're just requesting the URL but as we'll see in a few minutes, there are ways that with a post message
or some of the other HTTP methods that you're expected to actually send data along with the request and that's available here in the end. So this is a modification to our basic app to start digging into the end and do something a little more sophisticated although not that sophisticated yet.
What we do is we look at that path info that was provided there and that gives us sort of the relative path after the domain of what the user has requested and in this case, we look to see if it matches exactly slash bot and if it does, we're returning a 403 which is the HTTP status code for forbidden
and we give them a nice little message to let them know that we've spotted them trying to get somewhere that they're not supposed to. Very, very sophisticated sort of code here. This process of taking a look though at the URL that's being passed in and turning that into what code you're gonna execute is actually a really fundamental piece of web architecture.
In fact, it's called routing and this is one of the things that you get out of every single web framework. In fact, some of them, their claim to fame is how easy they make routing or how conventional they can do those sorts of things. This is really a place where you feel the lack of frameworks
if you just try to go at your own in Rack. You will end up building your own abstractions to keep from having deeply nested if statements which are most of what you're gonna see here. It's not gonna get too deep but you can imagine if you had even 10 routes in your application, it could get a little bit tough to manage without some help.
Rack does provide you a little bit of assistance though. So you're not entirely trapped in a land of nested case statements to get some sort of routing and it does it through a method called map. So in our config.ru, we originally showed that we just called run on that application and that's the only thing
that requests we're gonna be able to come into. Well Rack will also support you providing the leading prefix of a URL and then send those calls to specific app objects. So here we've made another Rack compatible application object called status and this will receive calls
that come to a slash status URL on the app rather than them going to the main application object. So you can imagine that at a modest scale if you had a small number of routes that you were trying to deal with, you could very nicely partition those off into their own separate application classes which is also kind of nice for testing and single responsibility.
And Rack will let you do some basic routing to get the requests that are supposed to go to those apps where they belong. If you've got more than one or two of them, there is also a URL map class where you can essentially hand it a hash of the strings for the prefixes and the instances that you want.
And I don't know, depending on how many of them you have and how you're using it, it can be a little tidier than the map method calls in your config.ru. So the inv is a hash. It has all the information that we could possibly want in it but it's a hash.
Like munging around in hashes, knowing the keys, you can botch the key value and it looks like something's not there, a hand in things that don't exist. It's kind of messy. And so Rack helps us out with that with a class called Rack request. Rack request, you hand it an inv that's coming in and then it provides a lot of helper methods
that give you cleaner access to the things that are expected to be inside of this Rack request. So in this case, we've replaced our lookup in that inv hash for path info in the upper case with a nice method call to path info instead. Now this, if we botched the typing on it and said pat info,
it's gonna give us a no method error rather than just returning us a nil value and behaving in kind of a mysterious way. So I highly recommend using Rack request any time that you're doing more than one or two very basic accesses of things that are in the inv. It really tidies things up.
So looking a little further at this, let's do a little bit more sophisticated things. So if you, rather than having slash bot return us just a static string, let's make it a little bit more like a Rails show route where you can say bot slash an ID that you're interested in and it will still deny you but at least it'll tell you what thing
you were trying to get at. Now this is a little ugly and like I said, routing is one of those areas where frameworks help. There's actually Journey and Musterman are both gems that are independent gems that Rails and Sinatra use for doing routing. So you could mix those in yourself.
In this case we're using a regular expression to match against the route that we're running. The %r from here with the curly braces is really nice when you're doing a regex that wants to match forward slashes because forward slashes, then you don't have to like backslash forward slash to get them as literals into it.
And then we have parentheses around that backslash D plus and that grabs as a capture the ID that we passed in. And the dollar one on the lower line below it pulls out the value that was matched when that regex went. Now there are lots of ways that this could be cleaner and tidier. This is the most concise way to fit it on the slide.
So don't take this as best practice but as kind of illustrative of where you could go with parsing up your URLs and taking out the information that you want. So isn't there an easier way? Like I said, this is where you really win big with frameworks. I mean, Sinatra's DSL for anybody who's used it
where you just say get and then give it the string and you can put parameters in it just with colons on the names. Like they do so much to help you out here. So this is a place that you might want to look for that help. If we wanted to transform this into a little bit more of a real application though, once we've done that match,
rather than just returning a string value, we can do whatever sort of code we want inside that. So here we have some mythical database class that goes and looks up by ID the things that we have in a store. It returns back that bot and as an object and then we just 2s that in our output.
So you can imagine if this database was storing things as JSON structures that this would be a way that you could have just sort of a typical restful API talking back and forth. Like there's no deep plumbing. You don't need anything here apart from the database class to be able to look up the data that you want to return back.
So as we've seen before, curl comes in handy for doing this and if we curl at bot slash one, look up in our database, there we have a funky little ASCII robot with the ID one on it as the response that it hands back.
This is an HTTP get like we had mentioned. So it's not expected to have any parameters really except for the URL and the query string that's provided there. You can send headers but we're not reading any of those. But we want to make this a little bit more full featured. Like we have a database that we're reading out of. We want to let people write into it. And for that, the HTTP method that you should use is post.
Post allows us to send data along with. So we'll adapt our call method a little further and don't worry, this is the most that this method is going to grow and you can see where the pain points are here in the routing that we're talking about. We had our match that we've seen before
so as long as we're in the bot and now we have a branch in here. And this branch says if the request is a get method which is provided for us by that rack request, then we would do the stuff that we were already doing before of looking it up. But if the request is a post,
then what we need to do is we go to that request and we read the body that comes in. So this is the data that the client is sending to us. Now in a lot of web applications, this would be something that would be coming from a web form that somebody had entered. But it could also be from an API client calling it directly or as we'll see in a moment,
there's easy ways to make curl post data to a URL rather than just get from it. Receiving a post, like we said, we would like this to write into our database. So having matched the ID and having read the content in, we can do whatever we need to with that and return a response to the client indicating that we were successful
in saving the record that they sent to us. So this is like the basic shell of a RESTful API here in 10 lines of code, excluding the database or whatever you bring in to do that. It's pretty straightforward. The things that you get from your frameworks
make this a little cleaner and make this tidier, but these are all the moving parts that are really necessary to get this job done. Taking a look at how this works at the terminal, if you say curl with a minus capital X, then you can provide it an HTTP method other than get, which is what it will default to.
We give it the full URL with the ID of the thing that we're wanting and the minus minus data then allows you to send the data along that you want to actually post in. It gives us back the message that we wrote and if we then turn back around and do a get against that same URL, we receive back the data that we had sent in.
So we have the full life cycle of posting and reading. Unsurprisingly, given that RAC has a request class, RAC also has a response class, which helps you in building up the valid responses.
It's pretty useful and it fills a couple of gaps in that format. I mean, for one, it's pretty strict for you to need to make exactly those three elements and make sure that the content's the way that it's supposed to. It also, RAC response also allows you to kind of have a little bit more of a flow in how you're building things up. Rather than making that array right at the point
when you need to return it, it gives you an object to tally up the information into and then at the time that you're finished, ask it to write it out to the wire. So we interact with RAC response by instantiating a new one. It doesn't take any parameters to start it up necessarily. And then we can set various things on this response.
It's sort of a stateful builder type of pattern. So one of them is write. You can write to it and that will write to the body. And you can do that as many times as you want. You can continue to append things. You can imagine if you were doing this with an HTML based thing, maybe you read something from a header file and write that in and then you write some other piece of dynamic content
and then you write a footer. You can progressively build up that response how you want to. And then when you're done, you call response.finish and it generates a valid RAC response to be handed back across the wire. If we pried in at that point and took a look at the response finish,
what it returns back to us, like we've experienced before, is that three part array. Status code, headers, and then the body. But two of them look a little different. And this is part of why you want to use RAC response. One of them is that it's appended a content length based on the things that we wrote in. Now web browsers will act okay.
Things don't break dramatically if you don't provide this. But it is in the HTTP specs and it is better for you to provide that information if you want to make sure that you're compatible with all callers. Additionally, that content, that last thing that we had been passing as an array with the strings in it, RAC has wrapped up in an object.
And this object actually takes care of some more complicated scenarios when things are nested and there's certain closing behaviors on the response stream that it will take care of for you. So you don't need to know about those things if you use RAC response. So at this point we have a valid app
and it returns data and we can interact with it, make our requests, get our responses. But there's another major component of how RAC works and that is middleware. And this is one of the most powerful patterns that this brings to play. And one of the things that applies the most when you're in other frameworks. So back in our config.ru where we had our run statement
for our application, you can use a method that's provided there called use and install a middleware. And installing the middleware, they get installed in the sequence that gets called so we could have done multiple installations there and said use this middleware then use this one then use this one. And what that forms is that forms a call chain
that's going to get flowed through. So the first request that comes from the web server will hit the first middleware that you said use in the config.ru then hit the next one then hit the next one and eventually most of the time gets down to your app and then the response goes back up through that chain. Those middlewares take something shaped like this.
So they have to have an initialize. Initialize is expected to take an app that is the next thing in the chain the middleware's gonna call. And you have to save that away so that you can make a call against it later. So in this form, this middleware doesn't actually do anything useful. All it does is takes the request and hands it along. But you can do your own work
before and after that call on the app. You can munch the environment. You can deal with the response and change what's there. You can control what's going in and out. So here's an example of a very basic sort of key API key validation as a middleware. We instantiate a request object to read it.
We get the HTTPX API key header which is a pretty standard value for passing an API key along. And if the key matches some predetermined string that we've chosen, I chose beep, then we'll go ahead and let the call through. They knew the key. Everything's fine. If they don't,
then we will immediately return from this middleware. That request will never make it to the application object itself to be handled. So in diagram form, we come in, we get to the middleware, and the middleware says I'm responsible for this, returns, and nobody else further down the chain gets a chance to get involved with that.
So middleware are very powerful for allowing you to apply these sorts of cross-cutting concerns, whether it's logging or authentication. Things where all of your endpoints across any portion of your app need to have the same behavior fit very well. And Rails actually is built on a ton of middleware.
This is a huge pattern that's applied there for a lot of cross-cutting concerns. So if we look at this, once we've installed our authentication, we can curl against that. We'll get our forbidden message. If we looked at the status code, it would tell us a 403. If we curl with a minus H, minus capital H,
we can give it headers in the HTTP format that they expect the key name, colon, and then the value. And once we pass a valid API key, that request then is allowed to go through. So RAC itself comes with a number of middlewares that you can use. There are lots of them around.
One of them is RAC static, so if you need to serve static files out of a RAC application, it allows for you to declaratively set that up. It has some basic session support, both with backing stores on your server and with cookies that you can install. This actually often gets used with Sinatra if you want to have sessions because it's a middleware that can get installed.
It has debugging help, things that will show you a nice exception page when you're in development, things that do code reloading that you can optionally install. A lot of the niceties that you have in Rails are available as middlewares with RAC itself. And that brings us to the last little bit,
which is to talk about where RAC intersects with all of the other frameworks. So we mentioned early on that Rails and Sinatra and all of these things are built on top of it, but what does that really mean? For Rails, your Rails application is a RAC app. There is something in Rails that has a call method that takes an in, and when those requests come in,
that's getting dispatched to your controllers and your routing and your views and all of those other things, but all of that is downstream of a call method that you don't have to write because Rails does it for you. That's not the only place where Rails touches RAC though. You can actually embed RAC applications into the routing inside of a Rails application.
So here in our routes file by using the mount command, you can hand it a RAC app instance and then give it the URL where it should delegate to that RAC app. And any request that gets there will get sent on to that RAC application. Similarly, Rails allows for using middleware.
There's a use method, so in your application config, you can just use a middleware just like you did in our config.ru, but it also provides these insert before and insert after. So if you have some concern about the sequencing of your middlewares, you can control that from in there. Now, you can't do that from RAC itself,
and so how is Rails accomplishing this? Well, it turns out that Rails actually has its own internal middleware stack. And so when you config use those in the Rails level, it's actually going into that middleware stack. You can install middlewares at the config.ru at the RAC level just like you would,
but you won't see those when you do things like RAC middlewares and ask Rails to show you all of the things that it has installed. So that's a fun little tripping point if you're ever looking around for how things are plugged in. Sinatra as well, just like Rails, is just a RAC app. At the end of the day, when you call Sinatra base
and you derive your thing from it, it's just a RAC application. And in fact, although you almost always use helpers and call render or hand back strings and do all the nice things that Sinatra lets you do, you can always fall back to handing back a valid RAC response. And Sinatra knows what to do with it and just hands it on back because it is just a RAC app.
So that's a quick tour through RAC and where it fits. We've looked at how you would build a basic application, what the moving parts are that are there in the box. We've looked at the request and response lifecycle and what plays into that.
We've looked at middleware and how you can use those to compose an app together and layer things in your RAC applications. And we've looked at how this plugs into the various frameworks. Now, I really just touched on the surface of this and haven't given a lot of really concrete details, but I did a course for Pluralsight. So if this is something that is of interest to you,
I actually have a bunch of tokens that people can get a free month's worth of time on Pluralsight and that screencast fills in a lot more detail. It goes into lots more of what's in the box with RAC and a much more realistic example of building a JSON-based API with it.
So hopefully you've all found this useful and I can't see how much time we have left if there's any time for questions. All right, thank you very much.