RubyConf 2022

Boutique machine generated gems

What if writing boilerplate for Ruby gems were automated using familiar UI building blocks? Many Rubyists are familiar with components for generating clean HTML with higher-level frameworks. Unfortunately, many developers are unaware they can generate clean Ruby code that is as beautiful as their UIs. This talk will explore how we automatically created a generator to produce high-quality ruby and docs for a popular gem. I'll show how to use this approach to keep gems up-to-date with fast-moving APIs, release new versions frequently, and provide an excellent developer experience.

RubyConf 2022

00:00:00.000 ready for takeoff
00:00:18.480 all right so these are some pictures that Dolly gave me of machine generated
00:00:25.260 gems so it's a machine generated images of machine generated gems and they're in
00:00:32.940 the graphic novel style I thought it was pretty fun um but I want to roll back to 2019 for a
00:00:38.880 second so I was out on a walk I was at an on-site in Seattle and I was walking sort of from The Event Center to dinner
00:00:44.940 and I was chatting with my friend Alex about this really cool tooling that he was building he was talking about how he
00:00:50.760 was using react but he was writing all these different programming languages using react and it sort of blew my mind
00:00:56.039 a little bit I was like this is really really interesting I was sort of bedazzled as uh we are when we're
00:01:01.680 talking about gems and so I have been sort of like chomping at the bit waiting to go out and talk about this and so I'm
00:01:08.280 super excited to share it with you all today um but before we talk about automatically generating some of our
00:01:14.280 sdks I want to talk about the hard version which is writing things by hand when I was going through practice one of
00:01:20.040 the people who I told we used to write our all of our Gems by hand they said by hand as if like we were actually like
00:01:26.340 pencil and paper which uh is not true so I work for a company called stripe
00:01:32.400 um the uh the only thing you need to really know about stripe today is that we have a web API and that a huge Lion
00:01:39.540 Share of the people who integrate with stripe use our official client Library so we have a bunch of different client libraries stripe Ruby is one of them
00:01:46.619 it's a very popular gem stripe uh apis are used by millions of businesses
00:01:52.079 around the world from super small startups all the way up to massive Enterprise companies to accept payments
00:01:58.079 make payouts and just generally manage their business online so again developer experience the hard
00:02:04.380 way when we talk about DX oftentimes we're either talking about the internal developer experience that we have going
00:02:10.860 out and working on our own applications building our own products that's like our own pains that we feel with CI
00:02:17.940 running slow or tests or you know the error messages that we're getting or the
00:02:23.400 the conflict and issues that we have when we're trying to like change our own systems but today I want to talk about
00:02:28.980 external DX and that is like when third-party developers try to integrate against our own apis and using our tools
00:02:35.520 maybe that's uh you know a third-party developer using an SDK a rubygem using the actual API the error messages that
00:02:42.120 they get the documentation that they read all the way down to the shape of the actual API response this type of
00:02:48.780 support you get that's all sort of external DX there's a lot that you can build into that automatically so you
00:02:54.840 don't have to do tons and tons of chore work all the time so let's talk about the hard way so in
00:03:01.800 2011 version 1.5 of the stripe gem this is sort of as far back as the public GitHub
00:03:07.800 goes for stripe Ruby uh this is when uh stripe Ruby was just basically one giant
00:03:13.260 striped RB file here that had just four resources you could interact with the
00:03:18.300 stripe API um fast forward a little bit we spent a lot of time hardening the core of strike
00:03:25.440 Ruby so if you look at the PRS between 2012 2014 this is things like cleaning
00:03:30.780 up organization making sure that we're backing into the patterns that we want to use inside of our classes or the way
00:03:36.420 that we want to implement stripe Ruby so that going forward it'll be a nice experience to use the SDK so there's
00:03:42.659 little PR's like this that are just sort of like okay let's organize our modules into their own files and things like
00:03:48.420 that going forward a little bit more the PRS that you see from 2015 to 2016 were all
00:03:55.739 of these really high effort PR's that were really just mirroring the API so
00:04:00.959 like as a new endpoint is released or a new property is released or a new whatever is released you have to go in
00:04:06.780 and make a PR to stripe Ruby but also strike python PHP node go java.net and
00:04:12.720 these are sort of like really heavy things that you have to do often costing you know hours per change or days per
00:04:20.400 change depending on how big that change was so here's an example of one uh
00:04:25.740 adding a new resource so this is a source object and if it doesn't follow
00:04:31.080 all of the exact patterns where it's just like a crud sort of rest API that
00:04:36.360 you're familiar with and if for some reason that resource has another method to it in this case verify then we're
00:04:43.979 going to add those in sort of manually but all of this is going to be a pattern that we're using across the whole SDK
00:04:50.699 in 2017 we introduced the open API spec into stripe Ruby and the whole point of
00:04:57.060 that first like dumping the open API spec into stripe Ruby was just for tests so we were using it as the fixtures that
00:05:04.320 backed our automated tests to make sure that stripe Ruby was behaving as expected and also this is the first time
00:05:10.860 that we have sort of this artifact that exactly represents what the API is that
00:05:16.620 is inside of the SDK and we're now able to use that to at least verify that what we're writing by hand is valid
00:05:23.400 so if you're unfamiliar the open API spec is a standard it used to be called Swagger so if you heard of swagger
00:05:30.300 before it got renamed to open API there's a bunch of stuff that happened around who owns things but
00:05:37.560 um at Strife we write all of our or we describe all of our apis with a ruby DSL
00:05:43.740 and then we have some homegrown tools that will spit out some yaml files and some Json files a bunch of different
00:05:49.440 versions of these specs depending on whether we're talking about you know beta beta versions of features or public
00:05:56.880 versions of features or um but at the end of the day we're giving out this open API spec and this
00:06:02.940 is actually available on GitHub so you can go to github.com stripe open API you can see all the different versions of
00:06:08.340 the open API spec that are available there still in 2019 we're seeing a lot of
00:06:14.280 these really high effort PRS that are going into all of these sdks
00:06:20.660 but if we fast forward to 2019 we'll start to see okay this is when we get a
00:06:26.400 glimmer of hope in that Cogen is going to come and rescue us and we'll no longer have to write all these high effort PR's just to mirror the API
00:06:35.100 um so again now today if you look at the repo you'll see like okay we're just
00:06:40.199 shipping one of these API updates PR's and then bumping a version and this is
00:06:45.360 all just generated now like every time the API changes it's flowing out to the open API spec that's automatically
00:06:51.660 generating the sdks and it it is super nice we're saving hundreds of hours in
00:06:59.039 engineering work per year but you might be sitting there wondering
00:07:05.220 like okay great like what alternatives did they consider how did they figure out that they need to build this tooling
00:07:11.400 and maybe it's worth talking about sort of the requirements that we had going into this so uh I already mentioned that we have
00:07:18.300 seven official sdks so we wanted to build some sort of pipeline that would support all seven of these languages we
00:07:25.560 also wanted that the we wanted the code that we were going to generate to um be almost exactly what it was when it
00:07:33.479 was handwritten there's a couple reasons for this we consider our sdks to be a
00:07:38.759 form of documentation we want them to be readable we want them to be like nice to use we want them to be something that if
00:07:44.520 for some reason if there's a bug then you can look at the code on GitHub for stripe Ruby and sort of easily figure
00:07:50.880 out what's going on why there was an error we also wanted some sort of pipeline
00:07:56.400 that was really straightforward to build and maintain for a very small set of Engineers inside of stripe who maintain
00:08:02.220 sort of this pipeline of SDK generation uh so this was kind of like our Baseline
00:08:08.400 requirements going into this so you're like sitting out there you're like okay he already said there's an
00:08:13.919 open API spec why is he using swagger code gen or the open API code generator so this open API is a standard it's uh
00:08:22.199 it's got a bunch of Open Source tools one of them is called Swagger code gen and it is a tool that will take your
00:08:28.440 spec and then you can spit out client libraries or sdks in lots of different languages
00:08:34.320 so let's take a look at what that looks like so you can Brew install Swagger code gen
00:08:43.140 and pretty simply pass a couple different options to it pass it this big
00:08:48.300 Json blob that comes from uh that's just on GitHub we want to tell it that we're going to use Ruby as the language that
00:08:54.720 we want this output and we'll just kind of like spit the files out into this directory called stripe Ruby Swagger
00:09:00.300 Cogen so this is going to go and generate tons and tons of files for us and if you are
00:09:06.120 starting today from scratch this might actually be a really good option just like go use this off-the-shelf tool that
00:09:12.600 you can Target tons and tons of different languages for really easily uh another
00:09:18.060 um reason that we wanted to do this is that or one of the reasons that we wanted to Target existing
00:09:24.540 um Target matching the existing code that was already there and already human
00:09:29.760 readable is that we wanted to minimize the breaking changes that uh third parties would have to make
00:09:34.980 um okay that didn't work as expected
00:09:40.260 doesn't like pausing in the middle when I'm trying okay all right so Swagger code gen spits out this giant
00:09:47.519 Ruby file called default api.rb and if we look at the number of lines 30 000 line files so just like a super massive
00:09:54.540 file for default API but that's not the only part of the SDK that's being generated so if we go into this models
00:10:01.320 directory which represents either sort of the params that we're sending into the API or the like results that we're
00:10:07.620 getting that are being then deserialized and bound to these Ruby objects there's over 2000 of them so it's like if there
00:10:14.760 was a bug you'd have to go dig through either these thirty thousand line files or two thousand different files so it's
00:10:21.000 like super tricky to go and debug anything and we felt like the developer experience wasn't great
00:10:28.019 um so uh this is actually one of the resources this is a customer object that
00:10:33.060 Swagger code gem wouldn't spit out for you it's actually pretty nice like there's documentation about all the different attributes and if you uh again
00:10:40.260 if you're starting today this is probably like a really good option off the shelf um
00:10:45.779 there's a couple different formatting things that were sort of bothersome and a lot of this code was repetitive so
00:10:51.540 computers are really good at generating repetitive stuff and then understanding repetitive stuff but we aren't as good
00:10:58.140 at that okay now it's no longer full screen
00:11:05.640 there was a couple different things that made using off-the-shelf tools challenging and that's because there's
00:11:10.800 some features of the stripe API that are a little bit um unique so one of them is that we have
00:11:16.560 this concept of expandable Fields so that means that by default if you make a request to the API and you get back a
00:11:22.680 Json object and somewhere in that object there's an ID to a related field then it's possible to change the parameters
00:11:29.760 that you sent for that previous request and instead of just getting the ID back you would get a fully nested object
00:11:36.000 that's like expanded in place inside of the Json that you got back and that means that you have like kind of these
00:11:41.519 polymorphic things where like oh a property could be a string or it could be like this other giant thing and so
00:11:47.100 that made it a little bit challenging but um the open API spec is really flexible and
00:11:52.680 so you can add your own sort of extensions to it so one of our extensions is expandable Fields there's
00:11:57.839 a handful of others but that made it challenging to use off-the-shelf stuff so while it is a convenience for
00:12:04.160 developers to have these different tools to in that case it's to avoid an N plus one query like to the API
00:12:11.820 um it can make it challenging to use off-the-shelf stuff so the uh this Swagger Cogen takes this
00:12:18.839 approach that uses templates they're kind of messy and if you look into the actual source of swagger Cogen it's
00:12:24.360 basically just like this giant these giant mustache templates that you then feed in the open API and fill out okay
00:12:29.760 this is the name of the class this is the name of the methods and then you will like iterate over certain results
00:12:35.160 that are in the spec and spit those out as parts of um as parts of the resulting code
00:12:41.459 we actually did a lot of this in our documentation and for a long time all of the Snippets that you saw in the docs
00:12:47.579 those were all just like written in Erb and just straight up like the raw code
00:12:52.800 was in the Erb template um and so we'll talk about how that has improved also but
00:12:58.139 um this sort of string concatenation approach or template approach was something that we want to avoid because
00:13:03.779 it's sort of just messy and toilsome on the other uh side of the world we've got these AST Builders and printers right so
00:13:10.500 like Ruby syntax tree or using a tool like that would be an option to approach
00:13:16.440 it from a different angle but one of this is like a list of reasons why we didn't take that approach oftentimes
00:13:22.800 these AST Builders and printers are very specific to the language that you're targeting and so uh as a team we would
00:13:28.920 need to go and learn all of the different AST Builders and printers for go and Java and c-sharp and all the
00:13:35.100 different languages that we want to support okay let's take an introduction to this thing
00:13:41.579 called prettier poet uh so this is one of the components that
00:13:47.459 is involved in our in our pipeline this is the one that I'm most excited about and super super pumped to share so
00:13:53.459 prettier poet is a react like tool for generating readable code in several
00:13:58.860 languages powered by the core of prettier so who's used uh react before
00:14:05.100 okay almost everyone okay at least at some point okay maybe 90 95 of the room
00:14:11.100 so um then we'll be able to spin through the Hello World stuff pretty easily so
00:14:17.760 react um we all often think about react in the context of a front-end framework right
00:14:24.899 so we're writing these components and we we at the end of the day are going to
00:14:30.000 receive back some HTML right so react is going to generate this this HTML for us but it's also going to give us some like
00:14:36.240 reactivity like you can have click events and you can listen for changes on things we don't actually use the events
00:14:42.480 or reactivity we are just using the components so what's nice about this is that we can have sort of really isolated
00:14:49.980 things that are easily testable and then we can build them up into much bigger things so in this case we have this
00:14:55.380 welcome component that is like super super isolated takes in some props and then renders out some things then we can
00:15:00.899 build an app component that is composed of these smaller bits we also get conditional rendering a
00:15:07.139 bunch of other nice features from uh just using jsx react is used for a couple of other like
00:15:14.220 really interesting use cases so react native is a way that you can write the
00:15:19.320 same sort of react code but you're building for uh like cross-platform
00:15:24.480 mobile applications you can write for IOS and Android but it's still you're you're using react
00:15:30.360 there's another example here so raycasts an alternative to Alfred or Spotlight on
00:15:36.180 your Mac there's an extension gallery for raycast and you can Implement extensions using these different react
00:15:42.180 components and tools all right so I wanted to do a live demo so
00:15:49.320 um this is prettier poet
00:15:54.360 so on the very first line here we're importing react so we can use jsx we're also importing this render to string
00:16:01.019 thing that's going to let us render out something to a string and here we're importing Ruby and this is where like I
00:16:08.339 was like whoa this is amazing so if you're feeling that I don't know like it's it's kind of crazy all right so
00:16:16.199 um we are going to build this higher order component called say hello Ruby that's going to take in some props that have a message on it and now we see this
00:16:23.100 new component or a sub component of Ruby called method call you give it a Kali and you can say whether or not you want
00:16:29.579 parentheses and then you can pass in some arguments and finally we just got
00:16:34.680 like this little helper method that's going to call render to string and that will actually like print out to
00:16:40.620 the console some some Ruby code you'll notice here when we're looking at
00:16:45.779 the render to string function it's kind of like a little yeah just like a little printing function but one of the arguments to render to string is a print
00:16:52.620 width now this is where prettier comes in really handy and that lets you depending on how wide you want to like
00:17:00.120 actually print the code it will break it at the correct line breaks and so if you're interested in the way that
00:17:05.880 prettier is implemented there is a a paper that will link to at the the end
00:17:11.280 and you can take a look at it it's only uh 20 22 pages long and there's a bunch of like fancy math in there but there's
00:17:19.799 just like a handful of functions that if you implement them you can build a tool that will make your code really
00:17:25.740 beautiful right and so we've probably um actually many folks that I have
00:17:31.080 worked with in the past are familiar with using prettier as a good way just like Auto format your code there's other Alternatives in Ruby we've got like Ruby
00:17:36.960 format and you know there's a lot of other things now but prettier is a language agnostic way to sort of build
00:17:43.440 tools that make your code look nice all right let's run it okay
00:17:50.400 so here's our output puts hello rubyconf
00:17:55.679 that's not Val I mean it is valid if we have hello and rubyconf
00:18:01.260 as constants but what okay so we wanted it to be a string right but instead we printed out just the actual like raw
00:18:08.280 contents of what was passed in as the message and so we need to use another feature of uh this Ruby like language
00:18:15.299 toolbox that we have here and that is ruby.string so here we're going to pass in as an argument ruby.string and its
00:18:22.320 value is going to be the message that we're passing in okay we can run this again
00:18:29.100 now we have quotes all right so we've got some valid Ruby code that's cool
00:18:34.500 but what if we wanted to print out uh the number 42. okay let's see how this works because I
00:18:41.280 don't know maybe it's going to do something Fancy with the string thing all right so we run it and this time we
00:18:46.679 get an exception it says what you try to call a string is actually not a hard-coded string it's something else
00:18:52.620 and so you get an exception it's like okay the props that you passed in they're not valid and so this allows you
00:18:57.720 to kind of like be really careful about what you're rendering out so they're instead of using ruby.string here we can
00:19:03.240 use ruby.literal that's another component
00:19:08.400 so we'll run this again and now we're able to say it puts 42 and if we wanted to we can put in both 42 and I don't
00:19:15.900 know uh hello run this again and we should be able to
00:19:21.780 see both options there so now we're able to like print stuff out okay
00:19:28.740 let's look at another example now we're importing Ruby and we're also importing JavaScript
00:19:36.299 so now we have this higher order component called say hello Ruby which looks exactly the same as what we just
00:19:42.000 showed we also have say hello JavaScript and here we have js. method call
00:19:49.140 and its Kali is console.log technically there are other tools I I took a couple
00:19:54.720 of shortcuts to build the demo but there's other tools that you can use if you need to like build a long method chain so you can you can say like oh I'm
00:20:01.799 in JavaScript and I need to build a like a chain of different calls that way when
00:20:07.380 prettier is rendering it if the line of method calls is too long it can sort of like split out so it has kind of like
00:20:13.980 the top level thing and then the dots on the new lines with the correct indentation
00:20:19.440 um so this is cool we're able to print out some stuff in different languages now we have the say hello function that
00:20:25.440 is just going to like sort of switch on the language that we actually want to print out so down here at the bottom
00:20:30.840 we're going to try to render hello Ruby and hello JavaScript both of those different languages so we'll say two and
00:20:37.140 now we get puts hello Ruby and we also have this console log for JavaScript so
00:20:43.080 um let's add go in here so here we can just say go you also notice that like
00:20:48.780 the say hello Ruby does not have parens but the method call in the JS component
00:20:55.140 world like has to have parents like you can't have a JS method call without parens as far as I know I mean there
00:21:01.020 might be some Edge case out there but all right so let's say const say hello go
00:21:06.360 all right thank you GitHub copilot go dot method call whatever so go it's not actually called method call the
00:21:12.059 component in uh in go it's actually called uh function call function call
00:21:18.900 and this is the right Cally format.printline and it will know that it's printing the right thing we need to
00:21:24.299 add this down here so we can say all right we want to actually print out go say hello go
00:21:31.559 all right and we also need to print out the right language hello go and we'll
00:21:38.159 just see if this works nice all right so now we're able to print out three different languages and
00:21:44.940 we're using kind of like this cool style so we'll come back to that as that's like one of the really important features that we use in the
00:21:51.179 documentation to render out like all the different languages as you're kind of like switching through and picking a
00:21:57.000 different language um okay so let's look at a third example
00:22:03.059 if I could type all right so this is another example where we're gonna have to just imagine
00:22:08.760 for a minute that this spec at the top is actually the open API spec right like the the spec that we have is so big that
00:22:14.580 GitHub won't render it so I assume it's like just really big file um and in this case we have two
00:22:19.919 resources we have a coupon and a customer and then maybe we have some operations so we can like you know send
00:22:25.080 a post request a get for a single one or a gift for a list and what we want to do is render out several different models
00:22:31.799 so here we can have a ruby module with our namespace at the top then we can have a comment with like a class level
00:22:38.820 description of what the what we've got going on this line tool here comes
00:22:44.520 directly from the core of prettier poet it is not Ruby specific but it is something that we use when you just want
00:22:50.220 to like add some some lower level formatting as you're building this stuff out so there is a set of prettier
00:22:56.280 prettier poet components that we use to build up these language specific
00:23:01.620 components and then sometimes you use them as you're building these higher order tools
00:23:07.020 next we're going to create a ruby class we do have to pass in the right strings when we're saying like okay here's the
00:23:12.480 name of the class we want to capitalize it and you can also say okay this is going to inherit from some other thing
00:23:17.880 called API resource ruby.statements so statements is a tool that lets us sort of like break up the
00:23:25.200 lines correctly otherwise they're all going to be sort of like bunched together so this gives us like gaps between all the different classes and
00:23:31.500 then because we're in react land we can just map over the list of operations and render out some other higher order
00:23:37.260 component that we can individually test and it's actually like pretty handy so let's look at that higher order
00:23:42.780 component it is this one so we're going to define a ruby method it has a specific name and then inside of that
00:23:49.799 we're just going to like do a simple assignment of some request and we're going to pass like a ruby symbol and a
00:23:55.919 ruby string and we're going to get back some response this is all just like totally fake and isn't exactly what we
00:24:01.320 use in in reality but I want to just show that you can actually like generate full classes relatively easy
00:24:08.159 um and so here at the bottom we're just going to iterate over the spec and for each of the sort of the resources in the spec we're going to generate a model and
00:24:14.280 print out the code in the terminal here so this is the third example
00:24:19.440 so here we have module we got our like namespace we've got this like top level you know documentation and then we're
00:24:27.120 printing out this customer class and inside of create it knows that it's like supposed to be splitting on these lines
00:24:32.700 like this to make a long method call but I actually want that to be printed out a little bit I don't know more like wide
00:24:40.440 and so I can come into my print with and change that to 80 and if we run this again
00:24:47.460 we're going to see that like okay now it knows that I have 80 characters and so I can like print it out in the right
00:24:52.860 format for 80 characters so that is pretty cool
00:24:57.900 let's look at another example in this case I thought this is like kind of another neat example of using jsx and
00:25:05.100 react to sort of like compose all this stuff we're going to build out a Sinatra server so some some route definitions
00:25:12.360 for a Sinatra server and we'll do the same for Express and the way that we're going to define the routes is just in
00:25:18.240 some data object again this is something that you could theoretically get directly from the open API spec it does
00:25:24.059 have like all of the um the routes and methods and sort of the arguments that it can accept
00:25:31.260 ooh warning something oh no
00:25:37.080 all right Amber Alert darn okay
00:25:43.500 inside of our Sinatra route there's going to be some children and so we can Define this higher order
00:25:48.960 component called a Sinatra route that's going to take in the name the method the path and then some children doc right
00:25:56.279 that we can then render out inside of our block so here we're going to Define another Ruby method call this is going
00:26:01.860 to be sort of either get push like get post put delete and then the the actual
00:26:08.419 arguments to that is going to be some string and then a block and inside the block that's where we Define the
00:26:13.799 contents for like the request the like business Logic for the request that we want to actually run and then inside of
00:26:19.799 our we can define a Sinatra app that uses this Sinatra route and as its children we can define a ruby method
00:26:26.279 call and for now we're just going to print out tests to keep things easy and we can do the same thing with Express so
00:26:32.700 in in Express land I just put everything in one giant function but let's run them both so for
00:26:40.500 okay so now we're printing out some routes for Sinatra some routes for
00:26:46.980 express pretty cool stuff all right another example
00:26:53.520 in this case we want to render out what it looks like to use the SDK so we're going to like print out what it what
00:26:59.520 does it look like to use stripe Ruby to make an API call to stripe so at the top we might have some spec and some methods
00:27:06.000 and then we have this API call which is going to use a
00:27:12.299 couple of other higher order components one is going to be the call E and that's going to like figure out okay which
00:27:18.720 resource are we talking about is it customer or coupon and then based on that resource which which method are we
00:27:24.779 going to call create retrieve list Etc so we have some params that we're taking
00:27:30.900 in and printing out a ruby symbol hash because that is the thing that you would
00:27:36.000 pass in as an argument to like a create call we also have this Kali I'm again like
00:27:41.520 sort of hard coding a bunch of this for brevity but you could use tools to compose stripe colon colon some other
00:27:49.020 namespace class name Etc with the name of the method at the end
00:27:54.419 okay so down at the bottom what we have is API call Ruby we give it a path we give it the HTTP method and then some
00:28:01.799 params just as this like JavaScript object right here and then we can run
00:28:07.080 and render this out so number five so now we get stripe customer create and
00:28:13.980 you can see the email the payment method Etc so those are the live demo it's like the
00:28:20.640 live demo portion and I wanted to like just quickly look at where this is used so when we're in
00:28:28.500 the documentation here um this all of this code that you see that
00:28:34.620 is part of rendering out the curl API call using the stripe CLI using stripe
00:28:41.400 Ruby python PHP go java.net this is all using that same tooling under the hood
00:28:47.220 to build out an API request and what's really cool is this enables documentation writers technical writers
00:28:54.720 to build out code in seven languages plus curl plus stripe CLI without
00:29:00.000 actually knowing how to write most of those languages right and so what we've done is we've taken that react code and
00:29:06.659 built it into this tool it is a a markdock
00:29:13.380 component so that you can just pass in a few arguments to this code gen snippet
00:29:20.820 component markdoc is the open source library that we use to implement our documentation but what's nice about this
00:29:27.120 is that when you go to generate the API calls we can also run validations so we
00:29:32.820 know okay the checkout session endpoint requires that you pass a success URL and a cancel URL so we're not actually going
00:29:39.299 to render the code for that unless it's valid so we can go through and make sure that not only are we able to generate
00:29:45.059 the code in all these different languages it's valid code in all the different languages and we can even include things like metadata so now we
00:29:52.020 can enable documentation and Technical documentation writers but also just like
00:29:57.179 the amount of code that we've deleted from our code base that is just purely for examples was uh amazing
00:30:05.820 um it's actually really fun to find old examples that are not using this Cogen snippet tool yet and just go and just
00:30:11.640 delete hundreds of lines of stuff that's either you know in Erb templates or just is hard coded in these markdoc files
00:30:19.140 um so that's this was a tool that was sort of like just put together in an afternoon using the core foundation of
00:30:26.880 the code gen tooling now there's other there's a few other things here that we do so in the API reference you've
00:30:33.360 probably seen similar API reference manuals where on the right side you see the code but oftentimes the code that's
00:30:39.720 being shown to you is like okay here's the path and we're just going to use some like rest client we're going to use
00:30:45.840 some other like low level HTTP library but now we can actually generate the code Snippets that mirror the sdks so
00:30:52.860 that's pretty powerful we can also generate change logs because we can know the diff between each of them and we can
00:30:59.520 uh so this this sort of like changelog bit is all auto-generated Postman collection is auto-generated and one
00:31:06.480 final thing is this the stripe CLI UI which if you go to any of the stripe documentation and hit tilde this comes
00:31:13.140 up and you can say like stripe customers list and that will like actually hit the
00:31:18.179 API bring back your customers and render them directly in the browser so you can kind of go through and check that out
00:31:26.100 all right thank you so much for your time and attention really appreciate you uh joining and hearing about this I was
00:31:32.399 like again super pumped when I heard about it got to use it for a few different projects and uh yeah happy to be able to share
00:31:38.460 so I'm available here if you want to chat and uh yeah otherwise I'll be up here for questions thanks again
00:31:46.140 foreign