Building web applications in Java with Spring Boot 3 – Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Learn how to build web applications in Java with Spring Boot 3. You'll learn about Spring's fundamentals by creating a REST API that communicates with a database and is supported by a comprehensive suite of tests. By the end of this course, you will have learned what you need to start building your own web applications with Spring Boot 3. Dan Vega created this course. He is a Spring Developer Advocate, Course Creator, and Speaker. Welcome to this course, Building Web Applications in Java with Spring Boot 3. My name is Dan Vega. I'm a Spring Developer Advocate at Broadcom, a Java champion, and really excited to be here with you today on this journey. So I want to start off by thanking everyone at Free Code Camp for having me. I'm a big fan of Free Code Camp, and I'm a big fan of the courses that are on the platform. So I'm excited to be a part of that. So today, we're going to go on a journey together and learning the most popular Java framework around for building applications, and that is Spring. Spring is massive. There are so many things that you can do with it. We're going to kind of narrow it down today, but we're going to have a lot of fun. I will go ahead and leave some links. If you want to learn more about me, danvega.dev is my homepage. I have a YouTube channel, so if you enjoy videos around Java and Spring, you can visit me there. Also, if you want to learn more about Spring and continue this journey, I'm an instructor on Spring Academy, which has a bunch of free resources for learning Spring. So go ahead and check them out there. With that, I don't have any slides. We are developers. I have a GitHub repo with a readme in it. So if you head over to github.com slash danvega fcc for freecodecamp dash spring dash boot dash three, I'll leave the link in the description below. That is the repo for all the code that we're going to go today. But more importantly, the readme that we're going to jump through right now. So there's a quick agenda on here. I don't want to dive too far into this because we'll talk about that as we get into it. But module one, just a quick introduction. I want to make sure you understand who I am really quickly. What are the outcomes? What are the prerequisites for this course? What should you know? And then a real quick intro to what is Spring? Why should you care about learning this thing? Module two is we're going to create the project. We'll get familiar with the IDE and how to run the code and where to put your code and how to write the code and some things like DevTools and logging. So that'll kind of get us started, get our feet wet, get us off the ground. Module three is, hey, we're building a REST API here today using Spring MVC. We're going to do this in memory. We're not going to talk to a database yet. We'll kind of again walk before we can run. And we'll talk about all the mechanics to build the REST API. From there in module four, we'll switch over our in memory collection of things to a database. So we'll talk about all things related to setting up a database in Spring. Module five is talking about the REST client. If you are in a Spring application and you need to talk to another service, this is something we have to do in a lot of organizations. How do we do it in Spring? What are the different options? How can I use them? Finally, module six is testing. Now, I know we don't usually save tests for last, but I feel like when you're learning something new, trying to throw in the mechanics of writing tests at the same time can be a little bit overwhelming. So normally, I would write a particular class and then write a test for it, kind of TDD-style, if you will. In this case, we're going to write the application, and then I'm going to come back and talk to you about what's included in Spring for testing, which is nice. You don't have to opt in. It's already there. And we'll talk about some of the tests that I would have written along the way just to give you an idea of how to write tests. I'll leave you with some resources, and that'll be the course. It's a lot of information packed into a pretty nice time, but I think we're going to have a lot of fun with this. So quick, who am I? I'm a husband and a father. I have two daughters, hashtag girl dad. We live outside of Cleveland, Ohio. I am a Spring developer advocate at Broadcom, so I get to go around and talk about Spring, but I want to make sure we understand that I have been an advocate of Spring long before anybody was paying me to do so. This goes back years. I've been a big fan of Spring. Spring was previously held by Pivotal and then by VMware. VMware got acquired by Broadcom, and that's how I got to where I am now. I was recently named a Java champion, which is really, really exciting, so I'm super proud of that. I am a Spring Academy instructor, so we have a Academy where if you want to learn all the different things with Spring or about all the different projects in the ecosystem, we have many instructors on there, other developer advocates, members of the Spring engineering team. So if you want to learn more about that, head over to Spring.academy, and I've been doing this a little while, 23 plus years of development experience in various languages, most of which have been on the JVM, but I've been doing this a long time, and I enjoy what I do. So if you're going to take this course, what are some prerequisites that you should have? Well, first off, we should have some fundamentals of Java. We need to know the Java programming language to build Java applications. I would say anywhere from beginner to intermediate. Beginner, if you really are able to learn on your own, great. Just some fundamentals of the Java language. So we need JDK 17 or more. Right now the current version is 21, 22 is about to come out. 17 is the baseline for Spring Boot 3.0 apps. We're going to use the latest version, which at the time is 3.2.3, but we need at least JDK 17 to be able to run these. You can go ahead and check your current version with java dash dash version on the command line, or you can check out SDKman if you're on macOS. It's a nice little utility that allows you to install different versions of Java or other SDKs and manage them in parallel. So I can switch between like 8 and 17 and 21, etc. Now, I am using macOS, so if you're on Windows, I don't have the equivalent of all these, but like SDKman, you can use something like Chocolatey to install, but some of the keyboard shortcuts will be different. I'll try and explain those as we go. If you have questions as a Windows user, try and ask them, and I'll see if we can answer them. So if you're a Java developer, you should have some a little bit familiar with some build tools. So once you get past kind of the hello world in Java, you need these build tools to to manage your application, right? Like, hey, these are the dependencies that my application is going to have. These are the build plugins, like the steps I'm going to take to like build an artifact that goes to production. Two of the big ones in the Java world are Maven and Gradle. I'm going to use Maven. If you want to follow along and use Gradle, that's great too. You need an IDE or a text editor. I'm using IntelliJ IDEA Ultimate Edition. It is a paid version. I pay for this. I have paid for this on my own monthly. Well, now I think I pay yearly, but at the time, it was monthly. And for the value of me of how productive I am in this tool, it wasn't a lot. They are not sponsoring this video. This is just my personal thoughts on this. But there is a free version of the Ultimate Edition. So the paid version, you can get a 30-day trial. If you've not done that yet, go ahead and do that. There is a Community Edition, which you can use, which doesn't have all the features, but I'll try and point those out as we go. You can also use something like Spring Tool Suite that is available in Visual Studio Code and Eclipse. One thing I try to tell everyone that I talk to when I'm teaching is to use whatever tool you're most productive in. If that is somehow notepad or a terminal with Vim, so be it. I want you to be productive. Whatever tools you use to be productive, that's great. This just happens to be the one that I'm most productive in, so I use that. We'll need an API testing tool. So if you've never tested a REST API, we'll go through the mechanics of it. But there are tools like Postman. You can do this on the command line using something like Curl or HTTP IE, which is like Curl for humans. You can actually use it and read it and understand it. IntelliJ Ultimate Edition has a HTTP client built in, which I'm a big fan of. I'm going to leave you in this repo in the API folder with the Postman collection and the HTTP client collection for IntelliJ. So whatever one you're using, you should be able to download the collection and not have to write all these API tests yourself. Docker Desktop is not a hard requirement. We are going to use an in-memory database until a certain point, and then we'll swap it out for a Postgres SQL database. But we'll do so using Docker and Docker Compose, and some of the features in Spring around Docker Compose, which are really great. I'm excited to talk to you about those. So that's our prerequisites. What is the outcome of this course? So a lot of people ask me, like, how can I learn Spring, Dan? Well, that's a big loaded question because Spring can do so many things. We're going to look at that in the next section. Spring can do so many things. So when you ask me how can I learn Spring, boy, you better have a long time because of just the roads that you can go down. But if we narrow down this road and we get a little bit more laser focused and you ask me, hey, Dan, how can I learn Spring to write a REST API that talks to a database? Now we have a much more focused learning path, and that's what we're going to do today. We're building a REST API. It talks to a database. I'm going to teach you some of the mechanics around that, some of the things that I've learned over the years, some best practices. We'll write some tests as we saw. And yeah, we're just going to learn a whole bunch of those things. So what is Spring? What can it do? What can it do? We'll talk about that in a second. How to build a web application, how to test it, how to interact with the database. What are we going to build? We're building a fitness application that allows you to track runs through a REST API. That's not the important part. The important part here is to take what you've learned and apply it to your own project. After you're done with this course, you really need to go through the mechanics of doing it yourself and not relying on me being able to tell you what to do. So take this and apply it to whatever you're interested in. If you like cooking, create a recipe REST API. If you like lifting weights, go ahead and create an application like that. So whatever you're interested in, try to apply this after we're done here. And then I think that will kind of really help cement some of the things we're going to go through. What and why is Spring? So I'm going to click on this link. It's going to take me over to spring.io. This is the main website for Spring. We'll get into why in a second. So what can Spring do? Spring allows you to build so many different types of applications. Do you want to build micro services? So you have a bunch of services in an organization that kind of talk to each other. There are some really great benefits to building microservices, big buzzword these days, right? Independently scalable. So if we have one application that just needs to scale more than others, microservices are great. You can build reactive applications, so non-blocking applications. So we know in kind of the Java world where we have this thread per request, we want to be able to not block our applications. We want to be able to scale better. That is the case with reactive web applications. But JDK 21 just came out. There are these things called virtual threads. So if you're in a blocking style application, there are ways to kind of scale those applications now as well. Cloud is big. We talk about, and actually I wonder if we go into Spring Cloud. There's a video that we recently did, and I'm going to just jump there now. So if you go into projects and you go look at all the different projects in the ecosystem, here's Spring Cloud. There's actually some videos on here. We did a Spring Office Hours video. So this is a podcast that me and my co-worker, Deshaun, run. And we did a video where we kind of talked about all the different projects in Spring Cloud at a high level and what they do. And this was really fun because we talked about Spring Cloud as basically the tool to build distributed applications in the cloud. And when you're doing this, a lot of common patterns are going to come up that you're going to need to handle. And Spring Cloud gives you the tools for doing that. So that's Spring Cloud web apps. That's what we're going to focus on today, building an MVC application that talks to a database. You can also use Spring for building serverless applications. Hey, I want a function to sit on AWS Lambda service. And when I send it a request, it will spin up, handle that request, do what it needs to do, and then shut down. We can work with event-driven applications. We can work with batch applications. So much more. Another thing that I don't see listed on here that I've been using Spring for a lot more lately is building CLI apps. So if you want to build a CLI, you might think, well, I would reach for something like Bash, Dan. And that's great, but I don't use Bash every day. So I forget how to even do the simplest of things. So I would be running over to chat GPT and asking chat GPT, how do I do a for loop in Bash? So with Spring CLI, I can build those interactive command line applications using the tools that I'm familiar with. That's a little bit of what can Spring do. If you go into Y, here's some great information on it. Again, it's the world's most popular Java framework. Here's a really good quote from Bix, Sporting Goods. So we use a lot of the tools that come with Spring Framework and reap the benefits of having a lot of the out-of-the-box solutions and not having to worry about writing a ton of additional code. So again, we're starting with a web app, but what if you need to talk to a database? What if you need to build for the cloud? What if you need to build reactive web applications? All of those tools are in the ecosystem here. All of those projects are here for you, and they all integrate seamlessly, which is really great. So Spring is everywhere, flexible, productive, fast, secure, supportive. Again, what can Spring do? I think there was another quote on, yeah, this is a good one. So if you don't know, Netflix is a huge Spring user, and it says, most of our services today are based on Spring Boot. I think the most important thing that Spring has just been very well-maintained over the years. That is important for us in the long term because we don't want to be switching frameworks every two years. So Spring has a huge engineering team. We have releases on the Spring Framework side every year. On Spring Boot, we have releases every six months. And yeah, I think that's an important piece. So thanks, Paul, for that quote. So you can go into why, learn about that here. You can go into learn. You can learn like an overview, how to get started quickly, but we're going to do that today. There are some really good guides. These are kind of quick 15-minute to 30-minute, how do I do this one specific thing? So those are great, but I'm going to show you those on Spring Academy in a second. There's a blog, so get caught up, stay caught up with what's going on in the ecosystem. And actually, I think if I go to overview, yeah, so here's the latest videos. Our Spring Office Hours is one of the latest videos on here. Josh Long, who's a legend in our community, has a podcast on Spring. You can go ahead and check that out. Here are some popular guides. Projects we'll come back to in a second. I mentioned the Spring Academy. If you go over to Spring Academy, you'll see that there are some courses there. We also have these guides. These are the same guides that are in Spring I.O., but not all have been ported to the Spring Academy yet. The nice thing about these is that you can do this in the browser. So this thing, I want to build an application with Spring Boot. You go through and there's an integrated lab environment where you can walk through and do this yourself here. So really exciting. Check out Spring Academy for that. Then we have solutions. So if you want to get support at a commercial level, check out the Tanzu Spring runtime. We have some community and even that all important dark mode. So quickly, we're going to go into projects. We're going to click on the overview. These are all the different projects in the ecosystem. So when you go into a project, you'll be given an overview. You'll be given a learn section. This is where all the documentation is. So here's the reference docs. Here are the API docs. If you want to get at the APIs, that's important. And just as important, the support timelines. What is the open source support? What is the commercial support timelines? So I'm going to go to Spring Boot. We're going to be going through Spring Boot today. If you go into the learn section and you go into the reference docs, here is like, hey, how do I get started with Spring Boot? So I can go in and click into a section, get started. These are some of the things we've talked about before. But just documentation is really great. One of the things about Spring that you have to know is that it's been around forever, right? We just celebrated 20 years of Spring, 10 years of Spring Boot. This is really great, but it also means that if you go out there and search for a question on Google, you might get 10 different answers. And how do you know which one is up to date? Which one is the right one? So I suggest first line of defense is always starting at the documentation because this is constantly being updated. This is being managed by the Spring team. This is a really good place to start. All right. And then there's some resources here. I'm going to update this. The reason I wanted to do this in a README is so we can constantly update this and help you out. I'll put some notes in here. If I see issues come up, we can go ahead and add those to this repo. This is kind of our home for everything that we're doing today. So that was our intro. We're calling that module one. Module two is going to be getting started, creating your first project, writing your first code in Spring. And I think we'll go ahead and do that now. So I really hope you enjoy this course. I think we're going to have a lot of fun on this journey and I'm excited about it and I hope you learn a lot. So with that, let's go ahead and head to module two. All right. So the best way to kick off a new Spring Boot project is by using the Spring initializer at start.spring.io. So I'm going to go through a couple options here. We're going to create our first project and then we'll go ahead and write some code. So we start off with what is the project type? This is what is the build tool. So I mentioned in the prerequisites that it'd be nice to know if you had some experience with Java build tools like Maven or Gradle. And this is where those come into play because you need to pick a project type. I'm going to choose Maven. If you want to choose Gradle and you've used that before, there is nothing wrong with that as well. In fact, it's the default. So language, I'm going to pick Java. You can also use Kotlin or Groovy. And then we need to pick the version of Spring Boot that we're going to use. I recommend using the latest stable version, which at the time of this recording is 3.2.3. You can always upgrade this in your application, so don't worry about it. Just pick the latest stable if you want. So now you're going to fill in some data about your project. And the way this works is you have a group and an artifact and you usually use the reverse domain. So my personal website is danvega.dev. So I'll use the reverse of that, which is dev.danvega. And then the artifact is what are we building here today? What is the application called? So in this case, it's called runners. And we'll go ahead and use that name. You could fill in a description, a package name, anything else is fine. Now you got to pick a version of Java. So we talked about at the beginning to use Spring Boot 3. You need at least Java 17. I'm going to pick Java 21, but I don't think you need to. So if you're on Java 17, that's fine. Now we get to the point where we pick our dependencies. So what are dependencies? So when we're building out bigger or larger applications, enterprise type applications, they're usually made up of a bunch of different projects, right? It's not just like Java code. There is, hey, I need to like, use this project and use that project and use these two projects. And that's how you kind of build these larger style applications. In the world of Spring, Spring has a bunch of different projects in the ecosystem. And it will allow you to kind of construct your application. I liken this to going to the grocery store, having an idea of mine in mind of what you're going to cook tonight, right? If I'm going to make a steak and potatoes and a glass of wine, like I understand the ingredients that I need to get as I'm going into the store. So as we're coming here to the start.spring.io, I need to have an understanding of what I'm trying to build today. Remember, Spring does all of these different things. It can build all these different types of applications. So I need to have an idea of what I'm trying to build here today. And we do. We're building a web API today. So we're building a Spring MVC app that talks to a database. Now, the nice thing is these dependencies are just kind of quick starters, like it encapsulates all the functionality of, say, building a web app. But you don't need to know everything you're going to do today. For instance, we're going to talk to a database at some point, but I'm not going to pick the data stuff yet because we're not there yet. So when I go into dependencies, I'm going to search for web, and I'm going to choose that. The other one I'm going to choose is the Spring Boot dev tools. And this is some really nice features for development mode. So we're going to choose those. And that's all we need. From there, I want to show you just a quick, a quick couple of things. You can go to explore and see what code it's going to create for you. Again, this is more of a bootstrapping your application. This isn't generating code based on what you're selecting there. So there's that. Then there's a share button. If you want to go ahead and copy this, you can send this to someone else, and it will pre-populate the spring initializer for them here, which is really nice. So with that, you're going to go ahead and click generate. You're going to generate that. It is going to download a zip file. You're going to open that up in whatever text editor or ID you're using. Again, as we talked about at the beginning, I'm going to use IntelliJ Ultimate Edition. You can use IntelliJ's Community Edition. You can use Visual Studio Code. You can use Spring Tools Suite with Eclipse. There are a whole bunch of different options here. But if you haven't downloaded a version of IntelliJ yet, there's a 30-day free trial for the Ultimate Edition. So I would go ahead and do that. But either way, let's try and follow along. If you have some questions or you're stuck on this part on how to open a Maven project in a particular text editor or ID, let me know in the comments, and we'll see if we can answer that. So with that, I'm going to open this in IntelliJ, and we are going to take a tour of that and write some code. All right. So we've opened the application here up in IntelliJ. I'm just going to take a quick tour around. One of the things I like to do, I just like to rename this to application. I don't like these long main application class names, but you don't have to do that if you're not weird like me. So this is like a normal Maven project structure. So we have our source main Java. This package contains all our Java codes. So we have our main package here, which was created based on all that metadata we filled out at the beginning in the Spring Initializer. And then we have our main application class. We'll come back to this in a second. We have resources. This is where we're going to have like static files or templates if we're building out like a UI. There's also our properties files. You'll also see maybe an application.yaml in here. That's also for configuration. So that's our resources. Then we'll have a test package. And under test, we'll have Java. And then we'll have a package mirroring our package structure in our application class. So we are in here. And then we have this dot Maven dot Maven Maven command. And these are the Maven wrapper. So this means that you don't have to have Maven installed on your machine to be able to run this application. There's kind of a wrapper included in the project. And this is nice because if somebody else downloads your project, they don't need to have Maven installed. It makes everything so much easier. The palm that XML is where all of our dependencies are declared. So this is the Maven build tool. It has dependencies. It has build plugins for things that we might need to do. Again, these are the things that we picked at the beginning. So if you wanted to kind of drill into these, these are what's known as Spring Boot starters. This starter includes a bunch of other dependencies. And it's an easy way to get up and running without having to figure out all of the things that your application needs. You can command click on a Mac, control click on Windows, I think, to look at the other dependencies in there. So all of that is kind of the basic project structure that we get right out of the box. All right. So the main application class here is the it contains the main method. So, you know, in Java, every Java program needs a main method. Public static void main takes an array of strings called args. And then in here, it is using the spring application dot run method, passing in the class name with the args. And this is how the main application runs. So now that we know that let's figure out how to run the application. So we can run the application a couple of different ways here in the IDE. So we have these play buttons, so you can run the actual class, you can run the actual method, you can come up here and hit the run button. So I'm going to just do it here. And we're going to go ahead and click run. You'll see some things going on in here. One of which is, hey, the port that you're trying to run on is already in use. So you may have that if you have like other applications running. No big deal. Let's just go ahead and take care of that right away. So one thing you can do is use this tool called jps and see which ones are running on which port. In this case, I know that I need to kill this particular one. So 9 2 4 6 4 9 2 4 6 4 4 6 4 Dan. And now we should be able to go ahead and run our application. And everything's running. We'll come back to like what some of this console logging is in a second. But I'm just going to stop it there. So that's one way to run it. Another way is by using Maven. So we said that there's the Maven wrapper included. And we can actually run this from a command line. I'm using the terminal integrated in my ID. You could use whatever terminal you use. Pop open that and go ahead and run this using Maven. So I'm going to say Maven. So so look at this. So we have dot mvn. We have dot mvnw. So mvnw. And now I need to give it a command. Now what commands are available to me? So in IntelliJ, there is this nice little Maven plugin or window that will kind of show you what is available. And if you look in plugins, hey, there's these things. What about Spring Boot plugin? Well, Spring Boot has a bunch of commands, one of which is spring dash boot colon run. So we know that's one thing that we can do to run the application, we can say spring dash boot colon run, and then it will run the application does pretty much the same thing that our play button here does in the IDE. So I tend to go that way. If you need to stop this, you need to control see that. And then I'm just going to close this out. I will continue to run it this way, but just wanted to give you that option because that's how it's typically run on the server, right? There is no IDE, there's no play button on a server, it's run through that Maven W command. So that's how we can start our application. Let's take a look at creating some code. The nice thing about Spring Boot is that it doesn't really put any restrictions on you on where you kind of create code. That's a nice thing. For me, that's also a con. I like to be told where things should go, because if you're not, sometimes you can kind of shoot yourself in the foot, right? So let's take a look at some examples here of where you could put code and where you can not put code. So this is the default package, this dev.danvega.runners. I could easily come in here and create a new package and maybe call this food.bar. And inside of here, put some kind of class. Let's just put a class that is called the welcome message, right? So inside the welcome message, I will create a constructor. Actually, let's just create a method. So we'll say, hey, I want to return a string. We'll call this get welcome message. Welcome to the Spring Boot application. And if you look in the bottom left, I have like tool tips to show you like some of the keyboard shortcuts I'm using. You'll also notice that I'm getting some assistance on code. That is through copilot. It's a great little tool. So if you notice that, it'll just kind of help us speed things up a little. So I have this get welcome message. I have this welcome message thing. I'm going to mark this with an annotation. We'll talk about more about annotations as we go. But essentially, what this should mean is that this class is available to Spring. So in theory, that's what it should mean. Now, if I go into my application and I say var welcome message is equal to new welcome message, I could do that, right? And then I could say welcome message dot what is the what did we say dot get welcome message dot s out. And we'll just print that and we'll go ahead and run this. So in this instance, let's take a look down here. Let's actually make this a little bit smaller because it's in the way. So we have our message printing down here. You'll see it in a second. It says welcome to Spring Boot application. So this this is fine when we are controlling the instance of the class. But as we will see throughout this course, we are Spring is an inversion of control framework, meaning we kind of flip the onus on the framework to handle all of these instances for us. Anytime you see new, we probably shouldn't be doing this. This is a place where Spring can handle these things for us. So what I want to do is ask Spring for that particular welcome message and see if we can use it. In this case, it's not going to work because we've made it outside of the default class. So so we're in outside of that main class. You can also put this in a default package. So let's do that. Continue and let's move this. So this is what's known as the default package, where there is just no package, right, because it's in the source main Java where there's no package declaration. So this is also going to exploit this issue. So now what I'm going to do is I want to go ahead and just get all of I'm going to try to get an instance of that welcome message class. Again, not to overload you right away. We'll talk more about this. There is this huge container of all the classes in your application called the application context, and we can ask the application context for a particular class, in this case, the welcome message. So I want to try and do that here. So what I can do is say, hey, this is the context and hey, context, I want to go ahead and get a particular bean and we'll get it by its name, which in this case should be welcome message. And we'll create a variable of that. So this just kind of shortcuts in IntelliJ to kind of create this. So I'm going to say welcome message, right? And that should work. But what's going on here? It's saying, hey, I don't know what that is. What is welcome message? I don't see that. And in fact, even if I was going to make this an object and try and get this out of here, let's just sis out welcome message. Let's go ahead and try and run this. It's going to say, hey, I don't know what you're doing. I don't have a particular bean called the welcome message. Now, bean is one of those terms that like scares people. I know it's like, what is that? What's a bean? A bean is nothing more than an instance of a class with some metadata around it. So just think, hey, when you see the word bean, this is an instance of a class that the spring container, this huge application context is container of objects is managing for me. So all it's saying is, I don't know what this welcome message is that you want to do, that you want to access. This is because we are outside of the main package. So my first tip here with writing code is make sure it is within the main package. So if we move this welcome message into here, and now we go back to here and we say welcome message. Welcome message is equal to context dot get bean. And what we can do is just say, let's cast that to a welcome message and then get this out. And then we'll go ahead and rerun this. And now we should go ahead and print that out again. And we actually just print out the we don't have a two string in this class. So we print it out. So that was just a long way of saying, hey, don't put code outside this main package or in the default package. Because when we get into using springs dependency injection and version of control, it's not going to work. All right. So you don't need to ever do this. This was just for kind of demonstration purposes there. Let's go ahead and rerun the application. And everything is working. So we have this log, we have this console here of things going on. And let's just talk about some things that are going on in here. So first off, there's this banner. So it's saying, hey, spring is a spring boot. This is the version of spring boot that you're using. And then there's some default logging going on. So the nice thing is you don't have to configure logging out of the box. This is already done for you. If you were to start a new Java project, a new Maven project, you'd have to like figure out how to get logging up and running, this is already working for you. And so there's a bunch of things the framework is going to log for you. And then you can add your own logging if you need to. So let's try that real quick. So in any class, you can go ahead and add a logger, I have a little keyboard shortcut for this. But all we're doing is saying private, private static final logger log. And again, if we look at our imports, we can see that this is coming from slf4j. That is the default logger in spring boot. And we can say log factory that get log, get logger for this particular class. Again, this is something I create a shortcut for this is something I don't want to type out. So whatever ID or text editor you're using, I suggest maybe creating a shortcut for that. Now that I have a logger, I can say log dot info. And I could say our application has started successfully. Now when I go ahead and log this, I can see that this is there. Now I have a log message saying that this started successfully. Now if you you shouldn't be brand new to the Java world, so we should understand that there are some different levels of logging, like debug, warn, error, etc, trace, etc. And we can kind of change those logging levels. What do we want to see in the logging? So go ahead and check out the documentation to dive a little bit more into that. So what we see here is that we have no active profile. We'll talk more about those later. We have our dev tools set. So we have dev tools enabled, which is good. What does dev tools do for us? So dev tools does if we go ahead and do this, when we hit save, it should automatically restart the application for us. So that way I don't have to constantly like make code changes and restart something. Now you'll notice it didn't change. And that's okay, depending on what text header ID you're using, it might be automatic. It might be something that you have to change. So if I come in here and I go to build and I go into build tools, Maven, we are looking for the compiler build project automatically. So I want to say, hey, go ahead and build this automatically. So I'm going to just add this log.info in here and something changed. And let's go ahead and click save and see if that changes it. And what we're looking for is that automatic restart. So you can see it restarted, something changed. And now I could just close this and constantly work on my application. Now it's only going to restart when we change our code. Like the something that's happening behind the scenes is not going to restart this. So this is nice because I don't have to remember to always restart my application. The other thing dev tools does is it sets a lot of sensible defaults. So we don't have any examples of this right now, but later on when we use something like an in-memory H2 database, when you're using this in development mode, you probably want the H2 console enabled. This is a UI that can go in and see your database tables and columns and rows and et cetera. And so in development mode, of course I want this on. I don't want to have to go like enable this. It automatically enables it for us. So that's dev tools and that's logging. Let's go ahead and start to write our application out. Let me go ahead and clear some of those imports. I'm going to save this. And I want to start to write our application. Now, what we're going to be building here today is just a simple fitness application to track runs. I like to go out and run. So I want to track different runs that I'm doing. And it's not that exciting, but the important part here is I put this in the documentation as well is I want you to go through this today, learn the kind of mechanics of building this application out, and then take this and apply it to something in your life. If you like to cook, make a recipe application. If you like to lift weights, make a lifting application. If you like to go out and whatever it is, try to apply this to whatever you're doing in your life. So again, one of the things I love about Spring Boot is it's going to allow us to create code anywhere. But this is also a problem. We can kind of structure code however we want. There's two kind of popular ways to structure code. There's more, but let's just start with these two. There's two ways to kind of structure code. You could come in here and say, I'm going to package by layer and what are layers? So in an MVC app, you might have things like a controller, a model, a service, config, repository, etc. There are all these different kind of layers of the application. Some people, and I did this forever as well, may structure their application this way. The problem with this is I know where all my controllers are, so I have a run controller, user controller, type controller, whatever it is. I know where all the controllers are, but the controllers, when you're in this controller package, will always have to talk to something outside of this package. A run controller would have to talk to a run service, so both of these things need to be public. So one of the things that I like to do is use a technique, an architecture, called package by feature. So I'm going to come in here and say run. Run is the feature. Later on, we're going to be doing something with users to be able to work with the REST client. So I may have a package called user. So now I know that everything revolving around a run is in this particular package. I can find everything quickly. Everything is in the same package. It can live in the Java world of, hey, everything by default is packaged private, so everything can kind of talk to each other in this package. So we're going to model our application after a run. So I'm going to come in here. I'm going to create a new Java class, and I'm going to call this run. So right away, I'm going to just tell you that I'm doing this the verbose way first, the long way, just to kind of show off some features of Java if you're not used to it. So what I'm going to do is, hey, what are all the fields that this particular class needs to know about? Wow, co-pilots on its game today. Look at this. Okay, so ID title started on completed on miles and location. Yes. And look at all this code that it needs to generate. It needs to generate all of these fields. So these are private fields, a public constructor that sets all of these things, and then has getters for each of these. So most of the time, you have getters and setters, right? So I might come in here and I might say, generate my getters and setters. Let's do that for all of them. I might have a equals and hash code. So I might do that for all of those. And then I might have a two string. So I have a two string, and all of that. And now we have 100 lines of code, just to represent a simple run in our system. Of course, if you're a Java developer, you know where I'm going with this, but we can get rid of all of this. And in fact, I'm going to go ahead and just delete this. And I'm going to go ahead and say, let's create a new Java class called run. And this is going to be a record. So now a record has record components. So something like an integer ID, string title, let's see, I'm going to put these on different lines. And we have an integer ID, string title, string started on. Actually, I want to do this as a local date time. And we'll do that for this. So this is a local date time. And then we have a location, which I'm actually going to create an enum from. So let's create, why is that? Oh, that's why. So let's do that. All right, now we should be able to. Let's not let me create that. Let's just go ahead and create a Java class called location. And this is going to be an enum. So it has a specific set of values that we can pick from. In this case, I'm going to say indoor or outdoor. That's all I need to know. Is it an indoor run or is it an outdoor run? So great. So that is a record. Look at all that code we got rid of. We're down to 12 lines of code. And I could put this on one line of code. I just think this is more readable. And we have this nice run record that we can go ahead and create instances of runs with. So let's actually do that. Let's I say we go ahead and create a simple run in the system just to kind of test this out. So one place I can do this is in the application class. I'm going to go ahead and delete that. So I'm going to create something called a command line runner here. Don't worry about it. We'll we'll get into this as we go throughout the course. But a command line runner is just something that runs after the application has started. And more importantly, after the application context has been created, this container of all the beans in the system. Right. So what I can do is I can say something like this. And that would get run after the application has started. I just want a simple way to test my run. So I'm going to say run run is equal to new run. And we need to pass in an ID. Let's see if this is good. So title started on. So we are not going to use the string version of this we can actually let's just simplify this. So this is a local daytime. I don't know why I'm letting co pilot do all this. Let's do this without co pilot. So I'm going to say local date time. That now that's going to be my started on. I'm going to say local date time now plus now I can add some amount. So I'm going to say one. And then what is the temporal unit. So we can say chrono unit hours. And now we have our completed on. So completed on how many miles did we run. Let's say we ran five miles. And what is the location. So I'll say location dot outdoors because it's nice today. I want to get outside and run. So all I want to do is go ahead and log that now because one thing I didn't mention here is the class that we created had all those getters and setters and equals and hash code and two string. A record has all those components as well. The nice thing is though this is immutable. Once you create this record you'll see there's no constructor here. There's no all arcs. There's basically an all arcs constructor. We create an instance of the run and then we can get at the values but we can't set them. We can't change them later. And that means that this class is immutable. But it also means this class comes with a two string and equals and hash code getters for all of those fields or they're called record components here. But all the mechanics that we need to create a run and get all of that information is there. So let's go ahead and rerun our application. See what we have. And now the two string is automatically called. It says, hey, here's the run ID one. Here's our title. Our started on our completed on miles is five and the location is outdoors. All right. So with that, I think we have all of the kind of infrastructure, the knowledge to kind of get around our application. We've written some code. We have this run. We have this location. That's really everything we need to start building a rest API. We'll call module two complete and we'll head over to module three where we are going to create a web application together. We're going to create a rest API using Spring MVC. All right. So this is module three web applications using rest APIs. Now we have our application running. If you look down in the council, we see that Tomcat has started on port 8080. All this means is that we have an embedded Tomcat server. So something that can serve up an application and take requests and return responses and that it's running on 8080. This means I have an app. I should go ahead and test it, right? Let's hop over to the browser, go to localhost 8080. I'll just refresh this and you see that there's an error. That's because we haven't done anything yet. We have not set up any endpoints for this application to respond to. So we're going to do that now and we're going to talk about really quickly Spring MVC. So MVC, if you've come from another language, another framework, you might have done this before. MVC stands for Model View Controller. Model is the thing or the type that we're going to work with. In our case, we've already built out the run and the location. So that is the model. The view is how are we going to represent this thing, this run in our system. Sometimes you might display this in like an HTML page. In our case, it's a rest API. So where the view is going to be the JSON that is returned as data. And then the controller. The controller is the traffic cop of our system. It is going to take in a request. It is going to figure out what we need to do with it, delegate to some other service to do things, and then return a response. Controllers are very dumb. Take in a request, return a response, don't do anything else. So we're going to have to delegate to some other classes to do those things. So that's what we're going to start doing is we're going to create a run controller. So I'll come into my run package. I'll create a new Java class. I'm going to call this run controller. You can call it whatever you want. It doesn't need to end in controller. It's just kind of a convention that you'll see in the spring world. And it makes it easier to kind of just look at a file name and say, OK, I realize that that is a controller. So I'm going to make this a controller. And if you did nothing else, this would not work. Right. So there are these things called annotations in Java. And if you've been around Java, you've probably seen them. And these annotations kind of add some behavior to your classes, to your methods, to your fields. And so you'll see a lot of annotations in spring because it cuts down on the verbosity of having to write all this extra code. So what we're going to do is we're going to use a couple of annotations. One is going to be REST controller. And it says, hey, this is a controller. It's a REST controller. So we expect the response body to be in some form by default. This is going to be JSON. So we're saying that this is a REST controller. Now we can go ahead and create a method. Let's say public. And I don't even need it to be public. Let's say it's a string. And we're going to say, let's just call this home. And we're going to return hello runners, basically our application. What we need to do is map this method to an endpoint to say when somebody accesses a specific endpoint, here's the method I want you to execute. So we can do this a couple of different ways. There is a request mapping annotation. And this takes both the path and the request method. So in this case, it would be a get. Now there are specialized versions of request mapping that I'll probably use the most. These are for each of the request methods. So get mapping, put, post, delete, etc. So I'm going to say that this is a get mapping to slash hello. And that's all we need. So if we go ahead and rerun our application, now there'll be an endpoint for slash hello. This method is executed. What is returned in this response is just a string, hello world. So let's go ahead and look at this again, nothing at the root. But if we go to slash hello, there is our string that's being returned. Hello runners. So that is kind of the crux of that's the getting started of a controller. Now what I want to do is really start to build out a crud controller, a crud REST API, where we can interact with the runs in the system. Now the runs in the system are going to be in memory first. Let's walk before we can run, let's create an in memory representation of all the runs in our application. And then we can play with those we can return one, we can return all we can create a new one, etc. Now what I said before was that controllers are very dumb, they shouldn't be doing a whole lot of other things. So one thing I could do, I could come in here and say I have a list of these runs, I want you to go ahead and manage these for me, we'll call them runs, let's say new array list and boom, we can go ahead and start managing the runs here. But again, the controller should take in a request, return a response, not manage any other logic, do anything else. So what I'm going to do is split this out into another class and delegate those operations to something else. So I'm going to call this a run repository. So there's a repository pattern for data access and we'll kind of use that. We're not accessing a database, but we are going to encapsulate some of that like data access there. So I'm going to call this run repository. And I'll go ahead and create this here. So now I have a list of runs. Alright, and in this run repository, the first thing I might want to be able to do is get all of the runs. Now there are no runs, all we did is initialize this list, there are no runs in there yet, we'll come back to that in a second. So I may want to say, hey, I want to return a list of runs. And this method is going to be called find all. And what you should do is return runs. Great. But again, Dan, there's no runs in the system yet. How can we do that? So in a class, there are some different annotations that we can use in the lifecycle construction of a class. Again, we talked about beams and application context. We'll start to dive into those more, some of this will start to make more sense. But in the creation of this class, when it's gets put into the application context, it follows this lifecycle. One of the annotations that we can use here is post constructs. Let's go ahead and take a look at that. And what does this say? It says it's used on a method that needs to be executed after dependency injection is done to perform any initialization. So this is going to do some initialization in this class. Just think of that. Don't worry about dependency injection and stuff like that. So I'm going to call this, this actually needs to be a private void, a knit, and then we can go ahead and add some runs. I'm going to pay some code in so we don't have to watch me type this out. So the class gets created, this method gets called, we add two runs to our list. Now we have some runs in the system. So if we call find all, we can get a list of those runs. Now it's time to start talking about some more of these annotations. So again, I talked about in the run controller, we mark this with that rest controller. If we were to move this away, this class wouldn't work, it wouldn't be able to respond to requests. And that's really what this rest controller annotation is saying. Hey, I am a class that responds to requests, returns responses, right? So this is one of those annotations. There happened to be a bunch of annotations in spring. And again, you can kind of command click into them. This is actually annotated with at controller, which is another special stereotype annotation and at response body. So it's actually made up of two annotations. But the at controller is actually made up of another annotation called at component. And that component is really what tells spring, hey, I want you to manage this class for me, the lifecycle of this class, the dependencies that this class has, you are in charge of this class. At the run repository level, I haven't done anything yet. I'm saying I'm managing this class, I'll worry about this class. But what we really want to do is tell spring, hey, I want you to be in charge of this. So I could add at component and that would fix things. But there's also specialized versions of this, one of which is at repository at service at control or at risk control. These are no more than just at component annotations. But if you wanted to do something fancy, like, hey, find me all the classes marked with at repository, you could. So this is now in the application context. So spring has an instance of this class for us. That's important to remember. We'll come back to that in a second. So we have this class that has the ability to store runs. We have a method that can find all the runs in the system. So what I want to do is go back to my run controller. And I want to go ahead and get rid of this. And I want to write a method that will return a list of runs. Because again, the run repository isn't available to the public. The controller is what takes in a request. That request is, hey, I need all the runs and returns the responses. Here's all the runs. So this controller method is saying, hey, here's a list of runs. I am going to call this find all. And how am I going to get a list of runs? Let's just call it null for right now. So now, to return all the runs in the system, I need to get an instance of that run repository, right? So one thing I can do is say run repository. I could go ahead and create a constructor. I'm going to go none at this time because I want to show you the wrong way to do it first. And this is the wrong way to do it. So let's talk about it. So I'm saying the run repository in this class to create a new instance of this, just use the new keyword like we are used to doing in Java and create a new instance of the run repository class. As we've talked about, Spring is an inversion of control framework. Anytime you see the new keyword, when we're creating new instances of something other than, say, a type like a run, when we're creating new instances of classes, a little alarm bell should start going off in your head and go, why am I creating a new instance? Spring probably already has an instance of this. And by the way, it does some other things in there like run that post construct for me to initialize that data. So anytime you see a new keyword, start to think about that and think, okay, maybe I don't want to do this because what if this controller takes in a thousand requests? So you visit this controller, I visit this controller, 800 other friends visit this controller. Every time we hit this controller, we create a new instance of the run repository. And that's not what we want. There's only one run repository. It's a singleton in our system. And so we want to just get the one that Spring has available to us. And this is what is known as dependency injection. So instead of doing this, what we're going to do is we're going to ask for an instance of that. So we're going to ask in the controller's constructor for a run repository. And I'm going to call this run repository. And then I'm just going to say this.run repository is equal to the run repository that gets passed in as an argument. Now in IntelliJ here, I can see that that worked because I have this little gutter icon saying, hey, I see a run repository and I manage it. I can go ahead and do that for you. Now just for fun, let's take this annotation off and go back to our run controller. Now Spring is saying, hey, I can't auto wire one of those in for you. I don't have one of those things. I don't have an instance of that because you haven't told me about that class that you're creating. So you can go ahead and undo that and that will fix that issue. Now sometimes you will see in older code, you'll see an at auto wired annotation right on the field itself. This is what's known as field injection. And this is not suggested and actually IntelliJ right here will say, hey, field injection is not recommended. There are some reasons not to do this. One of most is testing. If I wanted to be able to mock out this repository and pass in a stub or a different version of it, it becomes very hard because this is using reflection. So what happens is it's actually doing that on the constructor. But because there's only a single constructor there with some arguments, this is implicit. So you don't need to add that annotation. So at the end of the day, there's a run repository. Spring knows about it. It can inject it into this controller when it creates an instance of it. And we have a class that we can now use. Now we have a run repository. Now we can say, hey, the run repository has a find all method. Let's call that to return all of the runs. Now we need to create that get mapping again. Again, there is no there's no mapping. There's no endpoint for someone to visit. So what I would say is let's go get mapping. And I think I have I'm just checking the final and I'll say this is at slash API slash runs that will return all of them. So let's and actually we don't need to go ahead and restart our application because it will restart for us. So let's go back over to the browser. And let's go to slash API slash runs. And let's turn it down a little. And now we see the when we execute that endpoint, we get all of the runs back. So we have two in the system because we loaded two up in that init method. And so it's bringing back those two runs. Pretty good so far. Let's start to improve upon this a little bit. So first off, this slash API runs, I might start to replicate this or duplicate this over all of the crud methods in my system, right? So I might have a get mapping for slash API slash runs slash whatever ID for API slash runs for the post for the put delete, etc. So what I'm going to do to like cut down on some of that duplication is I can set a request mapping at the controller level. So this is API slash runs, and then every method that has like a get mapping a post mapping to put mapping falls under that base URI, right? So now what I can say is, this is nothing, this is slash API slash runs, that will call find all, then I can say slash API slash runs slash ID, that will return the ID, right? Or that will return just one. So let's actually do that real quickly. Let's say run find by ID. And maybe we want to use the run repository to find by the I'm just hard coding in a value of one because we'll come back and we'll fix that in a second. But let's go back to our run repository. And let's create a method that returns a run called find by ID, and takes in an ID, and then says that looks pretty good. Actually, we don't even need to throw an exception first. And we know this will work. So I'm okay with that. So let's just do that for now again, not the most ideal place to do it. But this will work. So now I can go ahead and rerun this application again, don't need to dev tools has restarted for me. And now I can go to slash runs slash one. And I get just that specific one. I can't go to slash two or three yet, because we've kind of hard coded that in there. And so that's kind of the next place that I want to talk about is being able to use dynamic variables in these paths. So we have a slash one here, but we really want a placeholder for an ID, right? We want to say, hey, whatever is in this path, I'm going to consider an ID. And I want you to use that ID. Now, the way that we get that and pass it to our method, our find by ID method here, is by using an annotation called path variable. So that path variable is going to pick it out of the path and assign it to whatever we create here. And I'm going to say that is going to be an integer of ID. So we can pass that now. Now this is dynamically passing whatever is in the path to this particular method, and should go ahead and use that. Still saying we have an issue, but I don't think we do. So I'm going to go ahead and save. Let's go back to our browser, see if one still works. It does. Let's see if two works. It does. And now we know that something like 99 is not going to work. It just returns an error because we haven't handled that exception. So, so far, so good. This is off to a good start. All right. So one thing I'd like to improve on right away here is the find by ID when we passed in 99 through an error. And so let's go ahead and fix that. I want to go ahead and instead of returning a run here, what I want to do is actually return something called an optional of run. So what is an optional in Java? If we go ahead and click through, take a look at this, it is a container object, which may or may not contain a non null value. If the value is present, we have this method called is present that will return true. So it's just a way of being able to operate on objects without having a null value present. Right. All right. So to fix this, I'll just remove that and that will return an optional. So back in our run controller, we're going to have to kind of change things up here. What we want to do is we want to check to see if it's there, if it's there first. So in this case, I will not return this. I'll say run repository dot find by d dot far is going to return an optional run. We'll call this run. And then what I want to do is say if the run dot so you can do a couple of things you can say is empty or is is present. So if it's empty, I want you to throw a new exception and we're going to call this. Let's actually do a response status exception. And we can say HTTP status not found and our run not found. Now we can also throw a custom exception here. Talk about that in a little bit. But if not, I just want to return the get method. So I'm actually returning the run that we retrieved. So this should be a little bit better. We're actually I saved the file, reloaded. Let's go back to the browser and try to look at run 99. So now we get a 404 not found instead of that 500 message. Now, one thing we've been looking at is just kind of testing this out in the browser. But I also want to show us that we could do this in the terminal from a command line. You can use whatever command line tool you're familiar with. There is curl curl is great because it's installed on everybody's machine. But it's also there's a lot of things you have to understand about curl. I like this program HTTP because I just type in HTTP what I want to what port I'm on. So in this case, 80. So this is basically a request to HTTP localhost 8080. And then slash API slash runs. And we can see that because we've kind of switched context, right, we're no longer in the browser, we're on a command line. We're able to get back the response here, here's some of the headers. So we're using HTTP one, one, here's the content type. So we're using application dot JSON, here is the response. Now I can say, give me just the first one, or give me that 99th one that doesn't exist. And we'll get a error there. Now, again, this is a 400. We can handle this a little bit better. And we'll do so in the future. But at least that's a little bit better than we were doing before. So we're starting to move along, right, we have our controller methods, we are starting to build out kind of the crud, we have the list, we have the find by ID. Now we need to do, let's say, we need to create one, which is post, we need to update one, which is put, and we need to delete one, which is delete. So, so how can we create a post? Alright, so I'm back in the run repository, I need to create a new method in here to be able to create a new run. So let's go ahead and call this, yeah, what is the return type? Do I need to return the run? Probably not, because I'm passing in all the info, I know what it is already. So I'm going to say void create, it's going to take a run as an argument, and then it's just going to add a run to that list. And that's all we need to do there. Now, this run is basically going to be immutable, right? So do we need, so that should work. Let's talk about it from a controller's perspective. How are we going to handle this? So I'm going to create a method to create one, so I'll say void create, and it's going to take in a run somehow, we'll come right back to that, we'll use the run repositories create method, and pass in that run. Now here's where it gets a little bit interesting, we have this run. And what we need to do is we need to somehow tell this controller that this run that is getting passed into us is going to be coming from the request body. So if you've ever worked with a REST API before, you know that you like will hit a certain endpoint, and you pass in a body as part of the request to use. And that'll in this case be in the form of JSON, it'll be a JSON object with the ID title started on created, you know, what are all of those fields as part of that request. Now the way that we tell Spring that hey, this argument is going to be part of the request body is as you guessed it, an annotation, we're going to say request body. And now it knows, okay, this is coming in as part of the request body. So this is great. Up until now, we've been testing everything kind of manually using the browser and the command line, which is easy for get requests, right, because a browser can respond to a get request, our command line is easy to use with a get request. But now we have to send a post request. And we need a tool to do this in. So I talked about this in prerequisites. But basically, there are a couple options, we could do this from the command line, it's a lot to remember, I'm a visual person, I like to be able to see it run. So there are two tools that we can take a look at here. And I have a in the main repository, actually, let's go back to the browser. If we go back to the main repository, you'll see an API folder. And in the API folder, you'll see a postman collection. And I HTTP file, this is the IntelliJ's collection. So if you're in postman, you can load up this collection, there's a way to import that by opening that file. And now what I can do is just click on one of these. And actually, let me close all of these, because I think some of these are older. Don't care, don't care. Don't care. All right. So now that I'm in here, I'm in the final, you can see that it's going to localhost 8080 slash API slash runs. And it's a get request, we can send that request, we can get to the pretty view. I'm sorry, where's the pretty view of all the runs in the system, right? We can go ahead and find by ID, we know there's one in there with an ID of one, we can get that back. Now we can start to use the other ones here, this is the create one. So this is going to send a post request to localhost 8080 slash API slash runs. And this is the request body, we see that we're sending it raw, but this is also a JSON type. So we're sending in this request. And I think I may need to update this because this one is for probably the end result, where in the case of a database, we may not send an ID. In this case, I'm going to hard code the ID and then I'm going to send because again, this is an in memory collection. So I'm saying here's my third run, send a post request, and then go ahead and make this happen. So I'm going to send this and see what happens. We get a 405 method because it is not allowed. So let's go back to our code. And the reason for this is we haven't annotated any methods in here with a post mapping annotation. So the only methods allowed by default are I believe get an options, I don't even know if options is by default. But what we want to say is, hey, I have a post mapping here. And all we're going to do is use the empty rack empty parentheses here, because again, that's going to go to slash API slash runs. So I've saved that, I'm going to come back over here and attempt to do this again. And you see nothing is returned. Because again, we said void, don't return anything. But I also get like a 200 back. And I'm not really sure like if something got created. Now one way I could check this out is going over to find all and clicking send. And oh, there's a third run in our system, it did get created. But I wasn't really kind of notified that it was created. So I'm going to do one more thing here. And I'm going to add another annotation here called response status. And what I wanted you to do is if you're going to return something, in this case, you're not returning anything, you're returning a response, though, I want you to send the response status of HTTP status that created this is a 201, as opposed to a 200. And what this does is it notifies the sender that something did happen, it was created. So I'm going to go ahead and send this again. Now I see that I got a 201 created, I don't even need to go check anything else. I know it's there because of that response status that was sent back to me. So just one little nice feature that we can add to go ahead and update that. Okay, so we're getting there. I'm going to go back to our repository, we need to add a couple more methods for updating and deleting. So let's go ahead and do the update. Let's say void update. Oh, boy, you're getting good. Co pilot. So I'm going to say optional run is, hey, let's find the existing run that you're asking me to update. If it exists, so if that existing run is present, remember, the optional returns back, this optional that has an is present method on it, if it is present, I want you to go ahead and set the index of that existing run to the run that I passed to you. All right, so that's one thing. Now let's say, what if we wanted to delete runs, go ahead, this is a collection, remove if the run.id equals the ID that we passed into. That looks pretty good. So now I'm going to go back to the controller. We're going to create a couple methods here. So the first one is going to be a put. So we're going to say void update. So we're going to get the run just as we did in the create, we're going to get this through the request body. Then we need the ID of whatever run we're trying to update. So at path variable, integer ID, use the run repositories to update that. That looks good. But now we have no way to respond to this yet, because we haven't created an endpoint. We can do so by using the put mapping annotation, and the ID as a dynamic variable, because we've assigned it using the path variable. So now we can respond to a put request. Now we can respond to gets, posts, puts, how can we respond? And actually, let's come back one more thing. I'm going to add one more response status. And I'm just going to say no content, like it's okay, this is a 200. I'm sorry, instead of sending a 200, this is done. We actually have no content to send back to you, right? Just again, informing the user of what's going on. So we'll do that here as well. I'll also say that this is a delete mapping to slash ID. And then we'll just say void delete path variable. Yes, call that. So don't worry if we're not following along all these methods, don't worry, we're just kind of building out the crud of the system. We'll kind of enforce this as we go along, and we move away from the in memory representation to say a database call. So we've restarted, I'm going to go back to postman. So now, the system is restarted. So there's only two in there right now, right? Because we've sent because it restarted. And when it does, it initializes those two runs. But now we can go in and we can create one. So let's go ahead and create one. We got a 201. So we know that's been created. In this case, we're going to update three. So whatever that was before, we're going to call this and say update that we have a 204. So not a 200 204 says, yes, everything was done. Everything was successful, but I have nothing to send back to you. And that's okay. So now we know that that's there. Let's go ahead and look at that. And there's our three with our updated record. And then finally, let's go ahead and delete one. So I'm going to call localhost 8080 slash API runs three. So if I send that in, we also get a no content. And if I go back to find all I only have my two in my system. So that's postman being able to test your API. That's important. I also included a collection for using an IntelliJ. And I think I'll do that. I'll copy that into this project. So let me say API. And let me find that. And so if you're using the IntelliJ Ultimate Edition, you can come in here and just click on this, you can actually run these right in IntelliJ, which I like not having to leave the ID. Here is the two in my system. If I wanted to get a one by ID, I can. If I want to go ahead and create one, I can. All is good. Now, again, you can do this through postman. You can do this through IntelliJ. You can do this through Curl. But as we start creating these methods, it's good to manually test these. We will write some tests for these letter, these automated tests. But this is good. Just a kind of good sane check to make sure everything is working OK. All right. Now, one thing I'd like to do is kind of improve on some of the error handling that we're doing here. We could go into a lot more detail on this. But just for the sake of time, I'm just going to kind of clean up one thing here. So I have this throw new response status exception. Hey, response not found. But we can kind of clean this up and actually create our own exceptions. What I'm going to do is go into main Java into run. And I'm going to create something. So new class run not found exception. Right. That looks good. And this is going to extend the runtime exception class. And we can just say run not found. But more importantly, I'm going to add that response status on here and say, hey, this is a not found. So I want you to return a 404. So now back in here, I can just say throw new run not found exception. Let's see if that saves. Let's go back to maybe our test here. Let's go ahead and do this in here. And let's just say that we try to find by an ID that doesn't exist. So let's copy this and say by ID that doesn't exist. And let's say 99. So let's go ahead and try and run this. And now we just get that nice 404. Hey, this is a run not found. Here's the path so we can see that it's API slash run slash 99. So that's kind of one good improvement. Something else we need to think about is when we're creating these new runs, we probably want to validate some data, right? Like, if we just accept whatever the user sends us, that's probably not going to be a good time. We need to make sure that whatever they're sending us is valid data, right? So there are a couple different ways to do this. I'm going to show you two. I'm not a big fan of mixing and matching these, but I just wanted to kind of show you both ways to do this. So one thing I want to do is I want to make sure that when we create a run, so here is a constructor for a record, I want to say if the completed, if completed on, sorry, that should be that, then what I want you to do is throw a new illegal argument exception and saying, hey, that completed date that you sent me has to be after started on. You couldn't have finished a run before you started it, right? So that's one level of validation that we can do. Another is by using something called the validation API. And this is going to be an extra dependency that we need to bring in. So this is one of those things. If you're on start.spring.io and you go through your dependencies, you can select validation and that will bring it into your project. But as I said, there are going to be times where you're working in a project and realize you need another dependency and we need to go ahead and bring this in. So I'm going to type in dependency here and I'm going to say spring boot starter validation. And that's going to come from org.spring framework.boot. And if you're in IntelliJ, you need to click this little reload button that says, hey, bring in those external dependencies that we just declared. And now we can use them. So now in my run, now I can use the being validation API. And with that comes a bunch of constraints. So one thing I could say is, hey, I don't want this title to ever be empty. So how can I do that? I can use the not empty annotation and you'll see that it comes from Jakarta validation constraints, not empty. If I look in the constraints package here, you'll see a bunch of different constraints that we can use. Hey, make sure that this is an email. Make sure it's in the future. Make sure it has a min or a max. Make sure it's not null, past, past or present. There are all these validations that we can take advantage of here. So I'm going to put one more on miles and make sure that it's positive. I don't want you to be able to enter negative five miles because an integer could be negative. But in the case of miles, that shouldn't ever be negative. So now I have some validation constraints around this. This will automatically get run anytime we create a new instance of a run. So we're not worried about this one, but these are validation constraints saying, hey, when somebody asks, asks if these are valid, I can let you know if they are or not. So one way we can do that is in the run controller. When someone creates a new run, hey, please go ahead and validate it. So we're using the at valid annotation. So before we even call this run repositories create method, Spring is going to validate that the object that's getting passed in is valid based on the rules that we gave it. If it's not, it's not even going to go here and it's going to throw a 400 bad request, again, letting the user know that something went wrong. So this has been saved. I'm going to go back over to my runners here. And I think I have an invalid one in here. Yeah. So here's one. Let's go ahead and remove the title to you. So I can see this and I can go ahead and try and post this. And right away it's going to say, hey, that thing that you're trying to create the completed on must be after the started on. Okay. Well, that's good. I've got some information there. That looks like it's working. So let me fix the completed on and the started on so that those are valid and let me run it again. And, um, you are response body to a one. Oh, because we have a title there. Oh, that's why now this should, I think I did the wrong one, right? Um, nope, that's still sending a two or one. So let's make sure that we are validating this title. So run not empty. That's true. We don't want it to be empty. And in our run controller, we are saying at valid. We actually want to do this here too. Um, let me just make sure that the server restarted. It's okay. Doing a little debugging is fine. Uh, let's try this again. Let's go over to runners and let's create a new post. And, uh, now we get our 400 and we're saying here are the errors that are happening with this. If you don't see all of this verbose logging of what went wrong, then you might not have DevTools on the class path. Remember, one of those things that I said that DevTools does for you is restart your application. When your code changes, another thing that it does is sense some sensible defaults and this default to kind of log out this, um, more information on these errors is one of those things. So it says, Hey, validation was run. There's a problem. Where is it? It's on the title and the title cannot be empty. So we're seeing some information there. And if we go ahead and fix that title, which we did in the good example, then it will go ahead and run and save our new run. So that's a little bit about validation. Again, you can kind of do it at the class level. This you could also write a custom constraint for. So there were all the constraints that we saw. Um, there are some, there's a way to write custom constraints. I will say when it involves another property, it can get a little bit more detailed on how to write those custom constraints. So I found this so much easier. Again, I, I don't know how I feel about mixing and matching these, but I just wanted to show you that you could do that validation there. You can also come in here and do that same validation, right? Like if, uh, title that is empty or is blank, then go ahead and throw some illegal argument exception there as well. So that's a little bit about validation in your API. All right. The last thing I want to show you in this module before we move on to talking to databases is we haven't really touched this application.properties yet. We really haven't had a need to do so. Uh, so here's where we can start to configure all of the things in our application. We know if I run the application, I look at the council, we know that, uh, Tomcat has started on port 8080 because this is the default, but most everything can be configured. So in the case of Tomcat, maybe I already have something running on 8080 and I want to run Tomcat on a different port. You can come in here and change that. So server.port, you see the default is 8080, but if I wanted to change this to 8085, I can do that and run this and I can see that now it's running on 8085. So I need to run all my requests through that port. This is simply to say that there are a bunch of properties that we can change about the way our application is working. Um, you know, spring is a convention over configuration framework, meaning if it's nothing's there, it's going to configure something for you. But if you want to go ahead and configure it and change something, you by all means do so. It'll back off and it'll say, okay, I've been told what to do here. These are all the properties that are based on whatever type of application we're building. So in the case of a web app, we are configuring a server and all of the things that go with that. I would say, look at this spring documentation to see what properties are available based on the type of application that you're building. There are also ways to create your own properties. I'm not sure if we're going to get to that today, but if we can, I'll sneak something in. If not, go ahead and check out my YouTube channel. I know I have some videos over there on creating your own configuration properties. So I just wanted to mention that because that's going to be important once we get into the database side of things and configuring database connection. So I think with that, we have, I think you should go ahead and give yourself a big pat on the back. You have created a CRUD REST API in Spring. This is the boilerplate of building REST APIs, right? We have this CRUD thing that allows us to list, create, read, update, delete for a specific type, in this case, a run. So this is the foundation for building REST APIs. We've got that. You've got everything you need to start doing that. Now what we're going to do is we'll move on to the next module and we'll replace this kind of in-memory thing that we've done. So we've done this where we have a collection of runs just in our system. And we'll replace this with actually talking to a database. All right, module four, talking to a database. Now, if you've been around the world of Java for a while, you know that it may not be the easiest thing to connect to a database. There's a lot of things you have to keep in mind. Like when I open a connection, I have to close it. Maybe I'm working with a connection pool. I have to use some of the APIs that have been around in Java since 1.1 to access a database. And some of them are clunky, may not be the easiest things to use. I'm happy to say that Spring has many layers of abstraction for working with databases. And it's really easy to get started. In fact, the first thing that we're going to do is talk to an in-memory database. And it's super easy to get up and running. We're going to do this in our app, but I just want to show you here on the Spring initializer. If we go into add a dependency, there is a dependency for h2 database. It says this provides a fast in-memory database that supports the JDBC API and supports embedded and server modes. We're just going to use an embedded in-memory version of a database first. Again, starting to like pick up the pace a little. We're still kind of walking, but walking fast. We'll start to run in a little bit. We'll change this out to like a Postgres database. We'll introduce Docker and do a whole bunch of fun things. But for first, we're going to use the h2 database. Now to talk to the h2 database, I mentioned there are different levels of abstraction, one of which is just the JDBC API. That's what we're going to use. There's also things like Spring data. We'll mention that in a little bit, but this is a really good place to start. It allows you to talk to the database, connect to it, talk to it using SQL. If we're coming from another platform like language and framework, it makes sense. If you're coming from just Java talking to a database, this is a nice level of abstraction on top of that. So I'm going to choose that as well. What I brought you back here is I wanted to show you another feature of the Spring Initializer. If you go ahead, explore, and actually we're in a Gradle project now, let's choose Maven. If you go ahead, explore, it'll actually list out those dependencies that we need. So this one is a runtime dependency. We're not actually going to use this in production. We are going to also use the Spring Boot starter JDBC. So this is that JDBC API that allows us to connect and talk to a database. So now I can come in and copy those dependencies, go back to my project. I'm going to open up the palm.xml. Again, this is the Maven palm that declares our dependencies. I'm going to come in here. I'm going to paste those in. I'm going to refresh my project. And as long as nothing goes wrong, we now can take advantage of those. So what I'm going to do is I'm not going to do anything. I'm going to rerun this application, not do anything. And I want to look in here, and I see a couple of things that are going on. First, the 885 there. Let's get rid of that. I like to run on 880. That was just showing some configuration changes. And now we're back to 880, and we see a few things here. It says the H2 console is available at slash H2 console. Again, this is because of the Spring Boot DevTools that we've included. It sets some sensible defaults. If you don't have DevTools, you could come in here and say, hey, I want to go ahead and enable the H2 console. That's great, because we want to disable that by default. We don't want you somehow running in production with that and making that available. The H2 console, for those of you who don't know, is this nice UI that you can go ahead and visit in your browser and manage your database. So once we create a table, and it has some columns, and it has some rows, we can do all of that right in our browser. And again, this is just a good starting point, right? We see that it's available. We also see that the Hakari pool, this is the database connection pool, is configured for some URL. So when we talk about databases in Java, we have a JDBC connection using a JDBC URL. It starts with JDBC, then the type, in this case, H2 memory, and then some random UUID identifying the database. So we haven't done anything yet. We just included some dependencies. And I'm happy to tell you that you are already connected to a database. Now we haven't done anything yet, but that's how easy it is to connect to a database in Spring. Now to get rid of this name, I'm going to do a couple of things here. I'm going to say the H2, let's say H2, oops, sorry. I don't know what I just did, Dan. So I'm going to say the data source generate unique name. I'm going to say, no, let's not do that. And I'm going to say the data source.name is going to be runners. So let's go ahead and refresh the application here. Now when I look at this, I see that I have a URL of JDBC each two mem runners. So if I wanted to, I could go ahead and copy that, but I don't need to. And what I want to do is go over to the browser and go ahead and look at localhost8080 slash H2 council, because that's the default. And you can see I have a JDBC URL. So I would copy that out of there if I didn't know it. The username is going to be SA, the password is not, there's going to be no password. I can test that connection. I can connect to it now. And now I have this UI where I can play around with my embedded in memory database. Now remember, in memory means every time we restart the application, everything is going to change. But now we have a database. Now there's no tables in here. We'll change that in a second. But there's no tables in here. There's no data in here, but we have something to get up and running with. So now what we need to do is we need to be able to create a schema and say, hey, this is what my runner's table is going to look like. And then we need to create some code that will allow us to persist and read information from that database. All right. So the next thing we need to do is we need to be able to create a schema for that database. Now again, it restarts every time the application restarts. So I want to have some way of automatically creating the schema. And Spring provides the mechanism for that. What we can do is come under Resources, create a new file, and we'll call this schema.sql. This is a specific name that we're looking for by convention. We're looking for this file. When it's an embedded database, we're always going to run this for you. So I'm going to paste in some schema here. This is going to create a new table if it doesn't exist. And this lines up with the run record that we created earlier. It has ID, title, started on, completed on. And notice that the way that this naming convention is, so we use the camel case in the record. This is using snake case here. I believe that's it. I always get those confused. And that's how we're going to name the fields or the columns in our table. So it started on completed on miles location. The primary key is the ID. So with this in place, I'm going to just restart the application again. Let's go back to our browser and take a look at this. We'll have to log in again. That's OK, though. Once we log in, now we see a run table. Now we can do stuff with the table. We can put data in there. We can read from it. We can do this here in the UI, but I want to do this programmatically in our applications. How can we do that? So first off, let's go ahead. And I think what we'll do is we'll go back to the run repository. Now in the final code that you can get on GitHub, there'll be two different versions of this in memory one, the JDBC one. For simplicity sake, I'm just going to keep this run repository as it is. I'm going to delete all of this, right? So let's just say all of that is gone. That's OK. This is going to cause some issues in our run controller. So I'm going to basically comment out everything for now. But we still have a run repository. So now what we want to do is we want to be able to talk to that database. So how do we do that? Well, we've already have a connection to the database. We just need a way to programmatically access it. So I mentioned there are different layers of abstraction in Spring. If you see some older code online, it's not that old. I mean, before three dot two, we still use the JDBC template. But if you see some older code and you see something called the JDBC template, this was really an abstraction on top of the JDBC APIs that made it easier to talk to a database. In three dot two, we got something called the JDBC client. This simplified that abstraction and really gave us this nice, fluent API for working with databases. So what does that mean to us? Actually, I don't even need this for now. One thing I want to do is get a logger real quick. So we talked about this earlier. I just have a logger that I can use to log in my class here. I'm going to declare a JDBC client. So JDBC client will get this through constructor injection. What this means is we saw this earlier, right? So this is dependency injection. Because we added that JDBC API dependency spring, this is one of the powers of kind of spring boot, looking at things that are on the class path and auto configuring things. So it knows, hey, we're we're going to be talking to a database, I'm going to auto configure you a JDBC client. And now it's in the application context. And if you ask for an instance of it here in the controller, it will pass it to you. You don't need to create one. So we have an instance of a JDBC client. What is a JDBC client? Let's take a look at it. So I'm going to go ahead and download sources. A fluent JDBC client with common JDBC query and update operations, supporting all the JDBC style positional as well as spring style name parameters with a common unified unified facade for JDBC prepared statement execution. So it gives some examples in here. You can dig through here. You can look at the structure of this and find out, hey, there's a SQL, a create, create, create, a very simple API from there, we can do other things. So let's use this to kind of replace the functionality that we had in our in memory repository. So I want to be able to find all of the runs in the database. So what we're going to do is say I want a list of runs, and we'll call this find all. And how are we going to get that? We're going to use that JDBC client. And now the first thing that we need to do is use some SQL. So we're going to have some SQL, and we're going to say select star from run. And once we do that, I want to go ahead and map the results to something. So run that query and map the results to a run. And oh yeah, go ahead and return a list of things back to me. So I don't have an actual connection to the in memory database here from my database tools. So it's going to just give you an error here. But that's okay, we have a connection, everything is going to be working. So I have a way to find all. This is good. But I also don't have any runs in my database. So how can I fix this? So another thing you can do is you can come in here and say, I want to go ahead and insert some data. So you can use data dot SQL. Now this is you're gonna have to write SQL to insert data. I don't do this a lot. But I'm going to do this just for this kind of demonstration. Later on, we'll do this programmatically, we can add some data through through through some code. All right, and I'm just going to paste this in. So we're inserting into run here our columns here are values, let's go ahead and try and run our application. And there we go. Now we have a single run in the system. So with some data in the system and a schema in place, now I should be able to come to my run controller, uncomment that out, we're using the same run repository, we've just changed that code in the repository to actually pull from the database. So now, this is probably restarted. By now, we should be able to just go over to the browser and go to localhost 8080. So we can go to localhost 8080 slash API slash runs. And there's our single run in the system. But now, we're pulling from a database. So this is exciting. We've moved on from this in memory representation to storing some things in the database. Now remember, every time we change our code, it's going to restart the application, and the data is going to kind of reset itself. But we're making some progress. We're doing some some fun things here. So now I want to go through and talk about some more methods that we can write in our repository. So I'm going to go to our run repository. And I'm just going to paste in some methods here because we can talk through them. We don't need to watch me type all of them out. But let's go ahead, we have that find all what about in an instance where we want to find a single run. Remember, in our in memory representation, we return an optional run, we can do the same here, we can say, okay, here's the SQL, I want you to find these columns from run where ID is equal to ID. So we're using a named parameter here. We can set that parameter by calling dot param. The param name is ID. Here's what I want you to pass to it. That is the ID that we got from the argument. I want you to map this to a run. So we have our run. And then I want you to return an optional. So it's a good way to find by ID. Now you'll notice I'm naming these the same as I did in the in memory representation. So that these are in place, our controller should just work exactly the same. Now again, this is for demo purposes, but I thought it was fun. Now, to create, update and delete, we are using something called update in JDBC. update is basically, hey, I'm either inserting something, I am updating something, or I am deleting something. And what happens from that is we, here's the SQL that we're going to run, here's the values I'm getting passed in, I pass in a list of params, I call update, what is returned from update is how many rows were affected. So in this case, we actually want to make sure only one row was affected. If it didn't, here's the message that you could send back. So again, update, we're just making sure one is updated, delete, we're just making sure one is deleted. We're able to count, we're able to, I wrote like a save all method if we want to save a bunch of them. And then just a custom query like, hey, find me all of the ones by the location. So this is, again, if you've never done anything in spring and just worked with databases in Java, this should look pleasantly familiar. It's a little bit easier to read, you get this nice fluent API. And if you've not done a lot of work with Java and databases, and you're coming from another language, I think you should be able to get dropped into this and understand what's going on. So what I want to do is go back to our run controller and uncomment all of these out. Great. We'll restart our application. And what I want to do now is take a look at our collection of things here, and say, let's go ahead and run all of these. I want to run all of these and make sure these are all working. And of course, they are still because, again, we've kind of named everything the same. So I know that my API from my controller level is still working. But now we're talking to a database. So let's go back over to here and go to H2 console. And if we wanted to look at the database here, we can click on run and run, and we see our one run in the system. So this is great. We've gotten one run in there, but I want to be able to get a little bit more data in there. So one thing I'm going to do is actually just come in here and comment this out. And now what I want to do is find a way to kind of batch load some data in just for example purposes, before we move on to having a little bit more fun with, say, like a real database, right? All right. So with this commented out, we're no longer going to be inserting that one record. So if we booted up our application, there would be no records in our app. So one thing I want to do is come back to this command line runner. This is very interesting, right? Because the command line runner is something, and if we jump into it, this is a functional interface that will be run after the application has started. If you're a little bit new to Java, a functional interface is an interface that has a single abstract method. So in this case, that method is run. And because it's a functional interface, it can be used as a lambda expression. A lambda can target this. So you don't need to create a class that implements the command line runner, and then does overrides like the run method. You can use a lambda expression, which we are doing here. So I want to show you this example, and then we'll move on to kind of doing some batch loading. So I have this run here, but I want to save this to the database. This bean annotation, again, is another way of creating a bean in the application context. We looked at things like at component, at REST controller, at repository, at service. These are ways of telling Spring, hey, this is a class that I manage. Go ahead and manage this for me. Bean is another way to create beans and put them into the application context. We're not going to go too far into that in this course, but this is one example of creating a bean. So what we're doing is we're creating a command line runner, and it will get run after the application starts. But because this is a bean, we can say, hey, part of this is, and I need a run repository, go ahead and pass that instance into this bean for me. So now I can say run repository. And there is a create method to pass in a run and create a run from that. So let's say create. Whoops. And then now we should be able to go ahead and run this. And we have an issue here, which is run controller. So let's look at our run repository, create. So insert into script. Fail to execute script. This looks like it's complaining about this. That's okay. Let's go ahead and delete that. And let's run this again. And there we go. The application started up. And if we remember, let's take a look here, we have this thing called the first run. So we should be able to go back to the database here and connect to this. And if we go to run, we have our first run. So good. So we know now that this is a programmatic way that we kind of bootstrap some data. So we're going to use this as a way to insert some data that we can use in our application. But I'm actually going to get rid of this because I'm going to go ahead and do it a different way. So the first thing that I'm going to do is I'm going to create a new folder here called this data. And inside of here, I'm going to say that this is a runs dot JSON. And we have some JSON data that we can paste in here, you can grab this from the repository. And we can say, there we go. So now we have 10 runs. And the reason I did this is so we can basically bootstrap some data, we have some data that we can work with, right? So now I want to talk about maybe how can we read this JSON data, and insert it into the database. Now we already have the mechanism for reading and persisting data, right? We have this create method, we have a delete method, I also have a save all method that can take a list of runs and insert that. So what I'm going to do is create a new file here. And I'm going to call this my run JSON data loader. And in my run JSON loader, I'm going to implement that command liner. Because in this case, I do want a separate class to do this in because I'm going to do a bunch of things. All right, first off, I'm going to get a logger, I have a logger to log some information with. I want to get that log that run repository. So I'm going to say run repository, run repository, and we'll get that through constructor injection. Again, this is dependency injection. When it creates an instance of this class, it will see that it's dependent on the run repository. Spring knows about that class, it'll inject that into this constructor for us. And now we have a run repository that we can use, right? So in this method, now I can say, hey, run repository dot count. So we know this is going to be zero all the time, because we are basically resetting the database when we start. And starting from zero. So we know it's going to be zero. But when we move on to a real database, that's not the case, right? We don't reset a real database all the time. But in this case, it will be zero. But that's okay. We're saying if the count is zero, I want to do some things. I want to go ahead and try and load some data. And wow, copilot on its game today. Let's see if this works. So we need one more thing here, which is an object map. So we need that. That will get passed in for us. This object mapper is equal to object mapper, right? So the reason we need that is we are basically reading in some JSON and trying to map that JSON, deserialize that into objects. And what are we trying to deserialize that into? We're trying to deserialize that into a list of runs. So just like I have run, I'm going to create a quick record. So I'm going to call this my runs. And this will be a record, which is basically just a list of run runs, right? So now I am deserializing that into a list of runs. Run repository all runs. Oh, do we call that something different? So now, again, you don't really need to know this type of code. I just thought it would be nice to show an example of reading some data from a JSON file and inserting it into a database. You could certainly, in the command line runner that was in application.java, insert 10 records on your own and you'd be off and running. I thought this would be a good example. So basically, we're going to read from that file, which is runs.json. If we can, we're going to try and map those to the runs record. We do a little bit of logging here to say how money runs we are loading. And then we save them all. Using that run repository, we're going to persist these off to the database. So let's go ahead and one more thing. This class will never run, because we haven't told Spring about it yet. So we just need to mark it with at component to say, hey, this is something I want you to be aware of. So let's go ahead and run this application. We see reading 10 runs from JSON data and saving it to an in-memory collection. That is probably from some older code, but we'll just say saving it to a database. So this will probably already restarted, but let's do that. And then we can go to the browser. We can reload our database here. And we can say connect. And now we can click run. And now we have 10 runs in the database. And we've loaded those through that JSON file. So cool. We're doing some fun things here. We've connected to a database. That was pretty easy. We're using an in-memory H2 database. We've made some progress replacing our in-memory run repository with a repository that is actually talking to the database. And then we just did some kind of batch operation where we can read from a file and insert into a database. So this has been fun. We're not done yet. Next, what I want to do is kind of replace this in-memory database. This was fun for getting up and running. But let's talk a little bit more about how we can take this one step further. All right. So we've already looked at using an embedded H2 in-memory database. Now I'm going to talk about using something a little bit more production-like, and that is a PostgreSQL database. So from a coding perspective, there's not much change. Now we saw with H2 database, we could simply fire up the application, and we had an in-memory database up and running. With something like PostgreSQL, there's a little bit more, but not much. So I'm going to go ahead and comment out this. And all we would have to do is go ahead and set up a URL, a username, and a password. Now the URL looks something like jdbc colon postgres SQL, something like that. Local is 5432 runners, and then you have a username and a password. If you have a postgres database up and running on your local machine right now, you could do that. Set up a runners database. And then now let's talk about a couple things now. First off, you need a postgres database up and running. So how can we do that? You can download, you can install it, or you can go the route which I'm going to go, which is like the Docker route. Second off, in this schema file, this schema file only gets picked up by embedded databases by default. We are not going to run this automatically when you're using something like Postgres or MySQL. So you have to tell us that, hey, I do want you to go ahead and run that. And the way that you do that is by using the spring.sql.init mode and setting that to always. So that would be good if we have a database up and running on our local machine, which I do not. So you could go ahead and install Docker. So Docker is a way to run a container. A container can be anything from like a database to another application to whatever application we can containerize, right? In this case, it's going to be a Postgres SQL database. This means that I can just run a Docker command and spin up a Postgres database without having to download and configure all, do all the things that we used to do. So you could, you have a couple options here. You can come in here and there is a, if you go to Docker hub and look for a particular container, in this case, Postgres, you can go down. How do you start a Postgres instance? It has the actual Docker run command. You could run this, but then you need to configure your properties and you need to do this every time you start your application up. There's also something called Docker compose, which is a file. In this case, Docker dash compose.yaml that could sit in the root of your project and you can run Docker compose up. It'll look at this, find all the services that it needs to start up and start them up. And this is really handy because imagine a scenario where we had, you know, Docker, Postgres running Kafka, RabbitMQ, some other thing, you know, some other microservice. So this is really nice to be able to like start up services. And in Springlude 3.1, we introduced the Docker compose module, which simplifies a lot of things and we'll talk about those. So when you're over at start.spring.io and you pick a dependency, let's talk like Postgres SQL, right? When you pick the Docker compose module, so we go in here, Docker compose support, it's now going to look at all the other services or dependencies that you've selected. So you've selected Postgres, maybe you've selected Kafka. And what it's going to do, it's going to create a Docker compose file with those services listed. So one way we can look at this is by checking the explorer. And again, I'm going to choose Maven. I'm going to check the explorer and there is a compose.yaml file now. So now this is listing the services based on the dependencies that we've had. So this is really good. So that's the approach that we're going to take today. So I'm going to show you this from the palm.xml. I'm going to copy this Postgres SQL driver and the Docker compose support. So with that, we can head back over to our IDE here. And I'm going to go into my palm.xml. I am going to just delete the H2 database and now bring in the Docker compose support with the Postgres SQL driver. I'm going to go back here and copy the compose.yaml file. So just copy that. And I'm going to create a new file in the root called compose.yaml. Now, if you have other conventions, maybe you put this in a Docker folder and call it Docker compose or whatever you want to call it. You can go ahead and set this up in your properties file. You can change where we're looking for that. By default, we're looking for compose or I believe Docker-compose in the root of the application. So I'm going to post that. Go ahead and set that in there. Now, I want to make a couple changes to this because the first thing is the image. I'm going to leave this how it is, but you may want to change it. So the image is saying, hey, grab whatever the latest Postgres image is. Great for whatever we're doing right here today. But if you're on a team and other people are pulling this down, we want to make sure everybody's on the same version. So you may want to specify a version here. In this case, I'm going to set a database of runners. We'll call this my username. Let's call this password for very secure password. And then we'll go ahead and set this to Dan. So that's the username, password and the database name. Now the port, interesting enough, when you use a Docker compose file and you just specify one port, what that's saying is on my local machine, just use a dynamic port. I don't care which port you're using, but on the container side, I want you to map it to 5432 because that's the port that Postgres is running on in the container. Now this is fine, but in the instance that I want to actually connect to the database, I need to know the port number. Now you could jump through some hoops and run some commands and find out at runtime what port this is using, but I want to be very specific here. So I'm going to say, hey, this is 5432 is going to map to 5432 on my local machine. Now when we use our database tools, we can connect to the database using that port. So with all of this in place, I think what I want to do is just restart the application, see if we have any errors. Oh, and we do because Docker desktop is not running. So let's make sure Docker desktop is running on our local machine to make this work. Again, if you don't have Docker desktop, no big deal. You can go ahead and set up an actual Postgres database and connect to that. That's fine. But now you can see it says using Docker compose file, it sees some services and it goes and went and went ahead and fired those up. So that's up and running. Now we have a database connection to a Postgres SQL database. And we've actually read 10 runs from JSON data and saved it to a database. So let's test that out before we had the H2 council. Now, how can we go ahead and look at our database? If you're not using IntelliJ Ultimate, don't worry. There are plenty of free grade tools out there to connect to database and manage them on Mac and Windows, Linux, etc. So go ahead and find something like that. If you're in IntelliJ Ultimate, you can just click this database icon, you can go here and say, I want to add a new database. And I'm going to say this is Postgres. And this is on localhost. Again, 5432. That's the important part. The username was Dan. The password was password. The database was runners. And that looks good. So now that's the JDBC URL, the connection string that we need to connect to the database. Let's see if this works. We'll go ahead and say, OK, come in here. We see that there is a table. There is a run table. And we see that we have our 10 runs in there. So this is really great to see. So we have our connection to our database. Now, I want you to notice something here because we've declared some properties in here. But I don't have any of those properties set up here in my application, not properties. That is because we don't want you to have to duplicate these properties, right? We have a database. We have a username. We have a password. We have a port. We don't need to duplicate these across both files. What happens is Spring uses something called the connection details interface behind the scenes. And there are some implementations of this, one of which is being able to create a JDBC connection. And it will read this at runtime and fill in those properties and put them into a property source at runtime for you. So it knows how to construct a JDBC URL. It knows how to get the username and password, et cetera. So that's really nice that we don't have to kind of duplicate those properties. So that is Docker Compose. Let's talk about one more kind of abstraction at the database level. OK, we're back over here at Spring.io. If we go to projects and you go down to Spring Data, this is a really cool project made up of and has many, many modules underneath of it. You see here it says Spring Data's mission is to provide a familiar and consistent spring-based programming model for data access while still retaining the special traits of the underlying data store. So we know that different data stores, different databases have special traits. We kind of keep those underneath the hood and we're allowed to use some of those special things that different data stores can do. You'll see that there are some features here. So powerful repository and custom object mapping abstractions. This really allows us to define an interface in Spring Data and have it get turned into an implementation at runtime. What this means for you is that you don't have to write all of these CRUD methods out. We saw the JDBC client. I really like the JDBC client. It's nice. It's fluent. It's easy to read, but I still got to write all that code to get just some simple CRUD things going on, right? Maybe I want an MVP. Maybe I want to kick something up real fast. I don't want to have to do that for every resource in my application. So Spring Data allows us to kind of bypass some of that and do it for us. Then when you have special needs like, hey, I got to find all the runs by location, then you can write these dynamic query derivations from the repository's method name. So you can just write, return to me a list of runs, and we're going to call this method find by run, find by location, and pass a location in, right? So this is really cool. Spring Data has a lot of really powerful concepts. Now two of the most popular Spring Data projects out there are Spring Data JPA, which is an implementation of the JPA specification, the Java persistence abstraction. And this underneath the hood by default uses Hibernate. So you might have heard of an ORM or Hibernate before. That's what Spring Data JPA is doing. Spring Data JDBC actually simplifies a bunch of things by kind of getting rid of some of the things that Hibernate does, and really just allows you to model your domain objects and use kind of straight SQL that we're used to writing. And it still gives you the power of repositories, dynamic query derivation, and so on. So we're not going to spend a lot of time on this today. We could really create a whole course on Spring Data and some of the other implementations. In fact, you could create a whole course on just like Spring Data JDBC, right? So what I'm doing here today is I'm just showing you this as an option so that once you get past like the JDBC client and some of the basic stuffs, you know that this is available to you. And you'll probably come across code out there that's written using Spring Data. And so I just want you to be aware of it as you're getting into it. So from start.spring.io, you would pick something like Spring Data JDBC. You would pick your database, in this case Postgres. We would pick the Docker Compose support. So if I go look at Explore, again, I'll come back and choose Maven. If I look at Explore here, the starter for this is Spring Boot Starter Data JDBC. So I'm going to go ahead and copy that. I'm going to head back to the IDE. We're going to go over to our palm.xml. And I am going to just put this right here. And we're going to reload Maven. And I'm going to actually stop this for now. And so now we're going to talk about like what does this do for us? So let's go ahead and look at run and look at our run repository. So right now this run repository has like all this code in here that we wrote using the JDBC client. So I'm going to actually rename this. So let's say rename room JDBC client. Sorry, my shift key has been sticking on me lately. I got to fix that. So JDBC client run repository. That's going to break some other things, but that's OK. We'll fix that now. So what I'm going to do is create a new one. We're going to call this run repository. But this is going to be an interface, not a class interface. How is this going to work? All right. So let's go ahead. We can extend some of the repositories that Spring Data gives us because it's a CRUD repository. For JP, there's a JPA repository. There's also a list CRUD repository. Now the arguments that it's taking here is the type and then the ID of that type. So we're creating a repository around the run type. So we have a run already if we had like a user, if we had equipment, right? Like we could create repositories around all these different types. So the ID type of a run is the integer, right? So now that we have that, that's one piece of the puzzle. The other piece is we have to come into run and we have to mark the integer. We have to say, hey, this particular thing is the ID of our type. So we're saying this is the ID. I'm going to do one more thing. And this is kind of specific to Spring Data JDBC. And that is there is an at version column. And we'll call this integer version. And this is just a way to track whether this is a new type, a new row or an existing row to keep it simple. All right. So with that, I need to make one more change. And that is to the schema. And I got to go ahead and say that I need a version. And this is an int. It can be null. So that's okay. Yeah, so that looks good. So now with all of those in place, I haven't done anything. Let's look at this list CRUD repository real quick. So first off, there's a save all method that will return a list of types, right? There's a find all, which will return a list of those. And then there's a find all by ID. We can also see there's a CRUD repository. So we can save, save all, find by ID, exists, find all, find all, count, delete, delete, delete, delete, delete, right? So all of these methods are available to us out of the box based on that type. And we don't have to write any of that code, which is really nice. So what this tells me now is if I look at my run controller, I'm pulling in that. Okay, so this refactored it. Let's go back to the run repository and see if that breaks anything. So yes, so this needs to be a run repository. So that looks good. So now our create method, we may need to call save instead of create. This is save. And this actually doesn't take in the. Right. And then the delete doesn't delete. So now the delete method doesn't take an ID, it actually takes the run to delete. So all I'm going to do is use the run repositories that find by ID, and then pass the ID in there. And we'll say get, we could do, there's another one, we could do this a little bit safer, but this is okay for now. So now my controller is basically lined up with the new run repository that is using Spring Data. Again, we haven't written any logic here. Let's go ahead and see if we can restart our application. So again, looking at that compose.yaml file. All right, now something interesting happened here. Says not loading runs from JSON data because the collection contains data already. Remember, we had in our JSON loader, we had this, hey, if the run repository dot count, now the run repository dot count method is using the new repository that uses Spring Data, there's a count method in there. So it'll count how many rows there is. Is there zero rows? If there's zero rows, go ahead and read from the JSON and save those. If not, hey, we've already got rows in there. Because remember, now we're using Postgres. This is not resetting every single time that we restart the application. So if we were to go into our database again, look at our table, we'd still see our 10 runs, right? So that's interesting. The other part is, yeah, if we go to the terminal, and let's just clear this and HTTP IE, so 8080 slash API slash runs. Oh, we got a little error. Prepared statement has a bad SQL grammar. That's okay. We like errors. Let me look over here. This is a little bit hard to read. So let's find out what's going on here. Okay, so bad SQL grammar, select run, column run dot version does not exist. Okay, so what happened is, probably the schema didn't get rewritten that second time when we added version. So let's just go ahead and come to this database. And I'm going to drop this table. Right. So now if we restart the application, it should see that that table doesn't exist, and go ahead and add it. And now it added those 10 there. So now let's go ahead and refresh this and make sure that it has the version, which is null. Okay. Right. So now that looks like it's working. Let's go ahead and check our terminal again, and go to 8080. There we go. Now we have our 10 runs in the system. So cool. I want to show you one more thing with Spring Data. Again, I just love geeking out over this stuff. So one of the things that we've done is add all of this like custom or crud functionality. But what if we wanted to add some custom functionality? What if we wanted to say, hey, give me a list of runs, and I want you to find all by location, and then pass in the location that you want to find all by. Next, this is not find all by. And then as you can see, we also get IntelliSense. This is based on the type that we're working with. So you could find all by completed on, completed on after, and you could start to chain these together. You could say, find me all by location and by miles, greater than. So I want to find all my outdoor runs greater than five miles. You can do that. You can start to chain all these together. Now I will say once you get into like, if you start chaining three or four or five or six different things, there's probably some better ways that we can do it. But that's OK. So I'm going to say find all by location, and I'm going to pass in the string location. And then I could just go into my controller and create a custom method for this. So I could say, yeah, that looks good. Get mapping. And I can say, list of run find by location, path variable, string location, return find all by location. That looks pretty good. Let's see if we can restart our application and do that. So now what I would do is go to this slash location slash outdoor. Right. And now it finds all of the outdoor runs. So is there no indoor runs? Let's see. Oh, there's a few. Oh, yeah. OK. So OK. I was looking at something different. I thought it was the 10 showing me the 10 of them. But yeah. So that was a quick way to write a custom query. You can also come in here and add the at query annotation. So if you wanted to write your own query here, you could do that as well. So there are a bunch of ways that you can add functionality on top of this repository that gave you all this CRUD functionality out of the box. So I think that's where we're going to wrap up our database section. I hope you learned a lot in the section. We started off by kind of replacing our in-memory collection with an H2 embedded database. We talked about connection strings and all those things. We talked about how to use the JDBC client to get data in and out of our H2 database. And then we moved on and we replaced our H2 database with a Postgres SQL database using Docker, using a Docker Compose support in Spring Boot 3.1. And we finished it up by taking a look at Spring Data. So I hope you learned a lot in this section. I had a lot of fun. But with that, it's time to move on to the next module. In this module, I want to take a look at REST clients. Now, we built out our REST API and we've talked to a database to get some data. But what you'll find is often in organizations, in applications, they're not just standalone applications, huge monolithic applications. Sometimes we're dealing with microservices where this particular application is dealing with one thing and maybe to get data about say a user, it has to reach out to another service in the organization. The question is, how do you talk to that other service? One such way is by using a REST client. So here we're in the Spring documentation. You can see the Spring framework provide the following choices for making calls to REST endpoints. Now, I'll give you just a really quick history lesson so you understand why there's some options here. So when Spring MVC first came about, the REST template was born. And the REST template was a way to make a client call to another service. The REST template over time had issues come up and, hey, I need to be able to do this in this sort of way. So over time, that API grew into the API that it is today. So there are a lot of overloaded methods in the REST template. Well, when Spring Web Flux came along, which is the reactive stack for building web applications or web APIs, they decided to take a look at the client and kind of start from the ground up. So they built the web client. So the web client is used strictly in the reactive world, but you could use it in Spring MVC apps before because it had a blocking call. So you could say, hey, do this, but this is going to be a blocking call. So the web client was really great. Folks really loved it because it had this nice, fluent API. It was easy to understand. There wasn't all these overloaded methods. And so we found that a lot of developers were bringing in the web client into their Spring MVC apps. So from that, the REST client was born. And the REST client is a blocking, synchronous client with this nice, fluent API. Really easy to use. And so that's what we're going to do today. We're going to take a look at the REST client, and then we're also going to take a look at HTTP interfaces. This is a really nice feature that allows you to talk to another service by just defining an interface and not having to write the low-level implementation to talk to another service. We saw an example of this in the last module with Spring Data. I need some crud functionality, but I don't want to write all of it. Just define an interface and let Spring turn it into an implementation at runtime. HTTP interfaces is analogous to that. So let's have some fun here. Now, we don't need to do anything as far as adding more dependencies because with the Spring Web dependency that we chose at the beginning of this course, that will bring in the REST client. And so we have everything we need. So now all we need is another service to talk to. So I fumbled around with this and thought about some different scenarios that we can go through. We could have created another application to do something, maybe to bring in a list of locations or something. But I thought I'd just go a little bit off the path of the runner's application and just use kind of a public API. That way, you don't need another service. This is a public API that anybody can talk to, and you don't need to authenticate against it or anything. So this service is called JSON placeholder service. And again, you can go out and test this on your own. You can see you can go try it. Hey, I want to talk to to-dos. I want to get a specific to-do. You can get it and it will give you back a to-do. Now, there are a bunch of different resources here. So I've done stuff with all these different endpoints before, but the one we're going to work with today is users. So we're going to set up. We already set up a user package earlier. In the user package, this is where we're going to define all of the code we need to talk to this service and bring us a list of users. If you want to keep it in the realm of this runner's application, let's just pretend that we have a bunch of users that need to log in, and maybe we get those users from another service, and this is that service. So here is what a specific runner looks like, a single runner looks like. I'm going to copy this because what we want to do on the Spring side is model a type after this. We're going to create a record based on a user, and it's going to have a couple things, right? It's going to have some fields, but it also has other types, like an address. An address has a geo. We also have a company. So we need to model this out on the Spring side so that when we call this service, we can say, hey, what I expect back is a user, and all these fields will kind of line up. So I'm going to copy that. I'm going to go back to IntelliJ. In a user package, I'm going to create a new Java class. We're going to call this user, and this is going to be a record. And then let's just put this on different lines. And now Copilot, again, is on its game because I've done this one before. So it's remembering this. So let's just go ahead and paste. I'm also going to paste this up here just so we can kind of see, oh, let's put that in a comment, Dan. And let's put that there. So now we have ID, name, username, email. Address is its own type, which is going to contain geo, string, phone, website, and then company. So now what we need to do is create an address. So let's create an address record. So I'm going to go ahead and do that. And let's put this on separate lines, and it's going to figure that out as well. So let's, I don't know why I keep hitting the wrong button today. Create record geo. And then what is geo going to have? It is going to have a lat and a long. All right. I think there's one more we need to create, which is going to be the company. And so let's create a company record. And this has a few fields, name, catchphrase, and yes. And then we go. So now we have something in our system that we can model after a user. So when we call out to that system, that public API, we could say, hey, give me back a list of users or give me a single user, right? So I'm going to create a new Java class here. We're going to call this the user rest client. We're going to call this the user rest client. And this is going to be a class. And we need to mark this with something. So I'm going to mark this with a component, just because if we want to go ahead and use this later, we want to tell spring hey, manage this class force, put an instance of this into the application context. So what we need is a rest client. So I'm going to say private final rest client. And we'll call this rest client. All right. So we've declared this rest client. But how can we get an instance of it? Let's take a look at rest client. And we notice right away that it's an interface. So we're not going to be creating a new instance of the rest client. But if we drill down into this, there are some static factory methods which we can use. So we can create a new rest client. We can also create a new rest client with a base URL. We can also create one from a rest template. So if you have a rest template instance, you can create a new rest client from that. And then there are these builder methods. And builder is actually an interface in here as well. If we look at builder, there is a default rest client builder that implements that rest client builder. And this is something that will get created by Spring Boot. So we'll have an instance of this default rest client builder if we just ask for an instance of the rest client builder. In here, you'll see that it declares a bunch of things, these private static final Boolean for like the JDK client, the JD client, the HTTP components client. We'll talk more about that in a second. So if you want, you can dig into that and see what the default rest client builder is. This means that we can come down here and we can create a new constructor. So we can say public user rest client. And we can get an instance of that builder. So we can say rest client builder. And it will basically pass in that default rest client builder. So now we have a builder, co-pilot. Yes, thank you. So we're using the builder to set the base URL. So the base URL is the JSON placeholder service. So if we go back to the browser, you'll see, this is going to be the base URL, this slash users will be the the URI for all the users. And then if you wanted to get like a specific user, you could say slash users slash one. Alright, so now that we have kind of our rest client ready to go, we can start to write some methods to interact with this service. So I want a an instance where I can get a list of users. So I want all the users, I might call this find all. And I'm going to return whatever the rest client dot and now this is for me one of the big advantages of the rest client over something like the rest template that had all these overloaded methods. When I hit rest client dot, I'm given some options here. It's not a whole lot of overloaded methods. These are the request methods. I know that, hey, I want to perform a get a put a delete a post, etc. So I know I'm going to perform a get here. The URI off the base URL is going to be that slash users that we saw before. Next, I need I basically have two options here. I can use retrieve or exchange. Now retrieve is kind of the simplified version of this where exchange allows you to get a little bit more control over the request and the response. So I'm going to say retrieve. And then finally, hey, what do you want us to do with the response in this case, the response body? In this case, I want to just turn it into a parameterized typed reference. And this is a way that we can get a list of things. So that will give us a list of users. How can we ask for a single user? So I may just want to get a user. I may call this fine by ID. I'll get an integer ID. Then I'm going to use the REST client dot get. I'm going to use a URI of slash users slash dynamic ID. And we're going to replace that with whatever we get as an argument to this method. So now we have a URI there. Next, we're going to retrieve. And finally, we're going to turn this into a body of what type, we're going to model it after that user record that we created. So great, we have two methods here that allow us to basically find all the users and find a specific user when we're talking to that other service. So normally, I would write a test against this, we're not going to get into tests until the next module. So right now, just find a quick way to test this out using the command line runner. So what I want to do is get an instance of that client. Let's just go double check that we marked it with a component and we did. So now we know that we can get an instance of this here, because it's in the application context. And let's just make this simple, let's call this client. And in here, I can say, client dot find all that is going to return a list of users, we'll call that users, and I'll just sis out users, and we should be able to run this now. And let's see. And there are all the users that we pulled down from that JSON placeholder service. If we wanted to get a specific user, we could say client dot find by ID, we know there's one in there with one, so I could say dot bar, we'll call this user, and then I can just sis out a user. And we can go ahead and run that. And again, because that's a record, we get that two string component in there. So we have that single user we're splitting out. Based on that two string, we're able to view a representation of that user. So good. That was pretty easy, right? I like the REST client, I like this simple, fluent API that isn't complicated. Again, I just I can read this, I can look at this and like know what's going on. I want to look at a couple other options that you can talk about when you're using the REST client. And then we'll move on to HTTP interfaces. So what is happening underneath the hood, this is actually the API, this isn't the low level mechanism that is actually making that API call across HTTP, right? For that, there are a bunch of different options that you have. There is a default HTTP client underneath the hood, but you can always swap that out for something else. And you can do that using the request factory. So we'll look at the request factory. It takes in a client HTTP request factory. We'll see this as an interface. If we look at the implementations of this, there are a bunch of them. So if we wanted to use something like the JDK client HTTP, we could use that from JDK 11. If we wanted to use something like Jetty, or something from the Apache Commons, we can swap these out. So all we have to do is say new JDK HTTP request factory. And now I'm using a different HTTP client library underneath the hood. I could also extract this out to a variable. So if I wanted to, I can say new JDK HTTP request factory, let's set a var there. And now what I could do is I can customize the underlying HTTP client. So if I wanted to do something like set the connection timeout, I don't think that's an actual call. I think it's set read. So we have set read timeout, set read timeout with a duration. So we can kind of change this if we wanted to. We could say I want the timeout to be this instead. So this is a way to get at the underlying HTTP request factory and go ahead and customize it. And then I would just pass in this variable here. So that's one thing we can kind of customize. Another thing we can customize is if we go in here and say dot, we see that we can do something like a default header. Maybe we wanted to pass a user agent and say what the value is. We can set a default header here. So any call that goes out to the JSON placeholder service, we'll go ahead and pass this header along with it. Some other things we can do is by setting a request interceptor. So an interceptor will allow you to intercept that request, you can do it in line. So we can see if we look at this, this is based on the interface client HTTP request interceptor. This is a functional interface, you can pass a lambda there if you just have something simple to do. If not, you can implement this interceptor. And it allows you to get access to the request and you can kind of handle do some more things with that if you want. A couple of examples of this and I've done some of these, I think on the YouTube channel is what if you had to do like an OAuth 2 handshake and you wanted to go out and get a JSON web toga JWT and pass that in every request. You can do that there. Maybe you wanted, there's a really great project by a co-worker of mine for retries. So if you wanted to call this service, but whatever reason it failed once failed twice, I want to retry this service three times. These are all like custom things that you might want to do, but you can do them in an interceptor. So that is some other things that you can do. So we've looked at the user REST client. This is really great, but again, I'm writing some code here. What if I don't want to write code? And we saw this already in the Spring Data example where we can declare an interface, have Spring turn this into an implementation at runtime, and handle some of this for us. So that's what we're going to take a look at now. And we're going to do that by creating a new Java class. And we'll call this the user HTTP client. And this is actually going to be an interface. So let's say interface. And then all we're going to do in here is write out the contracts for the methods that we want. This is going to look pretty similar to this. We want a list of users, find all, we want a user find by ID. So let's go ahead and put those in here. So I'll say list of user. And this is called find all. And again, all we're doing is creating the contract. And in this case, user find by ID, and we'll actually get this through a path variable. Now we need to kind of hook these up and say these are going to be, we have to give them an annotation to say, hey, like this is something I want you to make an exchange with another service for. And the way that we do that is there is the HTTP exchange annotation. But there are also specialized versions of this. So this is a git exchange. So I'm going to use the git exchange annotation. And then you're going to use the URI. So remember with the REST client, we'll set a base URL. And this is the URI. So for this one, we'll say git exchange. That almost looks good. Let's say users slash ID. And now this is all we have to write in this class. We don't have to write out all of this boilerplate. Now there is one boilerplate thing we'll have to do. And this is basically setting up that REST client and telling Spring, hey, this is a user HTTP client. And I need you to go ahead and create this for me. So the way that we do this is user, actually user HTTP client, user HTTP client. We're going to use that REST client to, oh, yes, the code pilots on its game. So really what we're doing here is we're creating a REST client using one of those static factory methods. We're setting the base URL. We're creating an HTTP service proxy factory with that REST client. And then we're just creating a client and we're returning this user HTTP client. Now again, this is a little bit of boilerplate. I usually have like a live template here in IntelliJ that creates these for me, or a co-pilot. If you've done it enough, it will go ahead and write it for you. Once this is in place, this creates a bean. This is now a bean in the application context. So I now have access to that. So really, all I got to do here is switch this out for the user HTTP client. Because I've named those the same, this should just work. But again, we haven't actually written any code to talk to that service. This is being done for us by Spring at runtime. So pretty cool stuff with HTTP interfaces. Now again, this in Spring Boot, in the latest version of Spring Boot 3.2, this is using the REST client underneath the hood. We can see that here. We're using REST client. In previous versions, if you're on something like 3.0, you would have to bring in the web client to make this work. But now this just kind of all works seamlessly in the MVC stack. So pretty cool stuff. I hope you got something out of this. We talked about a little bit of the origins of REST clients in the Spring world, how we've gotten to the REST client in 3.2, HTTP interfaces, to kind of simplify and take away some of that mundane boilerplate code that we have to write. So with that, I think we'll end this section and we'll get ready to start writing some tests. I will write some tests against this and a whole bunch of other code that we've written here in this course. So with that, let's move on to the next module and talk about testing. In this module, I want to cover testing. Now I talked about this early on in this course. This probably isn't the route that I would go if I was building an application today. I would write a class and I would write a test for it. But I didn't want to bog you down with the mechanics of writing a test. So I went through and we built out an application. We built the REST API. We talked about talking to a database. We talked about being able to communicate with other services via the REST client. So now I want to kind of step back and talk about testing and specifically testing in Spring Boot. One of the things I love about testing in Spring is that there is no need for you to opt into testing. We've already done it for you. So we are giving you all the tools you need to write your tests. And there are a whole bunch of tools available to you right out of the box. And I want to start there. So if we're on the Spring Initializer and we don't pick any dependencies, we go ahead and check Maven and click this Explore button. You see down here, we have this dependency for Spring Boot Starter Test. Now Spring Boot Starter Test is made up of a bunch of dependencies. It gives you a bunch of tools out of the box. The nice thing is this scope is in the test scope. This means that these dependencies are loaded when we're using tests. But when we build our artifact for production, then all of this kind of gets stripped out. So we're not asking you to bundle a whole bunch of libraries in there when you're not going to use it for production. This is strictly for testing. And there is a bunch of stuff that comes with it. And we'll go through some of that. So the first thing I want to look at is in your test package under Java, there is a single test. In this case, it's called runner's applications test. We could even rename this because I renamed the application. So I can rename this to application tests and refactor that. And there's a single test in here called context loads. There's no code in there, just a context loads. Now we can run our tests via the IDE. There's also a Maven plugin to do that. So I'm going to do this right from the IDE. You can say run application. And this will run the application tests. And if we look in here, we see fail to load, something has happened. And I think, and this is because of some of the things that we're doing with the database connection. I haven't refactored this to make this work out. But what this will do is it will basically fail if some exception is thrown and something's happening now with that. Basically, the database and the test environment isn't configured. But if you download a project from start.spring.io, you create this new project and you have the single test in there, this will work right away. And so this is a test that I would often keep in here. I get a lot of questions like, should I delete this? No, keep this test. This is a good sanity check. The context loads means, can I just get an application up and running? And from this standpoint, I can't because I have some things going on with the database connection. But most of the time, this will just kind of give you a sanity check. So this is a good place to start. This is my main test. And this is going to kind of stay there and give me that sanity check. Now there's another annotation in here at Spring Boot tests. I'm going to download the docs for that. And this is one you're going to come across often. This annotation that can be specified on a test class that runs Spring Boot-based tests provides the following features over and above the regular Spring Test context framework. So it does a whole bunch of other things. It allows you to set a context loader. It allows for custom environment properties. So you could pass in properties to override something. In this case, the data source, right? We could maybe switch back to an H2 for a test. I wouldn't do that, but just an example of something we can do there. Provide support for different web environment modes. So you can basically start a fully running web server or start some kind of mock web server that could be on a defined port or random port. Doesn't matter. So this is nice. The Spring Boot test, it's kind of like the kitchen sink for being able to test different things in spring. Also does things like register a REST template, test REST template, or a web test client being for web tests that are useful using a fully running web server. So I need to talk to like some other service, right? So this is the Spring Boot test annotation. You'll come across this often. Next, I want to go ahead and look at some documentation. So I'm going to go over to spring.io. We're going to go into project. We're going to go to spring boot. And under the learn section, we'll go to the reference docs. And in here, this is kind of broken up into different sections. If you look under core features, we see profiles, logging, testing and more. So this is where I want to be. So I can go into core features and go down to testing. And this is where I kind of want to start. So spring boot provides a number of utilities and annotations to help when writing or testing your applications. Test support is provided by two modules. The spring boot test contains core items. The spring boot test auto configure supports auto configuration test. Most developers just use that spring boot starter test, that starter that we saw that got included, which imports both spring boot test modules as well as JUnit, JUnit and Jupyter to be specific, that's JUnit 5, AssertJ, Hamcrest, and a number of useful libraries. By default, we're using JUnit 5 now not JUnit 4. So if you need to use JUnit 4, there's a way but we're using JUnit 5. So here's what I wanted to talk about. These are the number of dependencies, the tools that you have at your disposal. I think part of the key is, you know, we've talked about it, spring's been around 20 years, spring boots been around 10 years. If you go search for something, and you say how to write a controller test, like you may get all these different examples. And you're like, what are all these things in this test? I don't understand what these things are. And part of that is understanding what things are available to you out of the box, what libraries, right? So JUnit, the de facto standard for unit testing job applications. This is how we write our tests, how we there's a test runner, how we can run our tests. The test annotation comes from JUnit. JUnit also comes with some assertions. So I want to do this thing and then assert that this particular thing equals some value that we expected to write. So that's JUnit. Spring tests is kind of the core testing utilities, the integration test support for spring boot applications. Assert J is another way to use assertions, it's just a different way of using them as this nice fluent library. So you can use the ones that are in JUnit. You can switch over to Assert J, which I know is very popular. I wouldn't recommend mixing and matching both because you kind of want to just stick with one style, right? Hamcrest is another way to go ahead and match on things, also known as constraints or predicates. So those are the kind of core things. And we get into Makito. So Makito is, hey, we want to mock something out. So in the example of our controller that uses that repository that talks to a database, when I want to test the controller, all I care about is the controller. I don't really care about other dependencies. I don't care about talking to a database, talking to another service, fetching data from some event-driven architecture. I don't care about those things. I want to mock those out so that I'm only focused in on the controller. And Makito is, again, the de facto standard when it comes to mocking in the Java universe. Then we have a couple others for dealing with JSON. So we have JSON Assert and JSON Path. Whenever you're trying to test Assert against particular sets of JSON data, these two libraries are very helpful. And then we have Awadability, a library for testing asynchronous systems. So it's good just to know what's in there. These links in here are all links to the documentation on the various libraries. You don't need to study them and become experts on them. But I would dig through there and just get a really good overview of what they are and what some of the code looks like. That way, again, when you see a code example online or somebody shows you some tests, you can quickly scan it and understand what libraries are being used to kind of build out those tests. Okay, so that's enough of an overview. Let's go through and start writing some tests for some of the code that we've written so far. All right, so the first thing I want to look at is getting this context loads test to work. Again, if you just download a project, this is going to run right away. But we're running into an issue here. And I want to talk about that issue. So we are using a database. That database is because we are using this compose.yaml, right? When a Spring Boot application starts, it will see that file, it will run Docker compose up, and that is in that connection gets created and put into the environment at runtime. We're not running an application. We're running a test. So it's a little bit different of a workflow. So we don't have a database up and running. So in the test scenario, I would have to come in here and actually run Docker compose up so that that database starts up. See it start in a second. And that is up and running. And now that that's up and running, I have to come in here and actually set a data source because again, it's not getting injected from the Docker compose file because that's not getting run in a test scenario. So now that I have this up and running, I should be able to run my application tests. And that should work. Now, in a real world, I would not do this. This is not my workflow. In the real world, I would use something called test containers. If you haven't heard about test containers yet, it's a really great project. Go ahead and check out testcontainers.org. You can go ahead and check out the docs to learn more. There's different languages support, but the Java support is really great, has a bunch of really great features. And really, it just allows you to say, Hey, I want to the same way that we used a container for development, we could use a container for testing. And I like this approach much better. We used to maybe use something like an in memory database, like an H2 database for testing. But then we have an H2 database and testing a Postgres database in production. And we're really not aligned, right? Like we want to be as close to production as we as we can get on our local development machines. So in that sense, I like using test containers for tests. But to keep this short, I think we'll just leave that at that. For now, I have some more videos on my YouTube channel, if you're interested in learning more about test containers. But we'll just leave that as it is for now. So I want to focus in on some other tests. And to do that, let's go ahead and close this out. I have brought in our in memory run repository. I think we overrode that here while we were going through stuff. But if you want to grab it from the repository, it's there we've we went through this, right? This is just using an in memory collection. So I want to talk about how to test this. So the first thing I'm going to do is go ahead and generate a test for this, I can say create test. And this will actually create the right package and the name of the test for us. Now JUnit is looking for tests that end in the word test or tests. So that's why it gives us this nice class name, it says in memory run repository test. Yes, this is great. So I'm going to click OK. And now we're dropped into this test. And you'll see this test is now in the right package down here. Cool. So now we can begin to write our tests. Now we aren't going to use any annotations on this, we aren't going to do any kind of special things with the spring environment. Because in this case, we just have a class that holds some data in a data structure, a list to be specific. And we don't need to involve spring in this. This is for me a true unit test, right? Because all we care about is the in memory repository. We'll call this in memory repository, although that's kind of long, let's make it easier. So now I have a repository. Now if that repository gets created, we can let's do actually let's think about this for one second. So I'm going to in JUnit, there are some special methods that we can use. So we can basically say, hey, before each, I want you to go ahead and do some setup in my application. So I'll call this setup. And oh, that's pretty good. Let me just I think I need a null here. And a null here. Right. Right. So that looks pretty good. So all we're doing is creating an instance of this repository. Now the reason we are setting up two runs is if we go into the in memory repository, we have a create method. And this method is actually going to get called by the lifecycle in spring. So this app post construct gets called, and these get created. In this case, we are not involving spring. So that that init method is never going to get called. And we want to have a couple of runs in the collection to be able to test against. So now we can write a simple test, we can say at test. And we can say avoid should find, find all runs. And yeah, that's a pretty good assertion there. So all we're doing here is and actually, let me let me let me let me get this out of here. Let's do this. Let's say hey, repository find all oops, find all and give me a variable for that. And we'll call this runs. And then let's just do this, just so we can be a little bit more clear what's going on here. Right. So what we're doing is we have an instance of the repository, we've created two new runs in there. We're saying, hey, if we call the find all method, basically, we're expecting two runs to come back, we know that there's two runs in there. We know that there's two that are going to come back. There is a third argument here. And you can basically give a message on what should have happened. So in this case, we could say should have returned two runs, right. So now we can go in and we can go ahead and run our test here. And we see that it's green. And green is good. Now, you also hear of like TDD styles. So I come in, I would write this method first, and then I would make it fail. And then I would go into the in memory repository and write this method. So a lot of the questions that come up around testing are like, what should I test? Well, like, what are you writing? What what classes are you writing? In this case, we're writing this in memory run repository. This is our code that deals with a collection of state. So yeah, we should be writing tests against this. In this case, we don't need some integration tests. We're just testing this class, right. So that's one test. We're gonna, we're gonna kind of copy paste a lot of this, I don't want to walk through every single method and every single test. And actually, these are gonna fail because we need nulls here. And again, this is just because I wrote these before the database stuff went in. Remember, we added that null. So we have some tests here should find runs with a valid ID should not find a run with an invalid ID. So it should throw some exception should create new run, although I don't know if that's gonna throw an exception. Maybe we'll check it. So I just have a bunch of tests in here. And we can run each of them individually, or you can run them as kind of a suite right here. And then we got greens for all of those. So those are good. Okay, so that's our first test are in mom in memory run repository. What should we test next? Alright, the next test we're gonna write has to do with the JDBC run repository. So I'm going to go ahead and create a test for that. Now this is going to be a little bit different, we are not creating a unit test, we have to deal with some of the infrastructure in spring. And we also have to like talk to a database, right? We're like, we're testing out this run repository. So to bring in the test support with spring, we could use that at spring boot test annotation that we saw before. But one thing I want to kind of talk about with that is, at first, your test might be very fast. But as your application grows in size, that might tend to slow the test down. And that is because that at spring boot test annotation is basically going to load the entire application context. That means all the classes in your system that you might need, it's going to go ahead and load those. But for this class, this test, the JDBC run repository does I don't really care about all of the classes in the system, really only the classes that were that that pertain to a JDBC test. And so there are these things called slice tests in spring. And that says, hey, this is the slice that we're testing now only load all of the things that are equivalent to that. So there are a bunch of this, one of these is at JDBC tests. So if we go into at JDBC test, and look at the documentation, we can see that, hey, this is an annotation for JDBC tests that only focus on JDBC based components. This means that it's going to disable full auto configuration, and instead only configuration relevant to JDB, JDBC tests. By default, JDBC tests are transactional, and roll back at the end of each test. That's good to know, right? Like if you add a new one, and then you move to the next test, that new one is no longer there. This also gives us an embedded in memory database, replacing any explicit or usually auto configured data sources. This is important. We're okay, we could be okay with using an in memory database. But what if you wanted to say don't do that, just use the one that I have. So we need to understand how to do that. So this is the at JDBC test annotation. Now, I want to use that repository, I want to say at auto wired, give me an instance of the JDBC run repository, right? So we'll see in a second. I don't believe that'll work. But we'll check that in a second. And I know we talked about this earlier, when it comes to dependency injection, we want to favor constructor based dependency injection, that really is in our own code in a test. I don't think that makes a big difference, because we aren't trying to test a test. So using reflection here is okay in my books. So we have a JDBC test, we're going to I'm actually going to just paste some code in here. So we can kind of take a look at this. Again, we're going to use a setup method. And this is going to, we're gonna have to fix these. So no, so I promise you all of these worked at once. But that was before I introduced the spring data component. So now you know, we're using spring data now. So the entity uses an ID on there. And actually, I think I may get rid of that for these tests. So let's do that. So let's go back into run and say that we're not using this right now. And then in my schema, I'll kind of remove this. Again, this isn't something you'll have to deal with. This is just me having to like, show a bunch of different layers of abstraction. And you won't have to deal with that. So okay, so let's see, we have a JDBC run repository tests, no errors. So all we're doing here is we're calling our repository, and we're creating some. And then we want to be able to like find all find by ID, the same things that we did in the in memory one, but this time, we're doing against the database. Now, again, which database are we doing it against? If we don't do anything, we'll be doing it against an in memory database. So let's see. Let's just I'm curious if see if that works. Let's go ahead and run that. Yeah, I didn't think so. These things are gonna start to complain still. And don't worry, those ones will still work now. So let's try and run that again. Oh, we have more, more, more. Alright, and we have some failures, but that's okay. That's probably not test failures. Let's dig into here. And yeah, so failed to replace data source within embedded database for tests, we already have a database up and running, right? So how can we fix that? Again, we don't want to use that in memory database, we want to say, hey, we already have one up and running, and we have one configured. So I can just say auto configure test database. And we're just going to say replace none. We don't we don't want we don't want you to replace it with a embedded one. So now if we go ahead and run this, we should be using the regular database. And we're still having an issue. I suspect it has something to do with us flip flopping back and forth between all of the different examples that we're using. But nonetheless, let's see if we can't debug this in real time. No qualifying mean of type JDBC run repository is available. So this is a good thing. This is basically telling us that hey, this run repository that you've tried to auto wire into this test doesn't exist. Why doesn't exist? This app JDBC tests only loads certain things in certain auto configurations. So if it's one of those classes that we want that we don't have available to us, we need to just go ahead and import it and JDBC run repository. Let's see if that works. All right, still some red. Yeah, I believe this has to do with that already exists. So again, we're getting into a scenario where we're just hitting this because of all the fun testing I'm doing. So let's just do this drop table if exists run. And then let's try and run that again. So this is just basically create every time. And there we go. So again, I think in the real world, we are I'm using something like test containers. I'm trying to avoid that because I don't want to throw something else at you. But these things that we're running into are all because of the demo stuff that we're doing. So that is our JDBC run repository test. We've now been able to write tests against two of those classes that we wrote early on. I think the next thing that we really want to test is the run controller. And we want to test this from two different angles, we want to write more of a unit test that just tests the controller, the inputs and the outputs. And then we want to test an integration of this, we want to say, Hey, if I run a test against this run controller that calls the repository, I want to make sure that works as well. So I think those are really those are the two tests left there. And then we'll write a test against the user client that we wrote earlier. Alright, so we're going to write a couple tests here for a run controller, we're going to create a new test, we'll call this the run controller test that looks good. This is also going to be a slice test, we are just testing the web, the web slice. So I can say this is a web MVC test. And we're specifically testing the run controller. So I'm going to set up a couple of things in here. And then we'll go ahead and write a test. So at auto wired, because this is a web MVC test, it will auto configure Mach MVC auto configure MVC auto configure cache, always drill down into some of these annotations. And you'll find out that they are really just annotations that are annotated with other annotations. But you can drill into these to kind of figure out what those are. But one of the things that it does is it gives us a Mach MVC. And this Mach MVC is the main entry point for server side spring MVC test support. So we can create a Mach MVC, then we can perform actions against it in a Mach environment. We could say, hey, I want to perform a get to slash form. And here's what I expect to happen. So this is really helpful in testing the input and the output of a controller. Also, I'm going to auto wire in the object mapper. We saw this earlier when we were dealing with JSON. This is from the Jackson library that comes in with the web support. And it allows us to basically convert things from JSON to a type or from a type to JSON. Here's where the fun begins. Now, remember, the controller is dependent on this thing called the run repository. That run repository talks to a database in a unit controller style test. We don't want to we don't care about outside dependencies, whether it talks to a database talks to a service, we don't care about that. So this is where constructor, constructor injection comes into play is we can mock this dependency, we can say, hey, provide me with a Mach being which is not a real one, it's just an in place one. So this is really nice. So we're saying mock this particular thing when you're setting up this run controller. Finally, because we're not talking to a database, we don't have any runs. So we're going to set those up here. So how how do we write a test that uses a mock? So first, we're going to start with a test. We're going to say void should find if I could spell right, find all runs, right? Come on, Dan. All right. So now what we want to do is we want to mock out this repository, we want to say we want to say when so this is coming from Makito. So why that did that. So when the repositories find method is called find all method is called, then return this list of runs that I've created, right? And so again, we're going to import that from Makito. So now we're going to use the mock MVC framework here to say perform a get request. So where does this get request come from? I don't know why I can't find this. This should come from mock MVC request builders that get. Yeah, so you can import that as static if you want, you should add exception for that. So we're performing a get request against slash API slash runs. And then what we expect is the status to be OK. And here's where we're using that JSON path. Remember all those libraries I said that get kind of brought in for us. So we're saying, hey, from a result mattress standpoint, what is the JSON path? And so let's bring in size. So basically, we're saying, hey, this is an expression you can say, hey, like from the root, give me the size. We know that it's going to be 1. And we want to make sure that it's equal to the size of the runs, which in this case is 1. So with all that in place, let's see if that works and it doesn't. That's OK. We like seeing red first, then we can figure out what's going on. So hey, the run repository is not available. Yeah, that would make sense. So run controller, we want to mock out the, I guess we're mocking out the wrong thing here. So let's mock out the run repository. And let's see if that works now. OK, cool. So we got one of our methods running, which is finding all the runs. Now, again, I'm just going to copy some copy and paste some code in here. So we don't have to watch me write this. But now what we can do is we can say, hey, I should find one run. Here's the run I'm expecting when the find by ID method is called. And you match any integer, then go ahead and return this. I want to return an optional run, optional dot of, and then here's the run. So now try to go get one run and expect that the status is OK and expect the data that we're getting back is this. Again, we're checking the input, so we're passing some path in here, and then we're checking what we get back. Part of what we're getting back in the response is, hey, is it a 200? Is it a 400? Is it a 404? If it is a 200, what is the data? So those are the things that we're checking in more of a controller unit test. We're not testing the whole flow yet. And then we're testing, hey, what happens if you return an invalid one? What happens if you create a new run or delete it or an update? So if we go ahead and test this out, and I believe that this may fail because we've switched over to this run repository. Again, too many moving parts, but let's see if we can't fix it. It's fun fixing things. So let's see. I believe this is saying delete API slash runs and expect status is no content. What is it? No value present. That's because I believe the delete should take the actual run. So we say API slash run slash run slash delete and content type is application slash JSON content type. And then the content is the actual run. So sure, that looks good. And then do we get one too many there? All right. So now, let's see. Let's go ahead and run this one. Actually, let's just run them all again. No value present. OK, I'm going to skip this for now. I have this updated in the final repository. So these are our unit tests more because we're not we're not including the outside dependencies. But what if we wanted to write more of an integration test? I want to see the flow when we go ahead and do something. And it talks to the database talks to the repository, which talks to the database. How can we get that to work? So I'm going to create another test here. But this time, I'm going to call this our run controller int test for integration because we're integrating other services, other libraries. And so this is more of a full end to end test. All right. So now we're writing the integration test for the controller. I'm actually probably just going to write one method here for this one. But I'll try and get the final repo updated with everything. So we're going to use at Spring Boot test annotation. Now, we're also going to set up a web environment. You see the code assistance already there kind of helping me out. We're setting up a web environment to say, I want to run a server, but I want you to run it on a random port because this is a test. I really don't care what port it's on as a test. But when we do that, we will need to know what port it's running on. And to do so, we can use the local server port annotation and then just provide a variable for that. So now we have the server port. Now we can set up a before each. And we can basically say, let's go ahead and set up a REST client. So we're going to use a REST client here. We've seen the REST client already. And we'll say REST client. And we'll say REST client is equal to, remember, there are some of those static factory methods, one of which is create. Oh, that looks pretty good. Thank you. And we're saying, hey, go ahead and set up the base URL as HTTP localhost, not 8080, but whatever that random server port is, right? So with that in place, we should be able to say at test. And I want to, again, should find all runs. And what I want to do is I want to use the REST client to actually make a call. So I want to say REST clients.get to the URI of API slash runs. So now that that's there, again, we'll just retrieve that. We'll turn that into a body of new parameterized typed reference. And then from that, actually, from that, I'll get a list of, whoops. From that, I'll get a list of runs. And I don't know why it's saying object. I don't want an object. I want a list of runs, right? So now that I have a list of runs, I can say, let's assert equals. And we should have 10 runs because we know 10 runs are in the database. Let's see if that works. So now we're actually performing an integration test where we make a call into the controller, it talks to the repository that talks to the database, finds all of our runs, and then asserts that that's equals. So again, we've written some other tests similar to this. Again, I would just do this for find by ID, post, put, delete, and call it a day. All right. So one last test I want to write here is for the user REST client. So let's go ahead and create a test for that. Now, we are not going to write this. I'm just going to kind of show you this one. But let's talk through this. So there is a annotation called the REST client test. And what this does is it's an annotation for Spring REST client that focuses only on the beings that use the REST template builder or the REST client app builder. So this is, again, going to disable full auto configuration. And really, all we want is the relevant stuff to a REST client test like Jackson or Gson or some auto configuration for JSON components, but not regular component beans. So not all the beans are going to get loaded. So if you find something you need in there, you'll have to import that. So what we also get from that, if you look at this, there's a auto configure mock REST service server. So we get this mock server. So we can use a server to make a call out. Then we get the REST client we want auto wear it in and then the object mapper, which we've talked about before. So now we have a test here. And we're using the given when then kind of set up. And we're saying given here's one particular user I have. And I don't know, new geo lat long. Why is this complaining? Oh, this wants a double. Oh, we set these up as strings for some reason. Okay. Those should be doubles. I think they're doubles in the final. So we'll fix that. Okay. So we have our user. And then we say here's our list of users. It really is just one. So now we can use the server to say, I expect a request to, and in this case, the JSON placeholder service slash users. So we're not actually calling out to the server this public URL. But we're kind of mocking that out. And we're saying, hey, I want you to respond with a success. And here's the media type. So let's go ahead and actually perform that. Go ahead and call the client dot find all. And I expect the users to equal this. So we're kind of mocking that out. And this is a way that we can mock those REST client calls out. So if we're performing a full integration test, we don't need to mock that. But this is a nice infrastructure to kind of test those out. So let's see if this works. And it doesn't. Yeah, this is because double can't be converted to a string. Is this same thing? Was I running all of those? Again, I think in the final code, this is a double. So let's just try and run this one. And there we go. And let's try and run them all. If they pass, we'll kind of look through them real quickly. That one doesn't. Yeah, okay, that's just the expectation. So there was the one. And then this is to find by single one. So we do that same request. But now we're doing it to slash users slash one, we're saying, hey, respond with a success. And here's what I basically wanted you to write this value as a string. So write the JSON. Now I can go ahead and do this, I can do a bunch of assertions here, I'm saying, hey, make sure the name is this, the username is this, and the email is this, and then all I can use is assert all to make sure everything in the address is what it's supposed to be. Again, double versus string. So if we run this again, so pass, then we're saying, hey, phone, website, and company, I want to assert all of those. So let's go ahead and just run that again to make sure that works. And it didn't. Maybe we had these backwards. Let's see, lat is 37, huh? Okay, we'll rerun these. Hopefully third time's a charm, and it is. Great. So those are the tests. Now I know we didn't kind of spend a whole ton of time on these, but I just wanted to give you the infrastructure, like what is included in writing tests and what are the pieces that I need to understand. You can easily go back through the repository later and actually dig through every line of code if you want to here. But I think just getting an overview of kind of what tests you can write, what are some of the annotations that you'll use, what are some of the libraries included that I'll give you. But again, I would try to stick to once you get the mechanics down. I mean, you're just learning now. If you're just learning Spring Boot, you know, build stuff first. But once you get the mechanics down, try to make it a focus of, okay, I just wrote this controller. What kind of test can I write for it? Or even better, before you write the controller, start writing the tests for it. And this will just through repetition and writing these different types of tests, you'll be writing all kinds of tests in no time. So with that, I hope you learned something. I hope you enjoyed this section on testing. I think that is close to the end of this course. I can't believe it. Let's say a few words and wrap this thing up. Wow. Congratulations for making it all the way through this course. I hope you had a lot of fun. I hope you learned something new in this course. I had a lot of fun putting this together. So I hope that shows through the videos that we made here today. Again, I want to double back and say thank you to free code camp for having me. Thank you to all of you for watching this. I have the GitHub repository here. This is going to be a kind of ever living document. This is a way for us to stay in touch. So I'll keep updating this as the needs come in, as issues come in. If you have issues with some of this code or questions, I'll open up discussions on this GitHub repo. I also have a list of resources. I'm going to put some more resources in here. I have things like books and other courses you may want to take. But for now, the resources in there are me. So I have a website, a YouTube channel. Again, if you want to keep diving into some of the spring stuff, a Twitter account. Also on the spring side, Spring Academy, I just launched one of my first free courses, my free guides on there. Actually, there's going to be two on there now. So free guide on 3.2. Like a lot of the stuff that we talked about today when it comes to the JDBC client, the REST client, virtual threads, that will be included on Spring Academy. So that's a free resource. Go ahead and check that out. The Spring Developer channel, this is a really great YouTube channel with a whole bunch of spring content. Check out the spring IO website, the spring blog if you want to stay up to date with everything in the ecosystem. And Spring Office hours, that's the podcast that I am a host of. And part of that is keeping you up to date with everything that's going on in the ecosystem, as well as answering your questions. So if you have a question about something you went here through on this course, join us every Monday, 1pm Eastern may change in the future. Who knows? You can always check out spring office hours.io to find out more about that. But please come there with your questions. Tell me you went through this course. That'd be awesome to hear. And with that, those are my resources. I'll update that. Again, I'm honored to have been your teacher in this course. Very thankful to Free Code Camp for hosting me. Very thankful for to my employer Broadcom and the spring team for letting me do this. It was a lot of fun. And I can't wait for you to get your hands on this course. I know I'm saying that as you're probably watching this, but I'm saying this after recording this and ready to get this into the hands of you guys. This was a lot of fun. I appreciate it. And as always, friends, happy coding.
Info
Channel: freeCodeCamp.org
Views: 240,202
Rating: undefined out of 5
Keywords:
Id: 31KTdfRH6nY
Channel Id: undefined
Length: 210min 40sec (12640 seconds)
Published: Mon Mar 18 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.