Code 67

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
and it looks like we're live what we need is we need some some theme music so that everybody knows like hey I hear it it's starting music uh I like Gloria Estefan Get on your feet you know the one that Microsoft yeah that one you know yeah or Steve bummer comes running out like a madman yes dripping my whole thing like just just just that everybody well not everybody but like every time I do the slow flap start in my head I'm hearing developers developers or yes right this is like one of the funniest scenes in Tech but and but I love it it is okay I that's that's the energy I'm striving for if if uh if if the Twitter takeover with anything like this I would have been like yes it is it has happened uh so welcome we have a few people joining us uh thank you for joining us today is another episode of Code uh hello uh we appreciate you thank you for for letting us know uh you're here uh this is great Connor welcome to the stream uh it's it's wonderful I'm super glad that I met you Connor is one of those what I call a Spring developer Advocate that doesn't report to Tasha he's somebody that's out in the community doing cool things and doing the the the juice bringing the juice join us in creating excitement so Connor Thank you for joining uh Fabricio thank you for joining we're going to do the same thing code is a little bit different it's just another challenging TV show but what we're trying to do is we want to we want to put ourselves in your seat right we're we do stuff we want to share how we think we want to share what we're doing uh we want you to ask questions we have kind of a plan but if that that plan doesn't happen that's absolutely okay so thank you for joining uh my good friend Mario Mario introduce yourself hi Mario gray how are you guys doing um I am a tech developer Advocate with the spring uh framework team from night 2017 but I've been using spring since uh 01. oh no oh 304 something like that and um I guess what I can say is um I'm uh a developer since the you know slackware 1.0 um if you've ever used slacker that's that's kind of where I started developing uh software in a real sense um and I've been here uh I've been in multiple developer positions for for decades and uh now I'm here at uh VMware tanju working with um the fine people in front of you like Tashan and Dan and uh Joshua and uh and you know yeah and Cote and Lee and Tiffany yeah Tasha and Whitney did I miss anybody I hope I didn't miss anybody the big guns yes we have we have a great team uh under Sean Springdale Advocate I'm here in in large part because of Mario and Josh and uh before I was on this team I was also a spring developer Advocate just I enjoy it spring has done a lot of really good things for my career and I'm happy and I hope that I can pass some of those things on to you so today our plan is we're going to do some more spring rest docs but instead of using the rest template like we did last time this time we're going to use web client we're going to kind of Bring It Forward a little bit yeah it's still okay to use rest template yeah great I'll hand it off you tell me oh oh I I thought I was just gonna segue into like a question of hey what the heck are you talking about I like rest template um no rest templates awesome right it's been around for a long time it's core it's it's part of spring framework core um but the recommendation is maybe let's start moving towards web client get more flexibility right we can do restful and reactive oh okay right okay okay I get it okay so we wanna we wanna um yeah that's a good upgrade I like that that's a that's a nice upgrade you know going from one client to for rest template to write web client um I guess you're gonna get a lot more mileage out of the web client stuff anyway uh since I love I love web clients since it seems more functional and fluent than rest template um oh well I'd like to know how other people think about the reactive stack on web flux so basically anything webflex is is going to be you know fluent and functional uh in a way yeah so we're gonna that's another difference right it's not just the client that we're changing so last time we ran through this we ran and we used uh spring web So today we're going to use spring webflux yes another difference what we're going to do is bring in the whole so the reactive stack is well first of all what is reactive reactive programming is um the big it's a big question I I have a friend that I know that that explained this once and I like to give these examples out as uh you're talking about the difference between imperative and reactive and what you have an imperative is you know one scheduler one thing that executes your code that is your main thread everything blocks so for example if in in an imperative programming which is what rest template is you run up you know a method saying hey get a URL and your code sits there and waits on that thread for that get URL to come back and return an answer well in the reactive World rather than that one thread sitting there and waiting for it to come back reactive promotes a a scheduled uh event Loop so what ends up happening is rather than waiting on the single thread and then continuing after it's done um it's asynchronous so in other words the reactive scheduler lifts that call and it subscribes to it and on another thread it creates another thread it it does all the work there and then it comes back right and you have to be able to listen to these things you have to be able to say hey I want to know when this is done so you subscribe to it and you say okay well I either want to block or I want to um you know subscribe later and do some deferred work so basically when the answer comes back you can then fluently and and in a functional way provide more um programmatic functionality uh we'll show that late we'll show how what that looks like in practice I guess yeah just because it sounds like uh there's a lot packed into those into those words but essentially you're talking about like scheduling your code uh and reactive schedules your code in the way that um it would be very hard for you to implement this on your own you wouldn't I heard you say event Loop yeah like you know the JavaScript event Loop or how that works within ion and stuff um lib yuv live UV the uh the event Loop that you know it creates a bunch of lightweight threads and says okay well um it's a it's a task scheduler so it's going to be able to understand when when IO is ready or or when a threat is ready um or a unit of work is ready uh so that it can then event it can then send a notification to the thing listening to that event and and proceed with its uh with its code uh with its routine so uh I'll I'm going to put the link this is the repository we made last time we did it live we're gonna do something similar so I just posted the link to what we worked on last time uh Mario why don't you share your screen and I will step aside and we'll get your stuff up and let's just get started let's build some stuff yeah let's uh let me figure out which screen I want to share here I'm going to go ahead and we could start at start.spring.io I guess that's a great place to start yeah it's a great place to start only place to start but okay so present a screen yes I have two monitors and again it's interactive if you've got questions uh feel free to throw those in uh while Mario is driving uh I will be addressing questions if I can uh there are other members of the spring team may or may not show up so get your questions asked uh whether it relates to what we're doing or not uh we're here we're developer Advocates we are here for you uh if we don't know the answer Mario's got way more answers than I do if we don't know the answer together uh we've got slack and we can reach out to the spring team but this is just an opportunity for us to connect open up a channel uh let's learn some spring let's get some reps in uh let's do just uh I think okay so what we'll do is can you see my screen is my screen like uh I just now I've added your screen and I'm going to actually I'm going to slide off and I'm gonna let you drive okay great so if my screen's at the right resolution then everybody can see it and that's good um so I want you to be able to go okay well um I want to start a program and I want it to be spring application and I want to use webflex um so I want to be able to do this and also document uh my HTTP calls I want to be able to say hey I have an endpoint and I want people to know how to use that endpoint and if I want people to know how to use that endpoint hey I might also want people to um to be able to read it and then print it out so what we're going to do is we're going to implement something called uh we're going to implement a couple of rest endpoints just like we did before only this is going to be a reactive version not much has changed except for the testing API and and you will probably um like I would hope that you like the web test client the web client version of this because I think it provides a little bit more readable API in terms of fluidity has a question what's your suggestion for web blocks is it Nettie or Tomcat Tomcat we can't do webflux with Tomcat right is it Neti or someone yeah we have underflow right or yeah so you can use undertone not underflow right so by default it's nutty um by default like Neti is the spec for reactive and you get an Eddie HTTP server uh that comes with it you can use undertone if you want um you just have to okay well you just have to bring in the undertow server and then you can simply when you start up the application you can tell it how to start with undertow so it's not a very like you know it's not very difficult I have an example on my GitHub to do it um but you can bring in one of those two you're probably bring in another you know reactive HTTP stack if you want as well I haven't seen anything used more than uh Nettie and undertale undertow seems to be a popular one but Tomcat itself is really a certain spec uh so it's imperative it doesn't react to um it's not reactive so there's no way of getting those things onto a reactive stream without a lot of work uh and that work still makes it still means that you know if you were to bridge say for instance a non-reactive app with the reactive app that non-reactive app will be your um of losing in it will be the part of the application that eventually stalls the rest of the application because it's still operating under the uh under one thread it's still sitting there blocking so what we do have is a purely reactive HTTP server like Neti or undertow um and and that gives us the full reactive stack and it gives us all of the benefits of being reactive Mario you do a great job explaining things uh and I'm going to just kind of share my expectation my vision for everybody that's watching uh I I've always enjoyed watching this show I've always enjoyed kind of like having it passively on another screen where I'm kind of listening I feel like I'm working next to somebody but I also like following along so what I'm going to be doing and I'm you know if you have the opportunity in the audience I'm going to be following along and I want to you know Click by click follow along as much as possible last time we did the uh pair with me or the code with me do you think we should do that today yeah we can do that as well yeah I'll set that up and um yeah then you can just uh hop on and make changes in perfect yeah that sounds cool awesome um so play along if you can okay so how about this DeSean um not only is there rest docs because we love restocks um restocks does something else that's really cool um and I I've been kind of like living in the world of tdd for a while um I like to write tests um write as much test as possible I know some people think that tests are like ah after it's an after thought like I don't need to write tests but um I find that if I write tests first and then I write production code um I just feel a whole lot better than um you know not writing tests or even writing tests after my production code because I'm not sure if the production code even matches the test sometimes um so in this way I can ensure about everything that I write has been tested um so what I'll do is I'll write a little bit of a you know test and I'll just go to production when I need to uh EDD method so Johnny asked a question why would one why would one choose rest template instead of webflocks it looks to me like webflogs can cover the blocking case as well the answer is yes it can uh you might choose rest template for habit you know uh that muscle memory that's that's the only reason I lean there uh but I'm trying to learn too uh I just don't have as many reps with webflux uh and I'm trying to get them so yeah that's it webflux does cover all the Locking use cases as well yep yeah so okay um so the story goes yeah we have a we have an application we want to make restocks Drive some things one of the things that I wanted to drive with restocks if you don't mind DeSean is a spring Cloud contract that sounds awesome okay so what we want to do is we want to also create contract I used to do this uh this is like some of my earlier demonstrations is um using screen Cloud contract to generate uh stubs things that you can actually test against um from from Downstream consumers like a client for instance um so what we're going to do is we're going to add CDC that is uh consumer driven contracts we're going to be the producer here's the contract and what we'll do is we'll say okay so we have uh reactive web restocks uh verifier do we need lombok I like Walmart we probably don't need lumbac because we're going to use job 17. yeah okay let's not then okay let's let's uh let's call this artifact um uh producer actually uh one of the things that I'll I'll throw out there is when I'm building anything I always throw in the actuator oh actuator I always throw in the actuator and um you know because it's spring blue three who knows if we'll get there today but I also like to throw in that girl VM native support oh good one how is restocks different from Swagger or open API that is a great question on Boo and it's one that we've talked about I think you you were actually on the spring off Stars when we talked about it uh onto is a regular over there uh and there's some differences so rest docs is building the documentation from tests so typically with swagger opening and there's probably a framework that allow you to do the exact same thing but restocks the the main thing is that it's driven and it's creating its spec from the tests from the test output so that's one of the big differences and that's why I still lean into rest docs today you're going to see some of how we integrate it with our spring Cloud contract and reactive one of the things that the Swagger open API is not really great at a handling is things like uh hadios or however you want to say that and reactive uh specs so those are a couple of differences that we're going to be able to kind of highlight in even in today's show yeah it's something I don't think Swagger I'm not sure uh yeah it didn't the last time I checked uh it I'm sure everything's moving fast uh but yeah it's something we can Circle up on uh but yeah historically it wasn't really great at handling that thanks competencies did I miss something I think that's good that's good um actually a question uh the contract verifier versus the contract stub Runner uh-huh oh we're gonna do both don't worry so verifiers for the producer okay um we're gonna produce a contract here um and then stub Runner uh well stub Runner is the thing that consumes it so it's like my client that's going to you know if I'm on two teams and I have the guy the back-end team and I have the front-end team uh the front-end team is going to want to run the stubs in order to verify that I don't know I use the word verify in a different context here but they want to use the stubs to verify that their client works against the server the producer so it's consumer it's producer consumer semantic here got it I shouldn't use verified so many times I should just use it in the product in the producer context okay so let's generate that this is called the producer.zip and then if I have a shell terminal I might have a terminal around here somewhere I guess I do so let's go ahead and push that guy here um let's go to workplace demos and uh make sure I don't have a producer already dope foreign okay and it starts in another window or screen that's that's perfectly font looks really good it's a nice very readable uh I changed it to hack so now I'm using uh the font called hack Ed I guess uh who who makes hack is it GitHub I think GitHub or something it looks good that's a fun font a bunch are fun okay so what's the first thing we want to do we want to we want to write a test so you know in tdd tests come first right just a little bit of test and then go um so what we're going to do is this is a spring boot test this is our context load test we can leave it there because it's eventually going to have to run we just want to know if the context loads here so I can leave that test alone he doesn't need to go anywhere I'm going to create a new test and that test is going to be called um I guess rest controller test or rest tests how about that that's good enough okay uh and this is going to be a web Flex test so what is webflex test it's a it's a stereotype for saying hey this test medally brings in the application but it brings any web uh a web context a web application context so that it knows how to uh essentially enumerate your controllers it'll enumerate controllers so that you can then talk to them using webtest client webtest client is a way of talking to your controllers without talking to a tcpip okay so normally you have to start stand up a server and that server has to listen to a port um and that Port of course takes up resources and it has to sit there and uh and transform tcpip into a rest or a HTTP um request right with with webtest client you don't have that it talks directly to the API so it makes no um no transport bound requests so it's a very it's a very fast way of of producing these type of um unit tests so we'll just how to wire that so I I'm using a lot of wired but here's a web test client we'll just call it how about we just call it explained and I'll kind of like having that whole entire word in there um and then we'll test an endpoint so DeSean um can you give me like an endpoint that I might want to like code you know um what should our first endpoint do um add planet okay um what should the uh what should it be should it be a post or should it be a get or um a post okay planets uh how about Slash API slash planets oh okay apis life planets okay um okay and then what do we want to do for the body um I want to pass in some yeah Json uh but it's just a uh a planet uh name okay oh planet name like Jupiter because yeah okay so should it be a string I guess yeah what planet do you like yeah Jupiter sounds great okay um alrighty so what we're doing here is we're telling the application we're telling the test to close the URI with um with the body of Jupiter to um an endpoint we're going to say but this is encoded in an application Json it should be fine even if it was context text plane um we can send a more uh you know a thicker object later uh in this case the exchange thing The Exchange method here says that at this point we will be talking to um the response signed so above the exchange we were talking to the request side and below the exchange now we're going to talk to the response side uh so in this case I'm going to say expect um I guess created do we want to say created or just 200 yeah 200 for now can you close your um your sync tab so I can see more of the the class yeah and which what kind of tests did we have here right so what we want is that this is going to return to anything and maybe not returning anything it's just a post and it's like okay it's done and so that should be fine um in this case we can say expect a header um content type compatible with uh I guess media type application Json um and I suppose that's that's it do you want to say do you want to like repair anything or do you want to move it uh maybe uh return an ID oh okay there we go yeah so then we can move on to the expect body um and is the ID just a number or will it return like a Json entity uh that's the ID uh how about we return the entire planet object back okay you know the name and its ID that sounds good that might be cool okay okay so then we can say Json path uh and in the Json path we'll just say you know um dot you know ID I believe that's the correct example I might be wrong about that but uh exists okay we'll just say Okay so let's see I believe it's it's open close brackets or it's not open close brackets Json path can be one of those things where it's like you're looking for an expression and it's like ah which expression is it um in this case I don't remember this how about let's just put a comment there what are we expecting yeah what do we think that that's doing yeah what should this do you do okay so what should this return uh this is this is either going to I'm not sure if that Json path is going to be an argument is this an argument or is that an actual expression for the thing that we want to expect uh yeah I believe we need something like this is equal to so we don't need the arguments here in this case um I'm going to leave that and give us a whirl I'm going to break this test this test is already broken because there is no endpoint uh so if that's that's not obvious then I'm not sure what it is but uh yeah it's obvious that this is broken it's not going to work anyway um what we want to do is we want to go we want to go ahead and fix the tests and then we want those tests to pass so given this you know I'm going to send the word Jupiter and it will return an object with its ID and name so what we did here yeah we we said hey here's what we think we're going to be building uh so we made a test and this is our expectation for what we're going to build right we we did a web Flex test and we kind of thought through what we think we're going to build that's it there's nothing magic here right no okay uh not not completely magic not yet uh the magic happens a little later okay oh yes okay so I think I did do that wrong because I'm looking at my Json path Expressions um yes okay uh idea one okay so we wanted to have the idea of one or maybe it doesn't need to be one maybe uh maybe it will just say planet name how about that uh the ID can be anything testing for the idea is like the wrong idea right got it okay so it is equal to um uh Jupiter okay so we want the name to be equal to Jupiter okay so should that planet fails uh on purpose uh there's nothing there yet uh now the next thing we want to do is say oh well we don't have a planet yet let's let's add a controller uh so let's go into production uh and in production we can then say um here go ahead and call this my Planet controller on its controller or planet planet controller all right so let's say rest controller uh that's our stereotype for saying hey the thing is going to contain a bunch of mappings um and we want a post mapping and we want the post mapping to have um name value is actually um what was the URI API Planet okay foreign can I ask a question if on the top of my rest controller if I just said hey slash API slash planets up there Then I then you would have to it will be slash right yep and it'll be slash I imagine Maybe okay so uh this is going to return a string or Planet that's what we're trying to plan it we don't have a planet yet oh no we need a planet all right what does that look like um what was it body request life my bad that's body um okay so we need to create uh usually we'll do this in tests in fact uh the rest test doesn't cover the actual creation of the planet but uh in production I can't go any further uh none of this will work I'm going to consider this a failed test uh and then I'll create the class called plenty um it should just be a record is this recordable yeah I think so I think so okay what is the name what is the long long ID screen name right okay and kotlin works um pretty much like record it's the same thing essentially that one of the biggest uses in column was like the data class not having to worry about creating the using lombok even uh and creating a bunch of Getters and Setters and Constructors and lightning all that stuff uh in this case it's it's so great I can just go ahead and uh and have a uh I think I can just have a uh a single class that needs nothing else but go back to your record show us your record show us the record what is the record really fast right it was it was super quick like hey here it is yeah for the record this is a planet uh so that's just a long ID and a string for a name uh looks good yes no yes uh Json are we looking for uh Json serialize uh nah we'll get that out of the box we'll get default message converters cool cool default message converters for records guys um so we don't have a server right we don't have like a uh restful I mean we don't have a server we don't have a service a planet service yeah so what we'll do is we'll just say here uh one L and then um whatever the name is it'll only return a new planet it won't actually push it anywhere uh if you want to do that we can create you know we can create a we would need to bring in a persistence layer we currently don't have persistence so what we're going to do here is just return maybe even a random number um for the ID and then yeah okay that's that's probably uh there's probably a better way of saying hey that's great that's perfect but that'll work for now so uh let's see what we did here we created a post mapping uh we said hey I have API Planet uh and I'm going to take in a name and I'm going to return um yeah I'm just going to go ahead and return a planet with that name in it it's going to have a random number as a long uh that's its uh uh ID and this thing should do the same thing it should just say hey I'm going to go to API Planet post the body that's just the word Jupiter and expect everything to be fine expect the name to be Jupiter oh the next thing is uh to Sean um I need to add you to my code awesome uh four four and not found slash API slash planet hi um probably because is it doing coding no it's not the encoding nope range oh I know I know I know I know why I know why because on line 20 we didn't have a slash we put the slash in our post mapping and we didn't add the Slash on our test oh there you go well that's cool right I'll have to try that one out before yes I like that variation okay that's a little bit better uh so now it's telling me that it won't uh find it it says hey I don't see your um I have a 404 it's saying that content not even content type content type was fine okay I I've been bitten by the not found book before where I had the invalid content type but that's that was something else uh in this case I I have missed Matt so if I wanna if I wanted to map a uh a controller to the root of the you know if I wanted to map a endpoint to the root of the controller mapping um would I need the slash up front or what I need the slash down here uh that's the question I usually don't have to cut to what do you call them either way either way those will both work those are both work oh cool okay well I know that that works um in this case then I shall I shall attempt to fix this and uh go ahead and run that again uh 404 not found interesting so what should we do here let's take a look at that error make it bigger I can't see oh here we go all right it says Hey the range for response status for forward not found expected successful client error uh the assertion failed uh yeah but but what oh wait API planets the path API planets oh there we go it's because I'm sending in um a content type of I'm I'm supposed to I'm supposed to um produce and consume uh let me see let me change that it's I'm going to say about the content type because uh my mock my um blog post client is saying I'm expecting a um application Json except Jason yeah produce Json and also um consumes is it okay okay uh but nope that was a good thing it's not application Json value it's consuming text it is uh text plane oh I see what you mean okay so um producers except headers let's see uh so right consumes equals media type Dot um well that's not it I can't because I've done this a bunch of times uh let me try something let me debug real quickly and uh attempt to Salvage the last bit of that right there uh so while you do that I'm going to answer a few questions so Connor says is it public by default then or protected oh I think he's referring to right there line 13 uh that we're looking at and he's saying hey is that a public no will not be public by default it will be uh protected is protected the right word it's going to be yes effective protective package protected yeah uh then spring three treats quote and slash different yes yes it does uh isn't better that create return type change to Mono should we change return back to model we don't necessarily have to it depends on how we're going to access it and what we're trying to do today is we're going to show how we can do this as a reactive client and how the reactive client can also handle the the blocking client use cases so yeah we'll probably get to that in a little bit Connor says I like having that as an agreement among the team though yeah how are we going to expose these endpoints and it also makes a difference in how we're going to test those endpoints uh love asks why spring boot three not support Swagger configuration um I'm gonna need a little bit more probably I don't know why it won't yeah you probably won't find it in the initializer but you can include it separately yeah there is there are a couple of uh packages in the ecosystem that will create the Swagger uh endpoints from what what it finds I'm assuming it's going to go in and look for your rest controllers and and identify all the post mappings get mappings endpoints and they'll expose that as a API spec uh there are a few that do something similar to that but yeah so that in that sense it is supported but it's not something that we're getting out of the box right uh we're giving you a bunch of different ways to configure things but that's something we're just not we don't lean into uh right away out of the box but yeah there are tons of options for delivering and consuming uh Swagger apis uh programmers Algeria says try to remove the value equals question mark I'm sorry I don't I hope you can hear that uh Mitchell that was really loud in my ears I had a phone ring uh yeah yeah so um what what I did before was um what I'm doing now is I'm not even asserting uh the body I'm just saying here um don't even worry about accept because I really don't care about the accept you can you can do that up front but that will limit your um like your clients because if you're receiving a Json body you're always going to expect a Json body if I'm producing a Json body then at least this is going to ensure but I always accept uh produce the application Json um and I have a expectation that the result is going to be compatible with the application Json and I'm producing application Json here um so what I expect at this point is four one thing to happen and that is there is a slight compatibility that I introduced with the um media encoding and my media encoding still says hey I'm going to uh accept application Json of course I didn't set the content type and of course that's why here I'm supported media type this is text plane and uh that is one thing what application Json or range for responses we're passing in textplane we didn't convert our all right our our input we passed in so we didn't what we didn't do was we didn't give it a planet we gave it a stream yes right uh okay uh and because we gave it a string it's like hey this is text I'm not you know I'm not seeing Json here I'm gonna just uh go ahead and say hey this is text plane um where where is the body so what you're saying is what if I give it a planet and then just uh let the message converter handle it give it a planet without an ID or with a null idea or something like that um and then a returned one with the ID itself foreign I'm sure that things like this typically happen when I want to do something that I probably shouldn't do which is give you a string and return a Json object because I I can get into that uh that cycle of well what Dev said you know this is a rest call if you're just going to send a string um to a post and and then you're not going to say created or you're not going to say successful or something like that uh in this case it's it's uh 200 it's 404 it's hey we have the right request but we don't have the right uh encoding um I want the right encoding so in order to do that I'm going to suss out one or two things I'm going to create a git mapping here and I'm going to say what planets do I have and I'll say um let's get rid of let's pitch this to slash API but then let's put this to slash planets and actually I like I like the idea that you had slash planets in there um for some reason though um that wasn't even agreeing with me there you go so what we'll do is we'll say get mapping um I guess you can say value equals uh this is probably a good one too actually produces people's media type application Json value and um so what we'll do is we'll return we do want to return the list or do we want to turn the cut into just one whatever there's there so for now let's just say it's going to return a planet um I would say return to list how about we just became a list because we might have more than one client to get yeah normally if I'm calling the root uh just like where I posted in my head my typical default is if I call a git on the the root of that API uh for something like this a crud type API uh I do I want the entire list uh I'll later I'll figure out how to pass in like paging and sorting Etc uh but yeah I think I want them all yeah this is just a demo it's not you know it doesn't have to actually mean uh semantically what it's doing it normally we'll just create like a you know we'll have persistence in here I like persistence but I like a new persistence right now um so this test will fail for now because what I did was um I don't want to get too lost and debugging that one error should the planets uh so what do we want here we're just gonna do a simple um bracket I've got your uh Slash API slash planets cool uh and then accept a piece of Json Exchange let's write this one more let's try one more test of course uh that's going to just make sure that we have one or two uh Json entities so we can say fixed status expect a header or expect um body don't forget your trailing slash online 21. there we go yes [Music] what was that where did the double brackets go dot yes on path hi yeah things are loud over here well we have good planets uh and that's all it does this is even a more compact test because I'm just doing a get request uh against this controller uh and if you notice what I did earlier well I said hey I don't want to control I don't want to like write production code first I wanted to write test code first but what I did here is that's a way to kind of debug what my thought process is is to write a smaller controller uh and then go from there so I've run I've written this a million times I don't see why this wouldn't work unless it's just the uh you know the ghost of tusk's past clearly I pissed off a test at some point in life uh no content you got no content uh return arrays let's list okay yeah there is an areas list um that fell really let's do this wait what you were you are uh yeah you're you're trying my my patient's computer I'm going to run and I'm going to say uh HTTP colon 8080 slash API slash planets huh oh I can't see what it says because uh our little faces are covering it up oh no I'm sorry so it has not found yeah I don't understand why I'm getting that phone um okay all right it's a there's there's a rookie mistake I'm making here there's a there's a very it's a wooky Wiki let's see let's just call this endpoint slash all okay okay yeah yeah okay if you can agree with me slash all is is good um like just the API to respond under planets that sounds good but um slash all hey really um oh did I do something wrong oh no oh no I didn't write I didn't do the rest controller correctly no you did I did yeah that's the logical okay yeah right yes request mapping my friend is is what I need oh let this be a lesson in go t yeah unbelievable yeah it's always your your coding you're going oh crap I missed that once again what did I do right so okay all right it was right in front of us yeah yeah I was right in front of them it's request mapping um I I sometimes think that uh doing rust controller itself should uh take in the root of the uh you know I'm sure that there was a good reason for that I would like it to take in the route yeah there we go okay so now let's run that again now we're kind of look at it now we have Saturn in Jupiter look at this good okay one more time should get planets yeah I was getting uh I was getting a little testy there too I was thinking huh there's no pressure here what did I do differently there's a variation it's always you always got to ask yourself you're when you're a developer you're Alaska you're going to create you know a little bit of um you're going to create like variances right and you're going to ask yourself what did I do differently this time and it is such a small change usually about it changes the outcome of whatever you're trying to implement and in this case it was just I never I barely ever use that uh request mapping I haven't used it in in days God why would I need to use it today you know uh that type of thing yeah all right let's let's see if this does the same thing or it might it might still air out for a different reasons I might have a uh let's see oh yeah slash my bad so we gotta do post to APS left okay huh I told you we could write a resting Point somewhere unsupported media type this time uh this time let's see Json instead of we we have Json versus Json value I think we just want to remove that underscore value okay so so the way that works is that these are the same strings same this is just the media type that you would include but the Json the value just says like instead of the media type uh pointer we're going to just return the string itself and that's right okay and then so what is the difference here uh why is it saying what are we returning that's okay oh I know I know I know I know oh what uh right uh where we did contact compatible with yeah that's what we ranged last time yeah I'm gonna remove the variances um just because I'm um I'm not usually writing tests that specifically that specify that but if it's still a name path okay so there's nothing there yet uh and that's why so we just wanted to say dollar sign dot name all right dollar times the object I guess and then zero would be like the um the airity of the array and then would be the thing okay all right so all right we can feed like this we can continue to fix um that's the whole point I want to be able to do that I want to be able to say hey I'm going to um produce I don't want to produce a Json I'm going to consume ajson uh in this case so I want Jason to come back right but I don't want a Json to go in because I I'm going to have text um nope your post mapping produces Json right oh my god there you go yes there you go here you go yeah thank you I uh I don't think I heard that right the first time okay so that that fixed it um I I accept it I didn't expect it um and that's fine I'm accepting the uh return value and I want that to be uh compatible with Json and I suppose that text value is I'm sorry X-Plane is the same thing um so what does this mean what did we get wrong uh and how can we how can we change this my endpoint was consuming a text plane value correct um but my test was actually at first it was consuming a Json but my test was only producing text yeah and because I didn't specify hey this is actually Json um it was going hey that's just a string I'm going to make that a text now the question is to myself what do I do in order to change that so so uh let's see uh content type right how do you you're wanting to pass in Json uh actually I'm wanting to you know I don't I'm not passing in Json I'm passing in text you know the rough template I can do that I can say I'm passing in Json even though it's not Json I can still say hey I'm passing in Json um and then Json will be the the Matched header um even it's not correct right because it's not correct for me to pass in a stream when I'm only passing in uh it's not correct for me to say I'm passing in Json when I'm passing in a string right um and it's doing the right thing it's saying hey I'm going to convert this into a string you know this is content this is uh the context is this is just a a string value it's plain text um so I did the wrong thing in saying that it's going to be Json did that did that make any sense um it did so let me just look at our test again so we're doing a post to API planets uh we're passing in a body a mono with just Jupiter uh of as a string we expect or we are accepting uh application Json on the return and when we do the exchange when we do that post we expect a status of 200 successful we expect the header to say that is compatible with application Json we expect the body and in that body we expect the Json path of dollar.name to equal Jupiter that makes sense so let's go back to our planet controller okay and let's let's you know double check that like hey does that all make sense of what we just said uh we're at API endpoints uh we did the get we're let's look at the post we WE Post to slash uh it produces application Json value it consumes media type text plane value uh we're doing a create planet and the request body is taking in a name and we're returning a new planet that makes sense to me oh okay so um right so test pass okay yes all right well that's the way it's supposed to work okay um yes all right so what's next what do we need to do here um I think what we want to do is we want to generate rest docs no yes or no yeah yeah absolutely controller endpoints uh we're getting planets we're we're setting one we're we're getting the other these are mock-in points by the way these aren't mock endpoints I'm sorry don't don't let me say that word with abandon um if I say mock with abandon people might think that this is actually being locked um these are real production endpoints that will re respond these tests are using the mock web um web client so it will you know like I said before it won't use a transport it will talk to the API directly is that right talk to the API directly doesn't need to talk to a TCP Port um but you know the abstractions are all uh what I would call the same the abstractions are you know still an HTTP request an exchange and a response right The Exchange contains both the request and the response um so all we need to know is that the code the main path the thing that we want to test against this guy here the return statement basically works and that's all everything else um really well okay not the main path the main path is the um the setup so you know from your mapping to your to your headers to the actual code that returns your your value but that's all being tested um whether it's going through TCP or or UDP or whatever other protocol or you know it doesn't matter so these tests are super duper fast uh the next thing we want to do is um I guess we can say consume with so in order for ASCII doctor to work but Sean what is the first thing we need to do um well for ask a doctor one of the things that we did last time we had to tell ask the doctor hey here's why I want to generate a snippet right we're giving it that that command that says Hey I want to generate a snippet from what I'm doing right here okay so in this case um what I believe we can do is um we can say a couple of things here we have a plug-in and that plug-in where's that plug-in oh here it is the ASCII doctor plug-in okay so the ASCII doctor plugin allows us to say uh hey I'm you know this ASCII doctor uh and ask your doctor has attributes and those attributes are basically you know variables so what we want to do is create an attribute called Snippets and we want to point that somewhere right did we need to do that I don't know if we need to do that I think we get a decent value out of the box because we updated the acid doctor Maven plug-in so after our last show we realized like Hey we're not getting the right versions of everything yeah we opened up a ticket the the team was quick to respond and they gave us a new more modern uh version of the plugin that was uh not current and I think that the new version gives us this but we we can go this route anyways so what I typically do is um make it make it explicit yeah I just want to be explicit and like just make it known like if if you're going to use a build tool at some point to extract Snippets um you're don't worry about that you're going to want to know well where are the Snippets and so that's this is like basically setting it up so that any variable uh is already exposed right it's explicit good uh the next thing is is the following so I'm going to do that I I basically set up ASCII doctor at this point and the build Tool uh the next thing I want to do is I want to interact uh with ASCII doctor know or do I want to create ask a doctor how about it creates a mask a doctor how about I create like a like our little base yeah yeah okay so we need to create a directory under Source or under Main and call it ASCII doc and then what we need to do is create a file that explains um for instance is it one endpoint or is it all the endpoints uh in this case we can say uh planets dot uh Ada yeah and so what do you want to do you want to do you want to drive from here do you want to like create some documentation and uh just just fill it in so ask your doctor much like markup uh yeah let's give it a title planets API uh and then the next step we want to say like hey here's we have a snippet uh the first one we're going to show is uh our flash API slash planets we have one for post and one forget so those are the two that we've identified so far so we should be able to fill in just a uh we'll have a yeah it's an operator operator will give them we'll get or operation all of it yep operation colon colon so now this is where we're telling acid doctor it's a one of its methods to go grab that snippet and plug it in for us and because we're using operation we're saying give us all the options that you provided uh it's going to give us HTTP Pi a curl uh regular HTTP request response uh is it Snippets equals limited lists no way you don't have to do that if you just do operation colon all uh open close bracket I think that's all that we need Okay so this will give us everything that we need in here yes uh in that case then we can move on so we have an ASCII doctor here we we said hey we could get all the known planets for the following call operation all that's going to include what you said uh which is all of the little Snippets that a user will want to see okay um so let me pause for a second we have a couple of questions so fuel stable asks uh why do you need to pass in stream.class so in our uh in our test oh here yep we're passing in the class why do we need to do that what are we doing there were go ahead we're just gonna give it the type yep right there on line 36. [Laughter] are you you are mocking us I liked it um I got it uh what do you what do you need to pass through um the reason why we need to pass string is because we're passing in an object containing another object of unknown type and because Java has like this type Erasure which means that like I can't send in the list of strings and then have something ex expect a list of strings unless I explicitly say this is going to be always a list of strings this might be a list of anything right so if I um type Erasure means that sending in a list of T everything becomes T an unknown object okay and in order to know at the other time hey I gotta tell you a hint you know I have to say hey that t is actually a string so in this case that thing is a mono and that mono has a type T and I want to tell that hey type T is a string so dual stable now that I've actually heard his voice now I hear his voice ah type Erasure I I see it good thank you for that explanation uh Johnny says Hey the the recapping helps when we Circle back and say what we're doing uh Connor asks uh what was the path for Snippets attribute what was the path for Snippets so by default it goes under your target directory uh under something called generated Snippets hopefully that makes sense so we're going to ask our spring rest docs to generate some Snippets and throw those Snippets into this generated Snippets directory and then we just looked at asky Dr Ashley doctor knows how to pull in those Snippets one more time Snippets Snippets uh yeah but don't do it five times into a mirror in the dark don't do that no okay so um all right so let's go back to our test what do we do we create it we created this we created the ASCII doctor that will contain the uh you know the documentation that we want this is demo uh so it just says hey you know here are all the planets um and here's the operation here's a thing that will actually pull in all those Snippets uh and we'll show you the Snippets after we're we're done coding uh this one particular piece uh let's go back up to our kit method right uh and let's say um so for what blocks um for for rest template or Mark NBC you have and then do and do um for web Flex you can consume so you know you can return a consumer um so you can say like uh consume with and uh in this case we want to um let's see web test client rest documentation there it is okay so we want to engage the web test client rest documentation uh snippet generator uh so essentially what this thing does here um it documents restful apis that are are bound to um the client of webtest client so this is a version of um the the generator that will interact with this whole thing this whole guy here so it'll know the operation is done and it'll document them so let me clarify or let me let me place on the back we have a test that's working we have a normal spring webmdc test that that you might typically see the the line that you just added is the the one step that we take from going from a regular spring webmdc test to using restocks this is the line that says hey restocks uh we'd like you to generate these Snippets that's this is the difference right yes so the difference from going from your regular tested stuff that like that everybody is perfectly uh comfortable with and we've been doing it for years and we always test our code unlike dealsnable to go from your well-tested NPC slices to something that actually generates your documentation this is the step this is good um so that's the stuff that'll that'll produce the thing that we want so we you can literally just copy and paste it it's it's not that simple there are other variables that you can add uh to that so you can add like root paths and things like that yeah but to just get the documentation itself to get the known uh the no knowns you know the the everything that we know about this which is in code uh to get that out we can just simply call this method here uh and that'll get everything that we need to know um documented out so running this test will do the right thing it'll it'll you know execute the tests it'll oh hi what happened here uh restock oh duh uh we forgot something important yeah we had to say uh like extend with um Okay so what we want to do is we want to actually tell our test our unit tests we want to tell them hey um there is going to be a rest documentation context involved and that context is going to be the thing that like uh helps us assemble these Snippets so then dump them into a file can I try this can I try this part I think it's I think it's gonna be exactly like what we did last time oh yeah yeah let's do that uh you might not want to put that on the screen oh no yeah no no no all right you throw that in the slack and then we'll I'll grab it I mean everybody that's here is all friends and family but on the replay right uh so I will I will grab that and I think what I'm going to be able to do uh as soon as I see that link okay I'm going to um so what I'll do here is I'll I'll uh I'll chat you on the sideband here all right now let me just make sure Connor said uh you're gonna share that link I was gonna drop in he was like he was ready oh hey I'm looking like 40 people into my code like like yeah that's amazing uh okay I just don't want this to uh I stopped sharing my window because I didn't want any yeah everyone slot to just open up on on the window that I have because it sometimes yeah so let me grab this select by the way okay let me grab this uh I will copy that that's funny though and I will try to jump in here you have all these people like [Laughter] you know and that's something that maybe we do on a later show is you know we have folks that are are already screen developer Advocates like Connor uh we just have him jump in and encode with us that would have been fun I enjoy that sounds like a hackathon but like yeah but that sounds like a hackathon almost yes like a little like a a wheel and it just goes around and says Okay add code add code add code add code I am looking for the link here please continue to hold what happened uh I've got the link but it gave me like a curl Bash oh yeah it downloads yeah so um right from yeah I think I just have to grab this yeah go with it it works wait it might it works it doesn't have the uh uh yeah I'll run it here we go yeah it'll take it it looks like it's okay it usually takes a minute it has to unpack and then I already had all that I already had that I know I know it's that one command um that's weird there is a there's a there's a shortcut but um they didn't make it like intuitive to the point where you can just drop it into your ID and run it you have to like do one extra step got it Jeff rains like sure sure brains you can do that of course Mr Mr Mr Brands right and this is a natural like everybody does this everybody goes to this right you're going to be my Google you're going to be my GitHub co-pilot my GitHub brush awesome all right so now I'm connected you got it look at my code look at my code I'm the pilot now yes co-pilot pilot ha ha all right so what I think uh I'm gonna jump in and now I'm gonna drive on yours what I think I need to do what we just assessed like hey like I don't have that rest documentation uh context so I'm going to jump into rest docs I think this is what I need and I'm looking at our previous sample I want to extend I want to say hey here is some more details that I want you to to know about extend with uh can I do that nope you gotta just insert it there we go yeah and then I want to rest documentation extension and and spring extension I think that's all I need is that it um can we run it again I like to add I usually like to add um because I'm not going to configure the context myself here in another block of code um I usually add Auto configure rest docs to do that for me uh just because it's it's a little bit easier than me like saying here plug this into your web test client um other oh I'm sorry make that a you know what though I don't know if I needed that and and can I do this uh do I need both of these or can I just do this yeah to get rid of one it won't like try getting rid of it and then running it and see what happens yeah let's do that yep see it's so much easier that's why I that's why I'm learning so no not yet go to Target and see that it's in Target let's see I finished generated Snippets look at that I got Snippets for all you got Snippets okay so you don't need extends with so okay we learned something or I learned something right I just learned a shortcut because what I was doing was I was adding that uh extended width and I was adding things that I didn't need to add I too was doing both I was adding extend to it and also I was adding other configured rest docs now in other configure rest docs uh what is this going to do this is a target document inherited important Earth documentation provider uh so this provides the context already uh the extension let's see so digging to Jupiter for uh to manage it automatically uh what is this guy going to do it's going to create a context okay before we give me a context before test uh do something with the context uh get required test method name okay all right so it's just going to add hooks apparently uh it's going to tell you where in the cycle you are um it's going to allow us to do something like manually but we get it we got it so what I get what I understand is we can do it manually like there's two versions of doing it which is like a before you set it up um and then you have to do extends or you can do other computer best docs and we don't have to do anything all right so Nishant just showed up and he says what are we creating uh that's a great question so you know for those of you that just joined the Sean welcome uh this is code uh and what we're doing this week is we are uh building something we're just building an API then we're going to actually we're doing tdd we're writing our tests first then we're building an API uh then we're having spring rest docs along with ask you Doctor create our documentation from our running test from our successful tests and then we're going to add on Spring Cloud contract and we're going to talk about uh contract driven development okay so um in order to generate the whole adoc I got them even uh you know produce the uh artifact right um but your plug-in because we added spring rest docs your plugin should be configured yeah oh so you're saying that the uh rest docs should be there but where's the generated dot so we we did not uh do that but what we should do is if you go up you scroll up and you look at your acidoc planets.doc adock if you have the plug-in the scdoctor plugin look at that you'll see that this is what our output is going to look like yep so um okay so what happened there is I guess it just went and found our generated Snippets huh it did it knows so by default like I said it knows where to look so acidoctor is configured with those defaults the only reason we added that generated uh Snippets was we were just being explicit so you knew exactly where to look you knew exactly where uh things were configured so yeah we get that out of the box so now the question is like hey where does that document get generated where is our generated docs so where's our dock um that's the good question is yeah so our generated doc won't like our generated dock the thing that actually turns it into a book uh hasn't gotten executed well because you didn't do anything other than run your test your test generated the snippet we need to do a maven clean uh we need to run the other phase which is I think is generate Docs yeah so Gary doctor so if you do a maven clean package you'll get your docs exactly so um so I want to do a maybe clean package but because I have contract verifier in here if you're doing this with contract verifier it won't work let's comment that out let's comment that out for now so that's fine what we're going to do is we're going to disable contract verifier and the reason why we're going to disable contract verifier is um we're gonna uh contract verifier is going to with rest docs create the stubs and the contracts at the same time um say that one more time contract verifiers are going to create the stops and the test docs the rest docs well restocks is kind of driving the snippet creation uh spring Contra spring Cloud contract has a snippet generator that will generate um from your tests a contract of that test and it will it'll generate a stub from that test so um that stubble will be exactly the same as uh this your stubs will behave in the same way that you wrote your tests minus the documentation portion okay um so what we want to do is because of this normally you would create contracts on your own okay you would normally code a contract in this case we're not coding a contract we're going to disable um oops we are going to disable it um by doing skip so what we want to do is to disable the verifier okay that is the verifier plug-in from looking for contracts and then generating the stubs out of those contracts uh and verifying them and doing all the other stuff um we're going to disable that and we're going to say hey uh spring Cloud contract verifier.skin and that's that's all so now we can now we can proceed with our build so let's go ahead and even package it up okay and let's see Target should have a generated docs yes okay so okay and in that case that's just it's the same thing that we saw earlier it's just you know their CSS is different than IntelliJ Zone CSS right yeah other works yeah okay so that's the planets API uh rest doc documentation um now for the most part that's that's as far as it takes you okay uh it doesn't take you any further than generating a generated docs directory and putting the HTML file in there yep and you can do without what you will yeah right uh in your pipeline uh your path to production uh you might say hey uh after I've done my mavenclean package and I've verified all my tests are working things are passing uh I should have this generated docs folder I want to grab that docs and maybe I I update some uh Wiki or some uh central location that has the documentation for everything or what we did last time was we said hey take that documentation let's throw it back in to our actual artifact let's put it back into the artifact in some uh static HTML uh directory so that when I deliver this artifact to production the docks matched the code that it was tested against well that sounds like a good idea I never get I never get out of sync okay that's what I like that's that's where that's why I lean into this spring rest docs and going back to our earlier question like uh different what about open API spec and swagger like this is uh the plus plus part of that I want to deliver this back I want to deliver all the stuff but I want to make sure that it matches exactly what's happening and if I know I've got these docs I know there's tests that generate these docs it makes me feel better okay so you're seeing that we want to package this with our jar file we want to package this yeah we want to throw it back into our jar file okay in order to do that because it's not it's I don't think it's going to happen for us let me let me check the target I can do it like I can drive on this part okay yeah because we have we have our example that we've done before and this is just kind of my default so I've got I've got an example so I'm going to open up the palm.xml uh and I'm gonna go down towards the bottom uh after the asci doctor plug-in after the spring boot Maven plugin uh what I'm going to do is I'm going to add yep I'm here I'm going to add another plugin uh and this plug-in the group ID is uh no I want the art of activity I don't need to type this out I'm going to just go and copy and paste it yeah I I typically um it's XML man yeah check this out that's that's what I that's what I tend to tell people is like hey look uh like I did it yeah now I'll talk about it I grab the Navy resources plugin what's that do you like daylight I like daylight me too I love daylight yeah uh copy resources so we've built our stuff now we're gonna copy some of these resources we're just copy stuff okay during this phase while we prepare our package so the generate docs is before this phase in Maven uh and what we're going to do is we're going to copy some resources from or this is where it's going to go to from our build directory generated docs which we just looked at I want to throw it into our slash static I could have put slash static or slash public underscore HTML both of those are kind of default out of the box uh options so that's all I need to do so now if I do Maven clean package package is going to run all my amazing phases and during that prepare package it's going to say oh let me go and grab those generated docks and throw them back into my static directory okay oh I'm gonna make one more change because I want it to be visible I am going to go up to our main acidoc we've only got the planete doc I'm going to rename planets a doc I'm just going to rename it to index oh okay uh refactor uh I just want to rename uh oh I can't do it can you rename that planet's adoc to index.adoc yep okay there we go so now instead of a planet.html we'll go to index.html and it'll be at the root so the root of our package the root of our our our server uh that index.html will get uh discovered and then root I am love it uh so now now I think we're ready all right so um all right so we gotta we're gonna package it we gotta get out of here but and and whatever but um so we're gonna package it and um let's just assume that I did clean package right um and then I examined the package and then you saw that oh my God do that again um so we're gonna make a couple of changes here okay uh and I'm not saying that these changes are drastic changes but um we're we're at the end of the ASCII doctor generation portion of this right where we finally compiled the generated document and uh you know we turn it into a uh a jar file and it gets you know uh wrapped up into an artifact right sure xpf uh producer snapshot jar oh that looked good um open that up because we can't see it our our mugs are there you go so we have our we have our amp class static let me just grow up static yeah that sounds good okay so there it is index.html so it's in our drive file now uh so it's under it's under Buddha you know classes static index HTML this is a fat jar uh this contains everything and you can just run this and it'll be fine index.html takes up knows more space than a couple of kilobytes um but if somebody ever needs to see it they can just go in and run it on the other hand if we ran a web server um how about we say um let's not let's not worry about the web server part I didn't say anything about a web server this this how this whole application is a web server so in that case with our computer what happened I don't know I think my computer decided to update okay yeah I'm running Synergy and uh my second desktop is my mouse keyboard and everything else uh so I think Windows decided oh yeah I'm gonna update right now I'm like no you're not no you're not gonna update just I just hit the button okay all righty um so we did restocks we distributed restocks right yep that's good um but there's one more and that's not all there's more oh wait there's more yeah um the oh wait there's more part has to come in and what we want to do is we want wire mock do you know what why mock is are you familiar with larima um maybe but I'm I'm embarrassed to say it because I'm afraid I'll be wrong fine I um you know I've come in contact with lawyer Mark years ago and and recently now um and I forgot I had to like remind myself oh yeah why am I could do a lot of stuff wiremock is pretty cool a lot it allows you to basically write a write a script and that script will be will be your server you know uh so you can write a script for how an HTTP response looks and how HTTP uh request looks and wire monk will just do that um and it'll sit as a server and it'll just follow your orders uh that's what contracts are basically they're they're basically wire mock servers uh contract stubs they're basically servers that run just that little bit of application just to verify the thing that you want it and that's it you know nothing more um so so wire mock is just a very lightweight server that takes instructions uh almost on the Fly and it mocks it and it puts it over TCP um and you know you get the ability to stand up a a test server really quickly and basically validate things all right so what we did was we added the wire mock dependency um through spring Cloud contract because spring Cloud contract uses wire mock to do certain things we're going to allow it to write wiremod contracts as well okay so what we're going to do is we're going to take this consume with right and we're going to say one more let's let's add another consume with foreign and this usually happens what ends up happening is IntelliJ doesn't know that I've included wiremock in it what is the artifact that I am seeing there so yeah I see it too I see an artifact okay well that artifact is permanent isn't it oh nope okay no it's not okay so what happens is um for some reason my intelligent never actually picks up the fact that I put wiremock in here yeah we just got to go like that button and re build our index so what do you do to do to make that work um usually in my palm I scroll up to the top and there's going to be a little Maven button over on the right side but it's not there yeah so the other thing I can do is on the right side I have that Maven tab yeah I hit that refresh Circle uh so it rebuilts the index where do you see that oh there we are reload all righty okay let's see if that worked I hope that worked because before I always had to just quit intelligent uh in order for it to find screen explaining crowd contract uh rest docs and I was always wondering to myself like you know it's right there guys it's it didn't go anywhere um I'm just gonna exit out because that's where I'm at right now um I want I want to address a couple of things here uh says hey I I generate uh jukoko code coverage HTML file using Maven Tesco and go CD pipeline picks it up from Target folder custom location where I asked maybe to copy generator Docs absolutely uh we have a a not fan uh Mill Freedom says wow such a waste of time to watch guys who have no idea how HB body is represented and coded um thanks sorry uh uh and DeSean says Hey remove all compilation errors and Maven install on right side plus clean yes I don't I don't know either um so what we're going to do is we're going to create the DSL contract for this and what will happen is um at the call oh this this comes as a I'm sorry this comes out of the uh argument uh this is going to be a snippet so um web testclient rest documentation.document uh the API call for document says hey give me the identifier and then give me more Snippets okay so we need we need a class we need an object or something that will dump out uh Snippets in order to get to Snippets we have spring Cloud contracts rest docs that will dump out uh Snippets uh so this here um class will return to snippet that does all of the Opera it takes the operations you know it basically um introspects the operation given by my client call my web MVC or my mock what do you call this my web test client and it'll you know create a cloud contract dsls uh for it so we can do that twice we can do it for for this guy and then we can do it for this guy uh so if I run this I'll get what I'm looking for which is just um an extra directory in each one of the snippet directories right remember we have generated Snippets um so what we're going to see here is um we're going to see contracts and so this is the contract this is a contract for ingrubi uh and this groovy contract will essentially get read in by a stub Runner a stub Runner will then uh you know use something like wire mock or if stub run or service to stand up a lightweight HTTP server that represents exactly what this thing here says in contract um and it will let me test it um the stub on the other hand that's the stub I'm sorry this is the contract this is the thing that comes first uh I said that wrong this is the thing that comes first this is the thing that you write in order for you to get a stump okay um but now now that we can just write tests the tests can drive both contracts and stubs so as long as your tests are are correct your contracts are going to be correct if you if you deploy your contract somewhere and other people see it then they're going to expect that this is exactly how it works and if your test is exactly how this works then everybody's good um as far as your stubs go these are your stubs that get run uh with the cloud uh spring Cloud contract stuff Runner and these are you know the same thing it's almost as a contract only this at this point uh it's basically for wire mock um uh Json file that says here's your request and here's your response and this is the thing that actually gets injected into like a wire mock server uh so that it could run and you know take requests and responses in this way now what I want to do at this point is say look at what we have here if you include the stubs from if you include the DSL contracts what you're going to what you're going to get is a little bit more you're going to get a DSL contract in here and you're going to get a um no you're just going to get that extra DSL contract if that makes any sense to most people that's fine but you know um I believe you can do something like Snippets equals and at this point you can just say um which Snippets do I want right so I want my um my curl requests I want my HTTP request and my own HTTP response and then I want my um you know request body and uh response body uh in any order like honestly I would say like put the uh request and response with the bodies um no is that correct while you're doing that I'll answer a couple questions uh farce f-a-r-c-e uh is this about spring Cloud oh man I missed this I'm actually learning about it do you have a repo so that I can learn further please uh yes for you we will make sure that we post our repo uh after the show we'll kind of show what we've worked on that we've all worked on together uh and yeah you can absolutely learn more this is a hopefully a weekly show that we'll be doing going forward called code this is episode 67 uh and yeah it's bring your questions interactive uh we don't have all the answers but we know people that do and yeah join us so uh it'll be saved it'll be uh on the YouTubes and the in the Twitches and all the places uh for you to come back and watch uh from the beginning so thanks for joining Johnny we appreciate your your feedback uh we're here for you Nishan says wow hey we're doing cool stuff and ask the question where does this wire Mark server get injected as in the server will not be part of my application code right no what will be the URL of this Watermark server this is just in the test phase right this is just while we're doing our tests and doing that document generation phase um from maybe so yeah this wire mock will only be uh so the spring Cloud contract will utilize this wire mock in order to generate stubs and those stubs um are basically wiremot code for sending up a server and doing something uh and in this case this wire mock stub is here right hi oh I think there's hold on here yeah okay so am I there all right so yeah this is the wiremock stub this will get injected into something called the stub Runner um but wire mic doesn't go along for the ride with your server no it only goes along for the ride in the test phase and that's it uh it generates this code here uh and this is the stub that we want to generate to actually test later on so let's move on really quickly right um while I'm here I'm going to say okay I have everything that I need uh I have all of my my resources I have all of the things that are are you know generated I've got my contracts I've got my steps now I need them to get out to the world uh I need the real world to see it so what are you going to do um the first thing you want to do is um uh let's see okay I want to generate something you know that has these stubs in it that I can give out to the world because we're not done we're not done with our API right but maybe we've agreed on what this contract is going to be we're going to have our cried endpoints our list endpoints Etc and we want to say hey this is what we've agreed to this is how we're going to implement it because we haven't done the persistence but we're far enough along we're going to say this is what our contract looks like so you can go front end you can go keep working we're going to give you this stub that you can go and run tests against while we finish implementing the back end the persistence tier yeah this is something that um so this is this becomes a you know a thing in which only tests are basically driving your your your documentation so test for driving everything here uh production doesn't really Drive much uh if you change production in the way that test breaks then your contracts break everything breaks right so the idea here is tdd up front it's test driven development it's you know I have yeah first uh my tester and basically the uh our bro brokering the um the actual uh you know conform Conformity of your of your production code um and everybody else who sees your your contracts are going to see basically understand how your tests will work too because your tests again are driving uh the creation of your contracts and your stubs and your documentation um so you know production must follow that specific you know test obviously okay um oh so here's the information Sean says understood I'm going to try this tomorrow morning okay so here's awesome here's what we're gonna do we're going to use it maybe an assembly plug-in I hate saying this um no I like saying this but I hate seeing it at the same time we're going to use the maven assembly plug-in uh there may be an assembly plug-in is going to create another jar file and that jar file is going to contain um this green Cloud contract stubs okay it's going to create another draw file that create that contains just the stubs and some code or maybe the source code or whatever you want really um but in this case we're going to we're going to plug it in here we're going to add another plug-in um so let's let's just go ahead and add the assembly plug-in show you what that looks like I got a question yes could we I'm just throwing it out here could we instead of what I've typically done in the past and I'm just again thinking out loud uh what I've done in the fast in the past is I've made that additional jar file out of the same repository and basically in my pipeline I was creating two artifacts I was creating an artifact for my server my API and now it's also creating an artifact that delivered the stubs but hear me out could I generate the jar file and then put the jar file inside of my static directory so that if somebody went to the documentation oh here's a stubborn or grab it grab the step burner that that we're compatible with um what would that what would that feel like that would feel good I know where the problem is because the problem is we're not in production yet we're not production yet right so how would I get that out there right yeah this is uh yeah stubs are okay yeah exactly so what your question was can I take a production jar file and then run the run against those stubs and the answer is no um and this is why because your your stubs are supposed to gate production right so you're not supposed to do anything until everybody agrees that the stubs work uh so therefore you would never see a production jar file until those stubs are have been validated that they are indeed the correct way of running right okay so what we're going to do is create the stubs jar file here using Maven assembly and uh all it's going to do is we're going to configure Maven assembly um this way so Maven assembly takes a stubs XML file for its configuration and that lets me tell it what I want to put into the jar file okay so the next thing I'm going to do here is I want to create a source main or actually I think it's Source assembly and then I'm going to create a file called stubs.xml I almost said stubs.jar and I have XML already in my paste buffer so I'll go ahead and paste that XML in here um let me just make sure because we like daylight and uh and this is what we're looking at we're looking at somebody who wants to include a bunch of stuff into that jar file whether it be the source code directory uh whether it be the classes files and also uh the stubs themselves so that all the stubs are actually included um and for for a good measure you can include contracts now uh this comes from directly from you know one of the examples out of spring Cloud contract and so it includes everything it's all inclusive not everybody wants to include um you know classes with their stubs so that's not necessary not everybody wants to include Java files with their stuff so that's not necessary either but just because you know we want to create the idea that you can include everything here um this will be it so with the stubs file I can go ahead and say all right so now that I have my stubs now that I generated contracts I can go ahead and say maybe clean uh install um and what that's going to allow me to do yeah what that's going to allow me to do is go into another project and then test those stubs and that's even simpler because it's just going to be a stub Runner uh and that's it nothing more awesome and farce says yes this wire mock server is a new thing to be but is this proper proper industry standard to include such a thing in Cloud projects I think this is just for testing yes this is just for testing this is just something that gets initiated in our testing phase while we're validating our code and generating our documentation dinner stuff that's the only place where that my wiremock server exists um now let's see let me show you guys what happens here so Cloud contract did its thing it uh and so did restocks it did its thing um we have two jar files so if you notice we installed uh the actual producer the production drop file and we produced the stub shark file as well so the stuff jar file is in here uh and we want to test it um so I want to know what the heck happens if I wrote a client uh that did this right so that's simple um it's even easier um we can go ahead and create something called a consumer um we actually don't need restocks here we don't need contract verifier because we're on the other side now um we do want the reactive what because we want what we want the web client itself so we're going to just still include blood flux but we're not gonna you know we're going to go into the guys of I just want one component okay um but we want as well is the contract stub Runner uh stub Runner allows us to pick up that jar file that extra jar file and then run code against it so this is the consumer um okay stubs consumer ate and then go into the previous directory and zip it create a new window and there we are okay so so now we're on the client side yes so now now we're on the client side um and so what we're going to do here is simple very very easy is one two three we gotta open up a jar button I'm just kidding we have to do all that uh I like to say like back in the day when I was just a coder uh working on like enterprise software we used to break open jar files and add things and change things to them uh these days we don't do that anymore thank God you know um okay so what do I want to create here I want to create a application that is um consumers all the consumer stubs um let's say at Spring boots oh is this kotlin uh it could be cool I created a kotlin uh I created a kotlin I don't want to confuse you guys I know hey that's fine like we're calling friendly like it's a client it's some other team that's going to consume yeah this is great keep going okay web environment none uh so we're gonna say hey I don't have a web environment we're not we're telling you actually not to uh yeah okay oh come on yes 1.8 beautiful okay I hope you're happy okay okay so we're telling it not to start we are telling it not to start a um and just to get out of here kotlin don't do this to me Colin okay um so we're telling it not to start a web server because the web server is going to get started uh and it's going to get started through this guy here Auto configure um stub Runner um and then step Runner is going to do a couple of things first of all we have to tell it what stuff are you talking about what stuff are we giving it right um and in order to do that we have to know about the spring Cloud contracts um I guess locator format and the locator format means I give it an artifact so this is common example uh that producer I believe is uh the group name uh and then the actual artifact name is producer and then the version is plus and then the port that we're going to execute those stubs on uh is 8080. so we're at the end of this is um the spring Cloud contractor is going to create a um it's going to start it up and it's going to listen on that Port okay and then what we want to say is stubs mode uh stubs mode is the way of standing up the server that is locating it where is it actually at is it is it local is it in a GitHub somewhere is it is it a cloud what is an artifactory or where is it like how do I do it so what we say is stub um yeah Runner properties dot um stubsmode dot local right so now we're telling it hey it's just going to come out of our DOT mq directory right that's it um so so nothing too too hard over there uh the next thing we want to do is we want to say uh we want to write a test and that test should do something like this void uh should get Finance uh because that's going to test our uh oh this is a huh how about I love this fun common baby uh should get all planets okay so what do I want to do I want a web client right yes okay um how do you build a webcam do I is it can I just Auto configure one I'm sure Auto uh Auto Wire One auto wired otherwise what plant um or do I want to unlock a client uh we're doing kotlin so I don't know if not my head yeah oh and kotlin in order to get a variable man it's been a minute since I uh is lazy or is it um wow uh oh it's actually a VAR um web client on the web client lazy late uh okay yeah it's late in it okay so uh late in itvar allows you to do that in kotlin because uh essentially it's everything is public vinyl or everything is final unless you make it a lading at barring which it's not initialized at first I mean spring now has a chance to wire it in using late in it otherwise it's just going to complain and you're you're not gonna like like the way it complains uh so we could say get and uh we can say URI and we can say uh HTTP local hooks only ab80 slash API slash Planet slash um and then uh we can say hmm hmm let's change to fly to Mono or I think it's a flux because it's a list of things so yeah so uh what I want to know is am I going to buy an exchange but we returned a list we didn't return a flight okay right we didn't return a mono of the list or we didn't return a flux of list all right a flux of objects we just returned a list and it should just come out as a mono uh in the background that's supposed to do the right thing and just say hey this is actually going to be a model of a bunch of stuff uh and so that's it so we'll just say Okay exchange to Mono um and so this is a client response so it's res ident or how about body extractor and create exception headers a lot of people which is really spotty to entity and that will be planet and this also means that we need to write a planet all right extract this upper file tell me you put you put it into uh production nope it didn't we're going to move that in production in Factor so what we have here is I probably could just be like data class Planet uh and planet's going to be what it's going to have an ID um along and then it's going to have a name and that's going to be a screen right I think that's about it so the data class that contains two items in it and that should be uh um okay now uh client response so response Handler has the following thing uh where is to entity uh can I drop it really one point at you guys oh you guys yes okay uh kotlin's it's it's um oh it's probably it's it's uh it's it's that other thing it's it's project structure um yeah so uh modules I'm at language level 17. guys what's going on SDK uh let's see kotlin SDK uh what are we looking for home pal uh-huh oh [Music] uh okay uh it's okay why it's it's just giving me issues about compilation I haven't used kotlin in like days or months already you know what pause just go back let's just recreate it we'll create it as a really cool Java project it's actually it was Java click to click uh well because you called it dot kotlin oh what so wait are you saying that oh oh maybe uh so it wasn't a kotlin project after all oh this was a Java project after all it's no wonder it's freaking out okay I just created I just did the wrong thing here uh to uh okay we'll just call it consumer subtests uh we can just take this stuff out of here yeah that ought to work okay goodbye there okay so we'll just change a couple of things here this needs to be a curly braces and uh and that's good right homie this is a Java file yes foreign tology do some things this is how we work right this isn't a scripted show like we're not we we set the expectation I hope that uh this is just how we code uh we didn't come in here with the script that hey this is gonna work perfect and hey we practice demo no no we're thinking out loud we're learning from each other hopefully we're answering some questions along the way and yeah sometimes it's just easier to just wipe it hit refresh right yup okay all right so let's do this again guys all right my bad there um so what we're gonna do is I guess write some more tests and uh just run with the subrunner how about that how about we just do like one stub Runner test and we're good uh let's just call this one uh press um how about planet star tests yeah Planet stuff or it could be Planet API test it could be whatever you guys want though uh in this case we're going to say uh spring boot Fest um uh web environment equals uh screen improved test dot web environment we don't want that and uh we want to say uh Auto configure [Music] um example uh at McDouble restock is the name of it the rest stop uh colon uh producer pull in possible in 8080. okay so that should do the right thing there and then we can say um foreign properties thank you all the complete you're so awesome okay uh the next thing we want to do is create a web um the next thing we want to do is create a call out excuse me we don't want to create a web we want a call out so we need a web client in order to get the web client uh we have to inject a web client uh so let's let's get our web client out and uh Builder let's just build a web client simple [Music] client the client uh client dot Builder dot um build come on there we go um that works test um avoid planets there's no arguments here [Music] and the next section I will figure out if it is possible to see do I need a step verifier for this I'm going to need a step verifier all right wait a minute so this is this is probably like what will happen is I'm going to use one client to talk to the mocked server and I'm going to validate it like a note did a test like if I wrote an actual client for instance my client will be backed by a web test by a web client not a web test client because that's that's MVC or web Flex this is not web Flex this is wiremock so I'm going to need to talk to it with a regular HTTP client the what client itself suffices as a standard HTTP client so what I can do here is just create the call out um get the data so I'll create a stream I'll say like um uh publisher of um I can say actually how about a mono um and that doesn't sound right I don't like the way that that's going to work I don't want you I don't want to say a mono for a list of something because that gives me the heebie-jeebies what you would normally do is just say something like um um let's just go with the call first but uh that URI 8080 um slash API planets slash [Music] because I don't have the actual class right so no Finance Plus right so I don't have this yet um let's create this in production yeah what did we call this before a record uh we yeah we did we made it a record okay why don't we just copy and paste the record you know what last time yeah you could do that last time uh we we did it different on our implementations like hey we did uh a class on one side we did a record on the side it's okay because our message converters are gonna uh convert US to Json anyways where she realize it to whatever we decide uh so either way both are valid options okay no I hate this right here don't hate it it's okay look at this okay oh oh we'll upgrade later uh okay so what that should be really is a flux um this should be a flux um this shouldn't be a mono it will be on the next version yeah on 0.0.2 will will make it a flux and we'll do all the things reactive let's just make sure that we we still it thinks hey yeah you got a lot of these things that's gonna maybe I don't know uh let's find out what happens well we're going to get an error anyway here most likely uh just because um we're still I'm flexing I guess is that is that the correct word but yeah yeah let's let's go with it okay for something like step verifier um and you know reactive programming isn't even necessary for this we don't even need web plexus we could have just done this with straight up rest docs uh I mean rest and you can just skip the web plug stuff because testing web flux is a little bit more uh involved since you're dealing with the event Loop okay um so what we'll do here is we'll create the uh we'll let it subscribe you know to planets which is our extreme up there um and then we'll just expect um next and uh let's see oh I didn't expect next and uh new Finance one L I'm a Jupiter trying to connect new planet to uh what what was the actual thing I'm returning uh that's the thing because I have to look at the contract and find out what it wants I'm pretty sure the first one with Saturn have been second one was Jupiter so let's just say Saturn looks first and Jupiter was okay uh let's go back to our contract here uh generate Snippets and contracts um so yeah the first one will be id1 Saturn id2 Jupiter right uh and that's what the sub says too all it says uh yeah I'm going to return one Saturn to Jupiter okay all right so we did that right I'm gonna do a quick time check here we got about five minutes left in the show if you've got questions go ahead and get them in the chat ask your questions uh we'll be happy to get to them if we don't get to him today we'll get to them next time uh expect to see us next week at some point oh and my five minutes is up but yeah please hold High hi okay so that's it uh so what do we do there uh we used a verifier to actually talk to our web server uh using the uh web test you know the web client um and what did I get 404 because I didn't uh I said HTTP get a localhost 8080 um expected actual on error report um fine that should be the thing that we say slash API slash planet foreign that was correct and what did I do here um okay I'm gonna do something else hold on you guys okay so in order for this to actually to work um let's take a look at another test and and a test type uses a rest template I don't feel so comfortable using a web test client or not web test client but the uh the whole entire stack of reactive to do a test so what we're going to do here is just say oh look I have a test here I have the same test same exact one here um I get to comment out some tests that I don't have or that I don't need this is a pre-generated one this is one that I created like maybe a few days ago um it did the same thing only uses uh rest template rest template is actually um going to have a little bit more uh forgiveness in terms of you know type return I might not be returning a flux of something and I actually want a mono of something I don't know how to clutch with that at the last moment here so what I will do instead is I will say I have a stub Runner um I will create another stubborner test and that stubborner test is going to call um this is called a producer of stuff's test um so so what I did here is I'm going to go into another project and use rest template because I feel a little bit weird about using uh you know what flux it takes a lot to actually use it and kind of get into it all so what we'll do here is we'll say uh test um avoid should get all planets and then what I should do here is actually just go ahead and copy and paste good old copy and paste um because you know you should never go a day without copying some code it benefits from chat to GPT I don't care where it's coming from nobody's looking uh the coast is clear uh don't worry we've got your back uh AI won't take your job today today so address template is actually going to be created using a red template Builder uh template equals Builder uh Dot yes I'll build okay okay so now we have a rest template and this guy here it was an exception so we'll say gross exception all righty so if you notice there are a few things that are different from the last time um let's let's say that uh API slash uh planets flash okay is and it's at port 8080 instead of 90 90. um and it takes a planet.class let's just go ahead and call it a record and uh I have an idea how about that I like that idea actually okay so it doesn't matter I just added that for no apparent reason um so go back to our producer of steps test now we have responsibility of string oh we can't have a responsibility of string we have to have a responsibility upon it uh and now we have uh assertion so we can just assert basically basic things um based off of what came out of the body so um if res like dead body is going to be a planet then it's not mole and has no no fields or property which is probably a good idea um and you can say like has field oops field or property with value and you can say like um uh the field is going to be uh hmm it should be a field called uh ID but in this case we're going to have multiple Fields so I'm not going to be able to stipulate oh I have a field that is on um on you know uh already one I'm not going to be able to do that here so let me go ahead and make sure that this either works or doesn't work I don't have any time left but uh you kind of get the gist of what I'm doing here as I'm saying oh rather than um uh calling it the server directly insteading up that server as a test I'm just starting to get the stub uh and so that stub here is response type uh class Planet content type application from Json yeah that's my HTTP connect to serialize this value from an array oh yeah okay so because of time let's do this let's jump into it we had a couple of questions uh rest templates certainly deprecated I don't like it's deprecated yet I think we've just recommended that you move to the web client yeah but I'm not sure I don't see much difference yeah there's not much difference but definitely move uh in this direction if you can if and when you can but there's a lot of people haven't really uh upgraded right we got it we gotta think about the whole Community it's a massive community um we need to use flux versus mono uh I've seen some codes where people are using mono just like this monolith like we just did uh and that makes sense uh windy sucks versus mono like how is it different how is the mono list difference from a flux list I think we answer that uh maybe we had a typo here at slash planets uh with two ends uh Johnny thank you for sticking with us through the whole show uh we I appreciate it uh but also a monologue return all the information at once correct uh while flux is continues data flow yes blocking versus non-blocking uh and having that come as a stream if you will uh mono uh only one or zero element and flux is zero or as many elements yes uh thank you guys for all right this is the community answering the questions along the way in this case the same but if you're working with other reactive components and you turn a mono you might not retrieve the whole thing because it just finished at that moment yes correct thing because I wasn't sure if I can suss out like uh okay are we gonna return a flex or we're going to turn a mono of a list then I have to throw in a parameterized type reference uh for that and I'm thinking okay that's probably not going to work correctly uh at least the way I see it uh in this case I'm still returning a list uh but now what I'm doing is I'm grappling with the idea of uh telling the API hey I want to extract something out of a list um and then I'm getting an error based off of this which is saying hey um I know you have a responsibility of a list of planets but um I I don't have the correct you know information needed to to know what this is actually going to be even though I said a list of planets um so I will need to um just look at that really quickly I have a friend that will do this and why are you doing that I'm going to set up our next show uh hopefully we'll do the same thing next week we'll pick up uh hopefully this was valuable let us know we're on Twitter uh or or LinkedIn or the emails or whatever uh we're all available we're here for you uh if there's something you'd like to see us do on one of these sessions please let us know thank you all for joining uh but as far as I I think I think it'd be fun to kind of pick up where we left off uh on our next show and have some things kind of move forward a question here hey do you have some sort of group or Community where we can discuss more Twitter's a great place I'm also on on Mastodon we're both on Mastodon uh we like stack Overflow uh if you're you're there we're there answering questions uh email if you have email my email is DeSean deshawn.com so just like it is down at the bottom uh shoot us an email uh but we're here for you there's also a Twitter Community uh for spring developers over on Twitter uh there's we're here on YouTube uh all the places so uh evening midnight it's here it's fun to watch you again thank you so much for joining uh good morning you know midnight for some uh it's morning for others We Appreciate You Johnny thank you so much for hanging out for the show uh thank you you're very welcome Victor you're very welcome uh no say English uh I apologize uh I'll have to work on that uh uh uh uh I I can't even think of how to say uh I'm sorry Los siento lo siento there oh we'll get that figured out uh thanks guys uh we appreciate you uh hello everyone in chat uh and you don't have to reach out to us uh you have each other like uh our chat group has done a great job of answering questions as we go uh feel free to reach out when you can uh but we're here for you uh yes and there's also a spring developer community on LinkedIn uh so yes we have tons of places yes uh we appreciate you uh sorry hey thanks everybody uh is there anything else you want to you want to wrap up close it up um actually no um all right so we went through everything here right yeah we got to the stub Runner but I just said oh yeah crap yeah we got our stuff Runner like and we we delivered our stubs uh and maybe next time we just pick up and let's just consume some of those stubs and do that client-side maybe reactive uh but do the client side uh we should probably make a reactive API uh first we'll update a reactivate API and then we'll consume it with a reactive client so um so yeah the reactive web apis for the web are are very specific you have to use the verifier and um well that that takes a lot more explaining than just your Good Old rest template we have all the time in the world we have all the time but we're not the only ones doing this yeah we're not the one we're not the only ones doing this let's let's get through it and we'll do it live and we hope to see you all with us thank you everybody thanks so much bye
Info
Channel: SpringDeveloper
Views: 2,431
Rating: undefined out of 5
Keywords:
Id: EKBgAgmGywc
Channel Id: undefined
Length: 126min 13sec (7573 seconds)
Published: Wed Jan 18 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.