00:00:12.259
thank you so my name is Andrew cantino
00:00:19.800
um I work for a company called mavenlink we build a project management software and financial management software for
00:00:26.340
consultancies we're based in San Francisco and here I'm I'm here today to introduce
00:00:31.920
you guys to brain stem which is a API presentation library that we've been working on off and on for about a year
00:00:37.800
and we actually just released it as of I don't know about five minutes ago it's public on GitHub
00:00:44.399
um so yeah I'm excited to tell you guys about it so
00:00:50.280
you know so mavenlink has a really complicated data model we've for example we have projects which have tasks which
00:00:57.360
have budgets and those budgets reflected in time entries which belong to timesheets which are in reports
00:01:03.899
Etc it's a very relational product um and it's a very complex data model
00:01:09.900
but it needs to be because ultimately we're trying to build something that models business relationships in human
00:01:15.960
relationships and those are super complicated and as much as we try to dumb it down it just there's only so far you can
00:01:21.840
simplify it and we need our API to express these same relationships in a meaningful way
00:01:27.119
in a consistent way and that's how sort of brainstem evolved
00:01:33.119
um as I mentioned we started brainstem about a year ago and have worked on it sort of off and on through that time and
00:01:40.259
it was an extraction that we pulled out of our product and we've been using it for a while now and actually at this point it's the library that powers both
00:01:47.040
our internal and external apis and it's released
00:01:53.220
so I guess I wanted to start by saying what do you want in an API for your product and maybe more generally I just want to
00:02:00.240
say you know you want an API um you know you want an API for your users
00:02:08.399
so that they can get their data out of the product they can get new data into it they can transform it in meaningful ways ultimately you're building the
00:02:14.940
system for them and you need to make it easy for them to get the data in and out and that's probably pretty obvious to
00:02:21.120
you guys but sometimes it needs to be said um you also want to API for your users
00:02:26.879
users so these are people who are trying to treat your system as a platform in some
00:02:32.040
way or trying to build products on top of it and you know we hear a lot about ecosystems and it's a little
00:02:37.860
you know over spoken about too much maybe but they ultimately they are something you want to support both
00:02:44.280
because it helps your users if there's value if value has been added to your product by other people and it helps
00:02:49.379
your business too it makes your product harder to get rid of and more into people's workflow et
00:02:54.480
cetera and finally and I think maybe most importantly you want the API for
00:03:00.120
yourselves so you want to build a unified platform that you can build on top of so as your
00:03:05.940
company grows you you know new feature development can be on top of your own API and ideally it's the same API that
00:03:12.360
you both expose to your external users and use internally and that way you've really had experience with it you've
00:03:17.640
hardened it you've used it in lots of ways and you really can make strong statements about it and a mavenlink at this point where most
00:03:24.120
new feature development is on top of our public API which lets us make some really nice strong statements like
00:03:29.640
anything our mobile app can do you could do with our API because it's the same API
00:03:34.980
um and I think that's a nice statement to be able to say so I think it's you know should be
00:03:40.739
evident that you want some sort of API for your product ideally one that you can also build on top of what else do you want in that API
00:03:47.280
well I'd claim you want a consistent API which you know should be fairly obvious but
00:03:52.739
it should be consistent in various ways so things like simple things like dates going in and out I'd always be the same
00:03:58.500
format be that like ISO 8601 or Unix epochs but just pick something and stick
00:04:04.500
to it um you want IDs to be in a consistent format be those numbers or strings of
00:04:10.920
numbers or Shaws and you know other things like routes should be predictable and then the
00:04:18.239
response structure of the API itself should you know be standardized across your endpoints and be somewhat guessable
00:04:24.419
and somewhat predictable and you know for brainstem we use Json but if you're a terrible person you
00:04:30.479
could use XML I don't know why you would want to and you also want a versioned API
00:04:38.220
so upgrading apis is always a pain in the ass like I don't think that's hard to avoid both for you and for the people
00:04:45.240
consuming your API as well but like quick show of hands how many people have had an API change under you
00:04:51.000
without a version bump yeah like about a third of you
00:04:57.120
um and what about on the other side have you ever done that to someone yeah
00:05:03.320
so you know even with versioning dealing with changes in AP in an API is really
00:05:08.820
hard but versioning certainly helps and it's more or less a prerequisite and finally you you want a fast API
00:05:16.199
and what is a fast API well I claim that at least in rails of fast
00:05:21.900
API is generally fairly close to the database doing as few queries as possible and
00:05:27.300
ideally working with some of the same Scopes that you used in your models already and I'm just going to assume that you're
00:05:32.880
using something with active model made probably active record but at least something built on top of active model
00:05:39.259
along the same lines you want an API where loading associations can be done quickly and in the same request
00:05:46.020
so side loading is the idea of you know if I'm trying to get say a project and I
00:05:51.720
also want to get all the posts in that project or the participants in that project and I want to be able to do that in one request and sort of ask for that
00:05:57.900
in a consistent way um it's much it's akin to an active record if you're loading posts and their
00:06:04.560
replies you'd want to do an include statement so you so that you don't do n plus one queries
00:06:09.960
it's the API equivalent of that um you also want to avoid object
00:06:15.840
repetition so in that same example if you're loading posts and let's say they're posters which are users you
00:06:22.319
wouldn't want that full user object to be repeated for every single one of those posts in the Json response ideally you reference it by ID in some way so
00:06:29.580
that it's just so they have a smaller response and something like gzip might help you
00:06:35.580
know ideally a compression algorithm takes care of a lot of that for you but the reality is you still need to expand
00:06:40.680
that in a client so if it's a browser for example it still needs to uncompress that possibly large Json response and it
00:06:47.340
still has to parse that as an uncompressed response which can be quite large at least for older browsers quite slow
00:06:54.360
um and finally on this slide you want to allow expressive filtering and sorting in your API which again is the same goal
00:07:01.620
of getting small responses that are exactly what the user wants so you want to allow the user to tell you exactly
00:07:07.020
what data they need and only send that back so
00:07:12.960
I guess what I just talked about is sort of our motivation for building brainstem at the time that we started it we didn't
00:07:18.240
really feel like there was anything else out there that met our needs and that landscape has changed a little bit over
00:07:23.460
the last year but then I'll talk about that more later in the talk um but let me show you guys a motivating
00:07:30.479
example of um sort of from our mobile app we want to express some fairly
00:07:36.660
complicated relational data so this I mean you would think a mobile app wouldn't be that complicated and this is
00:07:41.940
just a post it's a private message between three people I'm posting saying hey guys I'm working
00:07:46.979
on my slides and there's an attachment which is a copy of the keynote file and then it's tied to a task called make
00:07:53.400
presentation and then Jeff replied saying looks like a great start and so that's a reply object
00:07:59.400
and so I want to display all of this data in a consistent way and I want to get in one request and I
00:08:05.880
really want this post object which is sort of the whole view that you're seeing here is a single post and I want its Associated data as well
00:08:13.560
um so let's look at what that data is and I sort of just said that but we have the project that the post lives in and we at least need its title we need the
00:08:20.580
post recipients at least their names the post itself with the text the attachment with the size and possibly an icon and
00:08:28.020
the name uh the task and at least the task name and then anything similar data about the
00:08:34.440
replies and there could be more than one and then serializing this relational data is tricky so let's look at a couple
00:08:40.979
ways that we could do this the I'm going to argue somewhat naive way but also probably the easiest
00:08:47.700
is to just write it out in a Json structure that has everything you need and nothing you don't so here's all the
00:08:53.820
data that was on that slide in a fairly usable structure coming over you know adjacent request
00:09:00.240
and that's great but what if I want other information too so what if there's some new attribute added
00:09:06.480
and then I need to add it to the Json and that's fine I mean it's easy to make this changes but it kind of sucks if
00:09:11.519
that's used in multiple places do I have to change my underlying API and more generally and to that point
00:09:18.480
like if I'm using this in lots of places then it has to be customized and have the superset of all those different fields that all these different places
00:09:24.660
need and what if I'm interested in lots of posts at the same time now there's gonna
00:09:30.300
be a lot of repetition because that project title there's lots of posts in the same project so that title is going to be repeated the user information and
00:09:37.560
obviously we probably need more than I was loading is going to get repeated for all the posts and the recipients Etc
00:09:42.959
and I think the most important point is what happened to my awesome relational model you know that I built so that I could
00:09:49.320
represent this data in a consistent way you know I use rails for a reason I use active record for a reason and at least
00:09:55.200
in our app it's super relational we use a relational database and that's exactly what we need and we've lost that behavior
00:10:01.920
so let's look at another option in this option we reference everything by Hades and this obviously is a subset
00:10:08.100
of the Json so recipient IDs attachment IDs Etc and we obviously we can flesh this out
00:10:15.060
so this is a post that was the post you saw it was id25 and then it had one reply id9 so let's add that
00:10:22.860
the reply is also just a post it's you know it's a dissociation between a post and a post so it gets
00:10:28.080
added to the same top level hash Etc and then of course you have all the other objects that we saw
00:10:33.959
and and this is by the way is an example of side loading here ideally we did a
00:10:39.300
single request asking for the Post told it what associations we wanted and they all came back
00:10:45.180
um now how should we feel about this it is I think you agree it's a longer at least in this example there's a lot more
00:10:51.060
top level objects potentially we're returning more data but I claim it's far more reusable
00:10:57.600
I'd also claim that it's much more consistent because you can predict what these objects are going to look like you'd like you know what their fields
00:11:03.060
are going to be et cetera there's no like project underscore title anymore you just have a project Association you look for its title
00:11:09.540
and if you return a lot of data I don't even think it's going to be longer because it's going to take advantage of
00:11:14.700
the fact that a lot of these IDs overlap and again more importantly we got our
00:11:20.399
awesome relational model back which is what I wanted so
00:11:27.480
um now I'd like to dive a little deeper into how you would generate a Json response like that and that's what brainstem will help you do
00:11:35.339
um and in brainstem you know you actually can get all that in one request you'd make a response in this case I don't know if people in the back of the
00:11:40.980
room could see it but you're just making a response making a request to the posts API endpoint for id25 and you're asking
00:11:48.180
it to include the project user recipients task attachments replies
00:11:53.339
and you could obviously set a default for that if that's the view that you think most users are going to want so that relational structure that you
00:12:00.779
guys saw was serialized from active record objects using brainstorm presenters
00:12:06.060
so what's a presenter a presenter takes an object and in this case an active record object
00:12:12.720
and a presenter itself is a class or method that serializes that object and outputs the fields that you ultimately
00:12:18.480
want to send over the wire so in our case Json but you could use something worse
00:12:25.079
so let's look at an example presenter so this is a brainstem presenter it
00:12:31.200
inherits from brainstem presenter it's versioned you might notice that the module whoa
00:12:39.060
you might notice that the module is version V1 and if you change that it would actually
00:12:45.120
change the version of this presenter you'd find that in a different scope inside a brainstem so here we're presenting post and it
00:12:51.540
just has one method called present which takes a post and returns a ruby structure of the data that you wanted
00:12:56.880
simple um now I want to show you how you would
00:13:02.399
add associations to that because that's where it gets interesting so using the association keyword you
00:13:07.500
just list the associations on the model that you want to expose to your end users so anything you list here they're going to be able to request and
00:13:14.040
obviously you also need a presenter for any of those objects and these will get serialized as you saw earlier respectively as like reply IDs
00:13:21.959
task ID attachment IDs user ID Etc and the recipients is an interesting
00:13:27.600
case because brainstem would infer that these are recipient objects but in reality they're user objects so you need
00:13:33.720
to tell it what key to use and as I mentioned you'd need to build
00:13:39.060
presenters for any other object so here's a user presenter which looks very similar and the user the one thing we've
00:13:44.399
declared is you could ask you could ask for posts by default you won't get associations back because they could be
00:13:49.500
huge but this is the things the user could request so let me now show you real quick how
00:13:56.339
you would use that from a rails controller so here I have an API V1 post controller
00:14:02.160
which is just inheriting from application controller but there's no reason you couldn't and you probably should inherit from API controller and
00:14:09.180
put all your authentication in there in any other shared behaviors like overriding what it means to have a 404
00:14:14.519
Etc the only key thing is you have to mix in brain stem controller methods and that
00:14:20.279
gives you the present method which takes the name of the posts it's actually the table name here of posts but it could
00:14:26.399
also take an object itself and you give it a scope in the block which is the scope from which all
00:14:31.440
further brainstem modifications are going to take place so brainstem works on aeroscopes that's the only thing it understands so you stay close to the
00:14:38.639
database so here in this example I'm just giving a post unscoped with no restrictions well there's no reason you
00:14:43.740
couldn't give it posts relevant to the API or posts visible to create user Etc that's where you have to deal with your
00:14:49.920
authentication your authorization and then by doing this for free you get
00:14:56.040
the inclusions that I showed you a minute ago you also get only queries so you can make a request to post Json only
00:15:01.860
five eight twenty five and you'll only get things with that ID back and you get pagination
00:15:08.579
and then and this is an index action but this works on all the other credit actions as well
00:15:13.620
and then we also get filters and sorts so filters allow the end user to control
00:15:18.779
exactly which data they get and sorts allow them to configure the order of that data
00:15:26.579
so here's a quick example of sorting we're back in a presenter again and this
00:15:31.620
is actually kind of a silly example because we're just sorting on we're declaring that two columns are sortable updated out and created at and in this
00:15:37.920
case they're just the exact same name it's those column names in the database but the sort order method can take a
00:15:43.620
Lambda and you could do anything you want inside that as long as you're returning a scope at the end and then you can also declare a default
00:15:49.560
sort order and then the user if they wanted you to return a sword that's not one of the default or not they the default sort
00:15:56.459
they just tell you the order they want it in and then this will honor that
00:16:03.199
now probably more interestingly on filtering here's again in the presenter here's a
00:16:09.899
filter this is a filter on task ID so we're in posts and this allows the user to ask for only posts associated with a
00:16:16.260
certain task so here what happens with a filter is it
00:16:21.660
takes us takes a Lambda and is given a scope and returns a scope and then you can do anything you want inside there to
00:16:27.420
restrict the data so here we're just given the user is sending us task ID as a get parameter
00:16:34.019
and we're just passing that right in and SQL escaping is obviously up to you we try we try to help but you need to think
00:16:40.440
about what's going into your database you can also defer to Scopes defined on
00:16:46.079
the underlying class on the active record model so here popular is a scope defined on the post model which takes
00:16:54.779
one argument which is true false and then you can just defer to that so if you have other Scopes you've already used all over your product and are well
00:17:00.899
tested you can just defer to those just obviously make sure that you're basically whitelisting here you're declaring Scopes that you're willing to
00:17:07.260
expose to end users um now Scopes can also or filters can
00:17:14.760
also have defaults which is useful when you have negative Scopes or you want a scope to always be included here this is
00:17:20.819
a filter that says include private posts the default is true which means this filter always runs so the user doesn't
00:17:26.220
have to ask for it unless they don't want private posts um it's also handy if you want a scope
00:17:31.919
to always like whatever that code is to execute on every request
00:17:37.679
so I've shown you how to make a simple API in brainstem and there's obviously a lot more to it but we have exposed filters
00:17:44.760
and sorts I've shown you how to do include queries how to make a basic controller that would respond with your
00:17:50.100
data that's been presented um and now I'd like to show you
00:17:55.380
potentially how to deal with it on the client side which I think is fitting for this conference given how many talks there
00:18:01.140
have been about sort of client and server apis and I didn't know that going in but I think we're all sort of solving the same problems at the same time
00:18:09.240
um this is probably not something you would give to your end users although you certainly could and there's no reason
00:18:14.580
they couldn't use it if you set things up that way but I'm encouraging you to develop on top of your own public API
00:18:22.140
and so this is what we use when we're developing our views and we use backbone
00:18:28.500
um and you know you have this API you've built it for your end users you should use it for yourselves as well you should
00:18:33.539
eat your own dog food and live on your own platform so because we use uh backbone we wanted
00:18:40.020
to combine brain stem and backbone which gave us brainstem.js which is a adapter shim for backbone to
00:18:48.539
let it do relational model loading over brainstem so it's a little bit like Ember data in
00:18:53.700
that it preserves these relational models over the wire and it's I'm not aware of anything else well that's not
00:18:59.039
true there is a relational library for backbone but we looked at it and it didn't handle the relations in the way
00:19:05.039
we wanted for The Way We Were transmitting these Over The Wire um and in addition it would have no idea
00:19:10.260
how to talk to a brainstem API so I'm just going to give you guys a really quick example in coffeescript on
00:19:15.360
how you would consume um your brain stem data in your in your
00:19:20.820
view and as I mentioned this is actually how we're developing most of our new code is against this an API and using
00:19:26.520
brainstem.js so the first thing you do is you make a storage manager and the storage manager
00:19:32.520
is in charge of keeping track of the different models and collections that can come over the wire and keeping track of how they talk to each other
00:19:39.000
and it's at the moment as a global Singleton expected to be found in base data but we're working on refactoring it
00:19:44.880
so that you could have more than one although it that hasn't really bitten us yet because ultimately you usually want to share this across different views
00:19:51.780
the storage manager is also an identity map which means it keeps track of the mappings between object types and their
00:19:56.880
IDs it makes it easy to quickly look up things by ID and more importantly to not
00:20:02.340
re-request things that it already has so the you know in the beginning we built this for our mobile app and we wanted to
00:20:07.860
be sure that the requests that went over the wire were small and quick and we didn't want to re-request things the
00:20:13.500
user already had so that was sort of part of it that was part of the design principles that went into this
00:20:19.380
so in this case in this example we have a storage manager we're telling it about posts projects and users and which
00:20:24.900
backbone collections to find those things in and then I'm going to show you how to use the storage manager and there's kind
00:20:31.440
of a lot here or I'm sorry this is actually just a post so real quick this is how you declare the associations
00:20:38.760
so you use in copyscript the at sign means clot in this context means a class
00:20:44.760
method and this is actually class data so you declare associations on the post
00:20:50.160
or on the model then you extend your model from brainstem model which itself is just a light extension on top of
00:20:56.160
backbone model so here are in our post model and obviously there'd be a lot more methods that we'd probably want to actually use
00:21:02.280
this but we have projects we have a project which is findable in the projects
00:21:08.100
collection we have many replies which are actually posts we have a user in the users collection recipients also in the
00:21:15.120
user's collection Etc and the syntax here is if you have just a literal string it means up has one or
00:21:21.240
belongs to and the array means has many and from that brainstem can the
00:21:26.400
brainstem JS can figure out where to look for things so and then let me show you how you
00:21:32.100
actually load this and here's my example which has a lot going on but if we just focus on the collection load
00:21:38.039
all we're doing is we're tailing the storage manager to load some posts it's going to be one page of posts using the
00:21:43.380
default pagination because we haven't said otherwise and you wanted to include the project user recipients attachments Etc
00:21:49.799
and this is otherwise just going to end up as pretty standard backbone where you get a collection object it won't have
00:21:56.039
any data in it yet unless this is already in the storage manager so it'll either be loaded right away if we have the data or it'll be async and you have
00:22:02.700
to wait for the reset we also add an event called loaded which you can bind to directly and happens late which is
00:22:08.159
usually what you want alternatively you can give this a success callback or just change success callbacks
00:22:15.380
the rest of the code here is just mostly boiler put boilerplate to deal with this we bind to the collection we've reset
00:22:22.080
and remove at all is it actually on the slide but it just renders all the posts on the page
00:22:27.299
and then when we render if the collection is already loaded which would likely be because we've refreshed we
00:22:32.340
already have had this page in the workflow already you just render everything otherwise you know show a spinner say just a moment Etc while the
00:22:39.480
data is coming over the wire the goal of the storage manager here is to tell you when all the data you need
00:22:45.299
is ready so you declare to the storage manager everything you're going to need I need these posts and I need these associations and when it says the data
00:22:52.200
is loaded you can just trust that it's there and you don't need to worry about where it got it maybe half of that came over the wire and half was already in
00:22:58.260
memory it'll take care of that so the storage manager of course can also load single models here we're
00:23:04.799
loading users a user with user ID and including its posts and you can also of
00:23:10.140
course run filters sorts anything else that you can do at a brainstem API
00:23:15.299
so obviously you don't have to use backbone and many of you probably don't but you might as well if you're going to use brain stem and you use backbone you
00:23:21.720
might as well play with this otherwise there's no reason you couldn't consume the brainstem API over some other format
00:23:27.120
and hopefully people will contribute other libraries for it or you could just use
00:23:32.280
it directly on the Json so to quickly rehash
00:23:37.740
brainstem JS extends backbone with relational models and it ensures that any associations you
00:23:44.820
need are available in identity map by the time it tells you that it's ready
00:23:51.000
um and then let me show you how you'd actually use these relational models so it looks just like backbone the post get user get name would be get
00:23:58.500
the name of the user on the post and under the covers What's Happening Here is the storage manager is
00:24:04.020
inspecting the post looking at the user ID going to the user's collection grabbing the appropriate user and then changing
00:24:10.200
on from there so it's just a lightweight wrapper with a super call or around the basic
00:24:15.659
backbone Behavior you can also also do that with has menus as we're doing with replies here
00:24:24.780
so you know brainstem evolved over about a year as I said and we went through a couple different iterations of it so I
00:24:30.720
just wanted to touch upon a couple design decisions we encountered and sort of challenges that I think you guys would find interesting you might find
00:24:37.260
this useful for stuff you're building or just humor me
00:24:42.480
um so let's see the first one is that we use IDs as keys
00:24:49.200
so many apis return arrays and we made the conscious decision to return hashes
00:24:54.840
instead so as you see here this is the posts and the IDS are actually strings
00:25:01.500
the keys are strings of the IDS now the keys have to be strings because keys and Json are strings it would be
00:25:08.159
kind of nice to be able to use numbers but that's not how Json works and it actually turned out to not be a bad thing because it means it's really easy
00:25:14.640
to change how you treat IDs you could turn these into Shaws and no one's gonna be making the assumption that everything's gonna be an integer plus
00:25:20.340
maybe it's huge maybe you're overflowing JavaScript so I think that ended up working well
00:25:27.240
um Additionally the one reason we did this is because when you're traversing the structure that comes back following
00:25:32.580
associations it just doesn't make sense to be iterating over arrays searching for IDs like most apis return with
00:25:38.940
arrays of things and you have to search them and we found we were also doing that and that just felt a little silly and we don't want to encourage that
00:25:44.940
behavior because you should be order one instead of order n on something you're doing repeatably additionally we just want users to treat
00:25:51.779
this as a lookup table this API response is structured like a lookup table it's almost like a database slice and we just
00:25:56.820
want to structure it that way to encourage that behavior but um one question that obviously would
00:26:03.900
fall out of this is fine so it's a hash how do you handle sorting because you certainly shouldn't trust sorting on
00:26:09.059
hashes and I know Ruby one nine has ordered hashes but I'm not sure that's a good idea
00:26:14.159
so that brings us to the results array which has a couple properties it's just a list of the matching keys and IDs that
00:26:22.080
match the user's exact response because it's quite possible that you're in this case posts your post hash could be a lot
00:26:28.679
larger than a response set because posts can have replies which are posts so you have a poly well you sort of you can
00:26:34.679
have polymorphic associations and here you just have same object the same object associations
00:26:39.840
so you what you do when you actually want to look at the result set is you just Loop over the results looking up each one in its base object
00:26:46.559
and that's all there is to it and you know if you use brain or back brainstem JS it'll do it for you but it's also not
00:26:52.440
very hard as you can see we've turned all IDs into Strings globally so that things are consistent you don't have to think about
00:26:58.380
it um it also means the results themselves can be polymorphic you could come back
00:27:04.260
with if it were for search results you could come back with users and assets and stories or whatever else
00:27:09.480
because they're they have a type effectively so
00:27:16.620
I think I basically just said this allows you to declare exactly what results match the order and sort
00:27:21.720
explicitly and it allows you to do sort of mixed type responses
00:27:28.500
um and then another interesting decision we made is how we that we put filters in
00:27:34.380
the presenters so usually presenters are just in charge of turning data or taking an object and presenting it getting it
00:27:39.840
ready to be sent over the wire and what we actually end up declaring the valid sorts and filters in them as well and
00:27:45.299
probably more things in the future and most other libraries don't either don't handle filters and sorts or they
00:27:51.299
let you they just leave them up to you to handle on your rails controller by changing scopes
00:27:57.720
um and we wanted to head in a different direction and the reason we did that was is twofold one is if we're if we're
00:28:03.779
versioning the presenters it kind of makes sense to version these other behaviors at the same time and it makes it easy to upgrade you just
00:28:10.200
you know use subclass or duplicate possibly the code in the presenter um and you can that's a good time to
00:28:16.559
change how filters and sorts work in their defaults um that's that and then also
00:28:22.500
it's nice for brainstem to know when looking at an object how it can be filtered and sorted without having to
00:28:28.799
infer that from like your controller and the reason we want to do that is because down and this isn't done yet but down
00:28:34.200
the down the line we want to allow you to do full recursive loading of objects so this is something that the Facebook
00:28:39.840
API does LinkedIn does to some extent it'd be really nice to be able to declare say I want this project and I
00:28:45.900
want posts that match this filter and from those posts I want users to match this filter et cetera just be very expressive and really the only way to do
00:28:52.620
that is to know that is for the brainstem to be able to look up filters easily by object type
00:28:57.659
so this is the direction we want to head and it's you know we think it's a valuable addition to the library because it's not something you'd want to build
00:29:03.539
yourself you know so it's a good thing for it to be boiled into the library for people who want it and obviously you
00:29:08.940
want to be careful because your users could ask for huge cross-sections of data but on the other hand if they need
00:29:14.520
that data and it's their data you'd rather them get it in one request and they'll tell you exactly what they need instead of hammering your database or
00:29:20.520
your system with lots of requests now speaking of other libraries I just want to talk briefly about some of the
00:29:26.700
other libraries that have started to show up this year explicitly active model serializers I think is great
00:29:33.899
um it I'd say it's more mature than brain stem in terms of its DSL for specifying fields we declare a ruby
00:29:40.559
structure and active model serializers has a more explicit DSL which probably allows for better introspection and
00:29:46.919
maybe in the direction that we'll head however it doesn't do filtering or sorting or pagination because it's just
00:29:52.679
in charge it cares only about the presentation and we care about also adding a bunch of API behaviors so you
00:29:58.500
don't have to worry about them so basically what we add on top of that is
00:30:04.039
everything you'd want in the API and I think there is definitely some
00:30:09.059
collaboration here there these I don't know if these can be combined if just we could share ideas but both of these have
00:30:14.700
sort of evolved independently over the last year um it's also worth mentioning as I did
00:30:20.039
earlier Ember data which I think is fantastic and Amber is very cool but you know we've built most of our site on
00:30:25.740
backbone I personally like backbone for its sort of I find it's very readable it's very easy to understand the whole
00:30:30.779
code base et cetera number is much bigger um and brainstem.js in a lot of ways add
00:30:36.840
some of the behavior from Ember data to Backbone so it might be possible these brainstem.js without brains without
00:30:42.480
brain stem if you just want relational models we haven't played teasing that apart yet
00:30:47.760
and again I think there there could be some interesting uh collaboration between these two libraries
00:30:53.340
so to summarize um brainstem is a presenter library for
00:30:58.679
serializing your models it's also an API abstraction layer for
00:31:04.500
building powerful apis and it has an optional adapter for backbone if you want to use it which is
00:31:11.940
what we ended up using a lot of and if you use brain stem then it should be easy to make your API user sortable
00:31:18.720
filterable with side loading of associations which we think means shorter response times fewer requests and hopefully
00:31:26.340
happier Developers so we've launched it uh a few minutes
00:31:33.480
ago you should check it out and uh these slides are online you should follow me
00:31:39.539
on Twitter and send me any questions you have I'm tectonic on Twitter or you can ask me after the talk or I think we have
00:31:44.880
some time now so do you guys have any questions