The ULTIMATE Guide to Spring Boot: Spring Boot for Beginners
Estimated read time: 1:20
Learn to use AI like a Pro
Get the latest AI workflows to boost your productivity and business performance, delivered weekly by expert consultants. Enjoy step-by-step guides, weekly Q&A sessions, and full access to our AI workflow archive.
Summary
Join Devtiro as they guide you through the ultimate six-hour Spring Boot course. In this comprehensive course, you'll learn how to build a REST API from scratch using Spring Boot, even if you're a complete beginner. The course covers everything from the basics to packaging your application in a Docker container and deploying it to AWS. You'll use a real Postgres SQL database and have access to all relevant source code and exercises. This in-depth guide ensures you grasp the theory while actively applying your skills.
Highlights
Create a full REST API using Spring Boot and Postgres SQL. 💡
Package your Spring Boot application using Docker for seamless deployment. 📦
Integrate pagination into your API for better data management. 📊
Key Takeaways
Master Spring Boot by building a REST API from scratch. 🚀
Learn how to deploy your Spring Boot application to AWS using Docker. ☁️
Understand the importance of DTOs for separating presentation and persistence layers. 🔄
Overview
This video is perfect for beginners eager to dive into Spring Boot by constructing a REST API from the ground up. The tutorial is designed to be comprehensive, covering everything necessary to implement a full CRUD functionality.
You'll learn to package your Spring Boot application with Docker, making deployment to cloud services like AWS straightforward. This process ensures your app runs smoothly in various environments.
The course emphasizes the use of DTOs to maintain clear layers between your application’s presentation and data persistence, making your code cleaner and more manageable.
Chapters
00:00 - 00:30: Introduction to Devo's Spring Boot REST API Course In the introduction to Devo's Spring Boot REST API course, the instructor welcomes students to an extensive, over 6-hour course designed to teach them how to build a REST API using Spring Boot from scratch. The course is beginner-friendly, ensuring students understand all necessary theories. Throughout the course, students will construct a REST API that interfaces with a real PostgreSQL database, and learn how to package the application in a Docker container for deployment to AWS. Students are encouraged to support further course creation if they find value in this one.
00:30 - 01:00: Course Promotion and Module Introduction The chapter begins by encouraging viewers to like and subscribe to the course for more content. It provides information about accessing the course's description for a full list of covered topics and offers a link to download the source code for free, enabling viewers to follow along with the exercises in the modules. The chapter then transitions to the first module, emphasizing hands-on learning by building a Spring Boot application. It outlines the prerequisites, including having Java 17 or later and an IDE installed on the participant's machine.
01:00 - 02:00: Setting Up Spring Boot Development Environment In this chapter, the focus is on setting up the development environment for Spring Boot using IntelliJ IDE. The instructor discusses using the free community version of IntelliJ, available for download from the JetBrains website, and advises that purchasing the paid version is not necessary. The chapter introduces the starting point of using Spring Boot with the Spring Initializer, a website accessed at start.spring.io. The goal of the Spring Initializer is to facilitate the setup process for Spring Boot projects.
02:00 - 03:30: Introduction to Spring Initializer and Project Setup In this chapter, we learn how to configure and download a basic Spring Boot project using the Spring Initializer. The chapter guides us through each step, aiming to set up a quick start application. Various options are provided for project configuration, including Groovy, Gradle, Kotlin, and Maven. However, for the purposes of this course, Java is the exclusive programming language used, and tools like Groovy or Kotlin are not considered. Gradle is explained as a build and dependency management tool, suggesting its importance in the project setup.
03:30 - 05:00: Spring Boot Project Configuration and Metadata In this chapter, the process of configuring a Spring Boot project using Maven is discussed. The selection of either Java, Kotlin, or Groovy as the programming language is addressed, with the chapter focusing on using Java. The importance of choosing the right version of Spring Boot is highlighted, with a recommendation to use version 3.1.1, the general release version at the time of recording. Additionally, the option to use a snapshot version, which includes the latest development features and fixes, is mentioned, although it may not be entirely stable.
05:00 - 06:30: Building Hello World Spring Boot Application This chapter focuses on building a "Hello World" application using Spring Boot. It begins with selecting the latest stable release version, which is 3.1.1. The process involves filling in project metadata, such as the group ID, which is customizable (for example, 'comevo'), and the artifact ID, named 'quick start' for this particular tutorial. Additionally, a description is added to identify it as 'our first spring boot app,' although this is optional.
06:30 - 08:30: Introduction to Apache Maven The introduction to Apache Maven begins with a discussion on selecting package names, indicating 'com.de tio. QuickStart' as a suitable example. The chapter proceeds to explain the basics of packaging options within Maven, specifically contrasting JAR and WAR files. While the differences between these file types are not fully explored at this point, the focus is on selecting a JAR file as it simplifies running the Maven project. Users are advised to select Java 17, and the chapter hints at a forthcoming discussion on dependencies, setting the stage for more in-depth exploration.
08:30 - 10:30: Phases and Goals of Apache Maven The chapter 'Phases and Goals of Apache Maven' begins with the creation of a simple 'Hello World' REST API, highlighting the ease of setup with Apache Maven. It discusses the necessity of only one dependency, 'Spring Web', to get fully configured. The process involves generating the project skeleton, downloading it, and opening it in an IDE. The chapter then sets the stage for implementing a Quick Start application, providing a practical introduction to using Maven for project setup.
10:30 - 12:00: Using Apache Maven from the Command Line The chapter titled 'Using Apache Maven from the Command Line' delves into the structure and components of a basic Spring Boot application. The primary focus is on exploring the 'quick start application' class located under 'Source main Java', which is identified as a Spring Boot application due to the presence of the @SpringBootApplication annotation and a main method. Additionally, the chapter highlights the existence of a corresponding test class under 'Source test Java', where the application is verified using Spring Boot testing capabilities.
12:00 - 15:00: Apache Maven Directory Structure This chapter discusses the directory structure of an Apache Maven project. It begins by noting a single test in the existing setup that checks whether the application context loads, which is a basic test provided by the Spring Initializr. The chapter proceeds to describe the process of setting up a simple quick start application. This involves creating a class inside the standard Maven directory structure 'src/main/java', specifically within the designated group ID directory, such as 'com.de.tio.quickstar'. The class in question will be named 'HelloWorld'. This setup forms the basic foundation of a Maven application.
15:00 - 16:00: Apache Maven Workflow In this chapter, we delve into the workflow of using Apache Maven, specifically focusing on creating a controller with a REST controller annotation. The discussion covers setting up a single endpoint in the controller, which is designed to return the string 'hello world.' The process involves creating a method that returns a string, although the method name is not provided in the transcript. Further details on the REST controller annotation are promised for later sections.
16:00 - 18:00: Running Spring Boot Application Locally This chapter guides readers through running a Spring Boot application locally. It covers the basic setup, where the developer writes a simple 'Hello World' program. The implementation involves returning a simple string 'Hello World'. However, to specify that this is an endpoint, an additional annotation is required. Specifically, the action involves using a 'Get Mapping' annotation, and setting the path to 'hello', enabling the application's controller to understand where this endpoint is defined.
18:00 - 20:00: Understanding Spring Framework and Spring Boot This chapter provides an overview of the Spring Framework and Spring Boot through a practical example. It shows how to launch a simple 'Hello World' application using Spring Boot, highlighting a straightforward method to run the application via IntelliJ IDE. The transcript details the process of running the application on a local server, emphasizing how easy it is to start working with Spring Boot.
20:00 - 23:00: Layers in Spring Applications The chapter covers setting up and running a Spring application on a local server using Tomcat.
23:00 - 26:30: Dependency Injection and Spring Framework The chapter titled 'Dependency Injection and Spring Framework' discusses the implementation of a basic Spring Boot application. It illustrates a simple process of altering a display message in the controller from 'Hello World' to 'Hello Devo'. This change is demonstrated through a code modification, application restart, and page refresh to verify the update. The chapter emphasizes the ease of creating a Spring Boot application, signifying minimal effort required for basic setup and operation.
26:30 - 28:00: Creating and Using Beans in Spring Boot The chapter introduces the concept of beans in Spring Boot, focusing on creating and utilizing them. It provides a brief overview of a basic Spring Boot application code, particularly a 'Hello World' controller class. The controller class exemplifies how Spring Web dependency facilitates the building of REST APIs with minimal coding effort.
28:00 - 30:00: Spring Boot Auto Configuration and Starters This chapter introduces the concept of Spring Boot auto-configuration and starters. It provides an example of a simple endpoint and highlights the flexibility Spring Boot offers in terms of creating as many endpoints as required, ranging from returning simple strings to complex JSON objects. The chapter also briefly touches on the 'Spring web', noting that more details will be provided later in the course. It examines the 'quick start application class', identifying it as the entry point of the application due to the presence of the main method.
30:00 - 33:00: Spring Boot Configuration Files The chapter provides an introduction to Spring Boot configuration files, focusing on the Quickstar application as an example. It emphasizes the importance of the @SpringBootApplication annotation, which serves as a composite of several annotations. This annotation is crucial as it marks the entry point to running a Spring Boot application. The text suggests that further details about the annotation will be explored later. The chapter also mentions navigating through resources within the application.
33:00 - 35:00: Spring Boot Environment Variables The chapter discusses the use of environment variables in Spring Boot applications. It starts by mentioning the presence of empty directories, but focuses on the application.properties file, which is used for configuring the application. It also notes that application.yaml can be used if preferred. While the chapter touches on configuration, it implies that more detailed discussion on it will follow. The chapter also references a test directory containing a simple application test, which was briefly examined previously but not run.
35:00 - 37:00: Custom Configuration Properties in Spring Boot This chapter discusses custom configuration properties in Spring Boot, specifically focusing on how they impact Spring Boot test executions. The chapter begins by prompting the reader to consider the consequences of running a quick start application's tests, particularly those annotated with `@SpringBootTest`. It goes on to explain that executing such a test will start up a test version of the Spring Boot application, as evidenced by the logs showing an application startup. The chapter concludes by highlighting the importance of understanding the context of these test executions.
37:00 - 40:00: Introduction to Database in Spring Boot The chapter titled 'Introduction to Database in Spring Boot' introduces the concept of dependency injection, which is a core feature of Spring Boot. It ensures that applications can start up correctly, which is crucial for both production and other environments. The discussion briefly mentions the testing framework, indicating that developers can create multiple tests to verify the application. Additionally, it highlights an option to organize tests in different classes within the directory when a running application isn't necessary. The chapter ends with a mention of a pom file.
40:00 - 45:20: Connecting to H2 Database in Spring Boot The chapter begins by discussing the use of a specific file utilized by Maven, which is influential in Spring Boot projects. The significance of Maven in managing dependencies and building projects is noted. The chapter highlights two vital Maven dependencies: the spring boot starter web and spring boot start test. These dependencies are integral for developing and testing Spring Boot applications.
Additionally, the transcript or lecture mentions how IntelliJ IDE integrates efficiently with Maven, performing numerous tasks seamlessly in the background, thus enhancing the development experience. The integration is so tight that many of the operations might not require explicit developer intervention as IntelliJ automates several processes, as hinted by the available options in the IDE.
45:20 - 51:20: Connecting to PostgreSQL Database in Spring Boot The chapter introduces Apache Maven as a crucial tool for anyone learning Spring Boot. It emphasizes the importance of understanding Maven, likening it to an essential preliminary step, much like tying one's shoes before running. Consequently, the chapter focuses on covering the fundamental aspects of Apache Maven to assist in the Spring Boot learning journey.
51:20 - 56:00: Database Schema and Data Initialization in Spring Boot This chapter introduces Apache Maven as a tool that aids programmers in managing their projects by handling dependencies. It explains how Maven simplifies the process of fetching and bundling dependencies, including managing transitive dependencies.
56:00 - 59:00: Using JDBC Template in Spring Boot The chapter discusses using JDBC Template in Spring Boot, focusing initially on managing dependencies in Maven. It highlights Maven's ability to handle second and third-order dependencies, build and test projects, and package applications for sharing. The chapter ensures that readers understand Maven's role in simplifying dependency management and deployment processes, using examples from command-line executions within a Spring Boot project.
59:00 - 64:00: Introduction to Data Access Objects (DAOs) The chapter provides an introduction to Data Access Objects (DAOs) within the context of a Spring Boot application. It starts with a demonstration of running the 'mvnw' script located at the root of a Spring Boot project. The script is used with the commands 'clean' and 'compile', and while it shows 'build success', the chapter acknowledges that the meanings of 'clean' and 'compile' might not be clear initially. Therefore, the chapter aims to explain these commands as part of the larger discussion on Maven, which is implicitly understood to be a critical tool for managing dependencies and building Java applications.
64:00 - 71:00: Implementing CRUD with DAOs This chapter provides guidance on implementing Create, Read, Update, and Delete (CRUD) operations using Data Access Objects (DAOs). The instructor advises using the Maven wrapper to manage dependencies without needing to install Maven directly. The chapter begins with a choice between using the command line or an Integrated Development Environment (IDE), with the recommendation to start with the command line for a more thorough understanding. Later, whether to continue with the command line or switch to an IDE is left to the learner's preference.
71:00 - 75:00: Testing DAOs with Integration Tests The chapter addresses how Maven's three phases (clean, default, and site) function as part of a build lifecycle. Each phase serves a unique purpose: the clean phase is used to remove unwanted artifacts or start afresh. Phases determine the order in which goals (specific tasks to be achieved during the build process) are executed. Understanding this lifecycle is crucial for efficiently utilizing Maven in integration tests for DAOs.
75:00 - 84:00: Introduction to JPA and Spring Data JPA The chapter 'Introduction to JPA and Spring Data JPA' provides an overview of the phases and processes involved in using JPA and Spring Data JPA. It introduces the environment setup, focusing on temporary directories and files essential for default configurations, building, and testing. The chapter emphasizes the significance of the 'clean' phase, explaining its role in clearing out directories and files as part of the preparation for the build and test processes. Additionally, it briefly mentions the 'site' phase where documentation such as reports and JavaDocs are generated, promising further details in subsequent discussion.
84:00 - 95:00: Configuring Entities and Repositories in Spring Data JPA This chapter discusses the concept and process of configuring entities and repositories in Spring Data JPA. It starts by introducing the clean phase in Maven, which includes specific goals such as the pre-clean, clean, and post-clean. The chapter explains these goals, focusing on their roles and importance in the build process, especially when developing Maven plugins. The clean goal is highlighted as essential for cleaning out directories and files, ensuring a prepared environment for new builds. Practical implementation is demonstrated in the quick start application, showcasing the importance of the Target directory in the project structure.
95:00 - 98:00: Creating Custom Queries in Spring Data JPA The chapter discusses the role of the target directory in Maven projects. This directory is used by Maven to store processed items, which include built classes, reports, and built artifacts like jar or War files once the project is built. The example given shows a project that has been built, illustrating the contents of the target directory such as a jar file for a specific application and other assorted Maven-related files.
98:00 - 108:00: Understanding JSON and Jackson The chapter introduces cleaning up the target directory using the Maven wrapper and highlights the excitement of covering the Maven default phase. It explains that while the listing of goals might not be exhaustive, it covers the major ones frequently used.
108:00 - 112:00: Building a REST API with Spring Boot The chapter discusses building a REST API using Spring Boot, emphasizing the compilation and testing process in Maven. It highlights different Maven goals such as compile, test, package, and verify. It's important to understand the order of the Maven phases as compile happens before the test, and both of these precede the verification and packaging stages. This sequential execution ensures that code is compiled into bytecode, unit tests are run, and integration tests or checks are verified before creating a jar or war file. The chapter provides key insights into how the Maven life cycle supports efficient API development with Spring Boot.
112:00 - 121:00: Implementing Create Endpoints in REST API In this chapter, the focus is on implementing 'Create' endpoints in a REST API, highlighting the sequence and dependencies in the build lifecycle using Maven. The chapter explains the order in which Maven commands should be executed to achieve specific tasks, such as compiling, testing, and packaging. It is demonstrated through a practical example where the project is cleaned and then compiled, emphasizing the integrated workflow within the development process. The explanation serves to guide the reader through effectively setting up and executing the correct lifecycle phases in a REST API project.
121:00 - 126:00: Implementing Read Endpoints in REST API The chapter titled 'Implementing Read Endpoints in REST API' covers the process of building and testing a REST API using Maven. It begins with ensuring that the project compiles successfully, as indicated by the 'build success' message. The compiled classes are located in the Target directory, illustrating successful compilation. The chapter further illustrates the concept of cleaning the build using 'Maven clean,' which removes the 'Target' directory and its contents, a common practice to ensure a clean state before running tests or deploying. Lastly, it touches upon executing tests in the Maven environment with the 'Maven test' command.
126:00 - 132:00: Implementing Update Endpoints in REST API In this chapter, the goal of testing is discussed in the context of the compile goal, which is part of the default phase lifecycle in a typical build process. The emphasis is on the order in which the test occurs, following the compilation phase, to ensure everything is functioning correctly. The transcript includes an example where a test is run successfully immediately after the compile step, demonstrating the correct execution of the lifecycle with the output showing 'build success' and confirmation that one test has been executed successfully. It highlights the correct sequence and the success of the compilation and testing process.
132:00 - 138:00: Implementing Delete Endpoints in REST API The chapter discusses the process of implementing delete endpoints in a REST API focusing on ensuring that classes are compiled properly. It emphasizes running the compile goal before the test goal within the Maven build lifecycle. The discussion includes an observation that no jar file exists in the target directory, prompting a need to clean and rebuild using Maven. The procedure involves using the Maven clean tool to remove the target directory and its files, followed by running the Maven wrapper to rebuild the project.
138:00 - 144:00: Working with Nested Objects and Pagination The chapter discusses various aspects of packaging in software development, particularly focusing on Maven, a build automation tool. It highlights creating package jar files and verifying them using Maven commands such as 'Maven clean' and 'Maven verify'.
144:00 - 155:00: Deploying Spring Boot Application to AWS The chapter discusses how to deploy a Spring Boot application to AWS, focusing on the usage of Maven for building and verifying the application. It touches upon the importance of integration tests and mentions the necessity of utilizing a Maven plugin to configure these tests. The instructor also highlights the use of the Maven verify command, explaining that it generally executes all the necessary build lifecycle processes, which will be demonstrated periodically throughout the course.
155:00 - 157:00: Course Conclusion and Additional Resources In the final chapter titled 'Course Conclusion and Additional Resources,' the course wraps up by demonstrating how to utilize Apache Maven within a Spring Boot project. The discussion emphasizes the importance of following the Maven directory structure, which is a requirement of Apache Maven rather than being specific to Spring Boot. The chapter directs learners to the Apache Maven website for guidance on the appropriate directory structure necessary for successful project integration. This ensures a seamless application of Maven's capabilities in building and managing Spring Boot projects. The chapter serves as a practical conclusion, providing additional resources for learners to continue exploring Maven's functionalities.
The ULTIMATE Guide to Spring Boot: Spring Boot for Beginners Transcription
00:00 - 00:30 welcome to Devo's ultimate spring boot rest API course in this over 6-hour long course I'm going to teach you how to build a rest API in Spring boot completely from scratch and don't worry if you're a complete beginner because I'm going to teach you all the theory you need to know and be with you every single step of the way in this course we'll build a rest API to use a real postgress SQL database once we're done we'll package up our application in a Docker container and deploy it to the cloud to AWS if you feel like you've taken some value away from the course and you want to help us make more
00:30 - 01:00 courses just like this then be sure to like And subscribe so before we start be sure to check out the description below for the full list of everything covered in the course and there's also the link to the source code that you can download for free and follow along with all the exercises in the modules so let's get into it with our first module one of the best ways of learning is by doing so in this video we're going to build your first spring boot application for this you're going to need a few things you're going to need Java 17 or later installed on your machine and you are going to need an IDE
01:00 - 01:30 now we're going to be using intellig IDE the community version the free version that you can download from the jetbrains website of course there is a paid for version as well but you don't need to purchase an IDE for this course you can use the free version this is where our spring boot Journey starts and it's at the spring initializer now this is a website that you can get to by hitting start. spring.io in your browser and you're greeted with a page that looks a little bit like this now the goal of the spring initializer is to allow you to
01:30 - 02:00 configure and then download a skeleton spring boot project and we're going to go through it together now to download our first spring boot project that we're going to run our quick start application so let's start at the top left here now we've got a project heading and we've got some options like gral groovy gradal cotlin and Maven now gradal is a build and dependency management tool groovy and cotlin are different programming languages we're going to be using Java exclusively in this course so we're not interested in selecting groovy or cotlin
02:00 - 02:30 we're going to use Maven now under language we're going to be using Java but of course you can select cotlin or groovy if you would like now we're going to go to the spring boot heading here and we're going to select 3.1.1 which at the time of recording is the general release version of spring boot of course you can select an earlier General release version of spring boot if you like or you do have the option to use a snapshot version now the snapshot version is like the latest Dev build it may have the latest features the latest fixes on it but it may not be the most
02:30 - 03:00 stable so we're going to stick to the latest General release version here of 3.1.1 now we get to give our projects metadata so this just allows us to identify our particular project so for the group I use the group comevo you may use a different one and for our artifact we're going to call this one quick start because it's our quick start application for our description not strictly needed but we're going to say our first spring boot app
03:00 - 03:30 and for the package name com.de tio. QuickStart seems absolutely fine by me now we get to the packaging and we have jar selected already but we could select a war if we would like now the differences between jar and a war isn't for now we'll cover that later but we're going to select jar for the moment because if we get a jar file then we can run our project nice and simple that's exactly what we want so we jar selected we now select our Java version we're going to select Java 17 now in terms of the dependencies here we're going to do
03:30 - 04:00 a very simple hello world rest API for our first project so we just need a single dependency and that is spring web and just like that we are fully configured so if we click on generate we get to download our skeleton project and then we can open that up in our IDE so let's download this and head over to the IDE so here we are with the project open up in our IDE so let's take a quick look through and let's Implement our first Quick Start applic
04:00 - 04:30 our hello world Spring boot application so I'm going to expand this and let's T take a little look around so we've got Source main Java and we have a single class in here which is quick start application and we've got Source test Java and we have a quick start application tests so taking a look at quick start application we can see that we've got bits of information in here at Spring boot application annotation this must be a spring boot application and we can see we've got a main method as well now if we take a look at the tests we can see at Spring boot test and we can
04:30 - 05:00 see a single test in here which is testing that the context loads it's not doing a lot else now more on what that means a little bit later but the spring initializer is basically given us the Bare Bones of an application and a test here so what we're going to do to implement our quick start application we're going to create a class in Source main Java and then inside of our group comde Tio Quickstar or whatever group that you're using and we're going to call it the hello world
05:00 - 05:30 controller there we go now a controller needs an annotation and we're going to give this one rest controller annotation more on what that means a little later on now we're going to create a single endpoint for this controller and that's going to return the string hello world now we're going to do that via a method returning a string and we're going to call this one
05:30 - 06:00 hello world like this and as you can imagine the implementation is simply returning a string of hello world there we go but that's not enough to tell spring that this is an endpoint on our controller we need to add another annotation here so we're going to do git mapping and inside of git mapping we're going to type in path and we're going to say say that the path is hello because
06:00 - 06:30 when we hit for/ hello it's going to give us hello world in our browser so that is the Bare Bones of our hello world application so what we're going to do to run this and there are several ways of running this but we're going to the simple way of going over to the quick start application here and because intell is fantastic we can click on this little play button and then click on run and it's going to run our application for us there we go and we can see that that we are running on port 8080 here
06:30 - 07:00 we'll cover what Tom cat is and all of that good stuff later on we know we're running on port 8080 let's hit this in our browser so here we are in our browser what we have to do now is we'll go to http Local Host 8080 and our endpoint was SL hello and we're expecting to see the string hello world and just like that we have hello world so if we were Zoom a little bit so have hello world returned on this
07:00 - 07:30 endpoint to show you that this is doing what it should do let's change the string here and we're going to go to our controller change from Hello World to maybe be hello Devo restarting our application very good refresh this page and we have hello Devo and just like that you've implemented your first spring boo application so as you can see we didn't have to do a lot to build our first spring boot application but we did skim
07:30 - 08:00 over a lot of details so let's just cover a few things now just to set the scene and of course we're going to cover these in more detail as the course progresses so let's go over to our code here so here we are back at our code and we can see we've got a few things on the go here here's our hello world controller class that we implemented with our hello world endpoint now this class is all to do with spring web so the spring web dependency that we brought in earlier has allowed us to do this essentially allowed us to build a rest API with next to no code and it has
08:00 - 08:30 a single endpoint it's very simple at the moment but this can have as many endpoints as you like and be as complicated as you like as well returning anything from a string to complex objects in Json format or other formats if you so choose so that's all to do with spring web and more on Spring web later in the course now for other things in the class here we did quickly cover this quick start application class now this is the entry point to our application we can tell that because it has our main method here which simply
08:30 - 09:00 runs a spring application in this case the Quickstar application here and we also have this at Spring boot application annotation on top now this annotation does so so much and we'll break it down later on this is actually an alias for several different annotations but for the moment you can think of it as just identifying a spring boot application an entry point to our spring boot application that we can then run so that's our quick start application here now if we go into resource ources we can see that we've
09:00 - 09:30 got some empty directories here and more on those later but we also have this application. properties file and if we were to configure our application in any way we would put our configuration in this file or file very similar to it for example we could have application. yaml if we prefer to use the yaml format and spring boot would be absolutely fine on that but again more on configuration a little bit later now if we go into our test directory we've got our quick application test that we took a look at earlier of course we didn't look to run
09:30 - 10:00 this or anything now if we were to run our quick start application tests bearing in mind it has the at Spring boot test annotation on top what do you think will happen let's run this now and see you've seen a spring application start up if you look at the logs for this test you might see something fairly familiar this is actually starting up a test version of our spring boot application and the context loads is a
10:00 - 10:30 dependency injection concept that spring uses more on dependency injection a little bit later on but it's basically making sure that the app starts up which of course is exactly what you want it to do in production or any environment for that matter so that's all that test does of course you can add as many tests as you like here to test against a running spring boot application or if you don't need a running spring boot application and there are some benefits to not having one in your tests you can add those in different classes in this directory but then we've got our pom
10:30 - 11:00 file down here which is used by Maven now we're going to cover Maven in detail in a little bit but you can see of course we've got our spring boot starter web dependency here we'll cover what a spring boot starter is as well and we've got the spring boot start test dependency in here as well which allows us to have some testing functionality for a spring boot application now you may have not noticed it but intellig integrates super super tightly with Maven and it's actually doing a lot of work behind the scenes if you take a look at this little tab here you can see
11:00 - 11:30 some more information on Maven so for the rest of our spring boot Journey Apache Maven is going to be our best friend so we're going to need to know a little bit more about it in order to fully utilize it to learn spring boom so let's cover Apache Maven so you're here to learn spring boot right but just like how you can't become an Olympic sprinter without first learning how to tie your shoes you're going to need to know your build tool so in this module we're going to cover the need to know of Apache Maven and let's start with the bigie
11:30 - 12:00 which is what is Apache Maven so one of the best descriptions I've come across is this Apache Maven helps programmers manage their projects and all the things they need to build their programs and Maven knows how to find all of these dependencies and go in Fetch them and once it's done that they can be bundled right into the project now this might sound really simple when you consider the dependencies your project needs but then you have to consider the dependencies of the dependencies that your project needs the first order
12:00 - 12:30 second order third order dependencies and Maven does a fantastic job of managing these transitive dependencies all for you but it doesn't just stop our dependency management Maven builds and tests our projects as well and once we know our project is working exactly how we want it to Maven allows us to build it package it up and then share it as a dependency to be used by others but only if we want them to so to run Maven from the command line in a spring boot project it's actually very straightforward so here's an example I'm
12:30 - 13:00 going to run mvnw which is a script which exists in the rout of our spring boot application project here and I'm going to type clean and I'm going to type compile you can see here we have a build success but it might not necessarily be clear what clean and compile might mean so let's cover that now as should be no surprised by now at Maven is a command
13:00 - 13:30 line tool now you can choose to use it exclusively via your IDE if you want to do it that way but it feels like a bit of a cop out to do that so I'm going to show you how to use it via the command line and then it's up to you whether or not you do it via the command line or via your IDE for the rest of this we're going to be using the maven wrapper so mvnw and the reason for that is so there's no obligation for you to install Maven on your machine of course if you want to go ahead and install it you go for it but we're going to be using the wrapper for the remainder of this so it's the highest level concept we're
13:30 - 14:00 going to cover phases now Maven has three phases that it uses it has the clean phase the default phase and the sight phase now you can think of a phase as a life cycle a phase can contain one or more goals so a goal is something specific that you're looking to achieve whereas the life cycle is the order of those goals or the the order of the things that you're looking to achieve now of the three phases they each have their own purpose now clean that's used to remove
14:00 - 14:30 temporary directories and files at least with the goals that it contains default this is where the most useful stuff liveed this is where you do your building and your testing and all that good stuff we'll cover it in more detail in a bit and then the site phase and that's where all of the documentation is generated so reports and uh Java doc all that good stuff is done in sight so let's cover the clean phase because it's something a little bit special so clean we know is there to clear out directories and files and there is one
14:30 - 15:00 goal in the clean phase that does all the work and that is the clean goal there is a pre- clean and a post clean goal inside of the clean phas but there just there is hooks because sometimes you'll build a plugin for Maven and you want to hook into the time before the clean or the time after the clean so clean cleans out directories and files let's see how that's done so here we are back at our quick start application and we can see we have a Target directory
15:00 - 15:30 here now the target directory is the directory that Maven uses where it puts all of the stuff that it's processed that might be its built classes it might be its reports it might be the built artifacts like the jar or War file so this project is actually been built so if we take a look inside of the target directory here we have all sorts of files we have a jar file here which is our quick start application we've got some things in Maven status and Maven Arch some classes in here if we were to expand this so you can see there's a lot
15:30 - 16:00 of stuff in this target directory and it might be the case we want to clear it out we want to get rid of it and we can do that very simply we're simply going to run the maven wrapper here and we're going to type clean that's a build success you can see our Target directory has been cleaned it's disappeared it's no longer there now for the exciting bit let's cover the default phase so this list of goals is not exhaustive by any stretch of the imagination but these are some of the biggies that you'll see used throughout
16:00 - 16:30 the course so the compile goal here will compile your Java code into bite code we have the test goal here which runs our unit tests we have the package goal here which creates a jar or a war file and we have the verify goal which runs checks and integration tests now something important that's worth pointing out here is the order okay so the maven default phase is a life cycle right and it happens in this order compile will happen before test test will happen
16:30 - 17:00 before package and package will happen before verify so if you wanted to run all of the things right up to verify you would run verify and of course it would compile test and package your code if you just wanted to run everything up to test you would run Maven test and it would run compile and then it would run your tests so to kind of give an example of how that works let's flip back over to our code so here we are we've just cleaned the project we're going to now compile it so we're going to run the
17:00 - 17:30 maven rapper here and I'm going to type compile you can see it's a build success it's recompiled our classes here and if we go to our Target directory which is now back we can see we've got our compiled classes looking very good indeed now if we were to run Maven clean once more of course getting rid of that Target directory and all of those files in there let's run Maven test remembering that
17:30 - 18:00 the test goal is after the compile goal in the default phase life cycle there's the test running build success one test has run looking very good now if we were to go up here a little bit we can see that the compiler has run default compile and that proves
18:00 - 18:30 that our classes have been compiled that compile goal has run before the test goal so here's something I want to point out before we move on if you take a look at the Target directory here there is no jar file okay we haven't got a jar file in this target directory so we go down here and we're going to run Maven clean it's going to remove our Target directory in all those files that disappears and now we're going to run the maven wrapper and now we're going to run Maven
18:30 - 19:00 package there's the compiler there's the tests okay and we have if we look in the Target directory now the jar file so that's our package jar file there's our artifact so everything's looking good so far now we'll just cap things off by doing MAV and clean and we'll now run Maven verify now we
19:00 - 19:30 don't have any integration tests configured to do that we would need to use a maven plugin more on that in a little bit but by using Maven verify because at the end of the live cycle It generally runs everything so that's what you'll see me run periodically throughout this course there we go and we just check in the
19:30 - 20:00 Target directory we can see there is our jar file once more that is how you interact with Apache Maven via the command line but how do you actually use it in an actual spring boot project let's look at that now so to use Maven is to use the maven directory structure so this isn't so much a spring boot thing as it is an Apache Maven thing so if we go to the Apache Maven website here we can see an example of the directory structure that Maven requires Source main Java Source
20:00 - 20:30 main resources so on so forth and you can see the description as to what these different directories do so let's see how that works in a spring boot application so let's go back to our quick start so here we are let's expand our directory structure here okay so best place to start is this Source main Java that then contains our Java code so we can see within Source main Java we have that com. devevo doqui start so our group uh the package that
20:30 - 21:00 we're using and inside of there we have the hello world controller and then the quick start application class as well now we also have here our source main resources and that's where we find this application. properties our configuration file now if we did have any static files that we wanted to use any other files that we wanted to load in we would put those in Source main resources and that pretty much covers it for our source main directory so so if we minimize that we have our source test
21:00 - 21:30 directory so just like we have Source main Java we also have a source test Java so Source test Java contains the same group so we can see here the same package that we're using in our source main Java directory but this one contains tests so you'll usually see a reflection of the directory structure used in our production code so Source main Java inside of our source test Java directory so you'll usually have a class
21:30 - 22:00 in Source main Java and then the equivalent test class for it in Source test Java in exactly the same package what's also interesting is you don't have it in this project but you can also have a source test Resources directory so if we create one here you can see it has a different icon so it's already been picked up by intellig and inside of source test resources you can have static files and configuration files that are only used
22:00 - 22:30 in your tests not in your production code so spring boot actually allows you to override configuration inside of your test by placing configuration files inside of source test resources we'll cover that in much more detail later on it's just worth knowing that you'll find those in Source test resources and also any static files that you're using for your test as well and of course we've come across it before but our built project and any files that Pro process by Maven are placed into this target
22:30 - 23:00 directory so we can see here our quick start jar and of course you have our compiled classes as well so it's worth bearing in mind this directory structure is enforced by Maven it's required when you use Maven but you can build spring boot applications with it and actually by convention spring boot allows you to do some really nice stuff by using this directory structure such as overriding the configuration files in your tests by placing something in Source test resources as opposed to Source main
23:00 - 23:30 resources but again much more on configuration later on and there we go those are the main ones that you need to know for a spring boot project there are some other directories that are used in just general Maven projects of different types but we're not going to need to know about them today so how would you use Maven typically in a project what would be your workflow well let's cover that now so what would a typical workflow look like when using Apache Maven there's a few things to point out here I'm going to show you my workflow this works for me it might not necessarily work for you but it might be
23:30 - 24:00 a good place to start I like to use Maven from the command line rather than using it via the ID this might be out of habit but I find it a lot more flexible I also do not follow test driven development as a general rule if you do your workflow will be different it's not to say that I have a problem with test driven development it's just typically not the way that I do things so this is what my workflow looks like in terms of the project I'll go ahead and I'll identify what needs doing look at the requirements and then I'll start writing
24:00 - 24:30 code now as I'm writing I may want to get some super fast feedback on what I'm writing is there something a little bit weird here how I done a compilation error now the IDE usually does a really good job of highlighting these for you that occasionally I will write Maven compile into my terminal and get some fast feedback from the compiler there so once I've written the feature then I'll get to testing and typically I will run Maven clean and test quite a bit just to
24:30 - 25:00 get some fast feedback when I'm writing tests again this can be done via the IDE but I like to do this via the command line now you might be asking why do I do clean well to be honest compiling a project takes next to no time at all and I don't really want any leftover files from a previous compile to influence the test as they are running again the likelihood of them doing so is usually fairly slim but I just like to uh use that anyway you see here we got a bill success and one test has
25:00 - 25:30 run so once I've written the feature and I've written the test I like to do one final test of the feature before I'll then commit that and push that up and what I like to do is I like to build the artifact in this case a jar file and then run the jar file the same way that it might be run in production now of course you can run your application via the IDE and you can even run your application via the spring boot Maven plugin but I like to run it the way as if it was going to you run in production and what I'll do to get hold of that is
25:30 - 26:00 I usually go Maven clean for the same reasons as earlier and then I'll type package or verify depending on what I've got configured in my Maven project here there we go so that's everything built now if we go into the target directory we'll see that we have that jar file in there and perhaps the simplest way of running that is Java Das jar passing in the path to the jav file
26:00 - 26:30 and this should run our application there we go it's now running on Port 880 and we should be able to now hit this in our browser there we go Application running and right before I'm about to commit the code and push it on up I'll run one last Maven clean and verify to make sure that everything is working nicely
26:30 - 27:00 looking good I'll typically then commit this and push it on up so this is the workflow that I'll typically use on a maven and in this case spring boot project it's not completely perfect but it's what works for me and of course I'll tweak it depending on the project that I'm currently working on of course take it under advisement if this interests you and you can benefit from it go for it but if not feel free to use your own workflow so we want to run a project locally we have loads of different options to do this we can run it via the IDE we can run it by building a jar file
27:00 - 27:30 and then running that jar file with Java djar or there is another option which is we can run our application our spring boot application via the command line via Maven via the spring boo Maven plugin and it's very simple on how to do that so we go down to our terminal here and we're going to use the maven wrapper and we're going to type spring hyphen boot colon and then run and this is going to run our
27:30 - 28:00 application looking good the application's up and running let's hit it in our browser so there we go we can see our application is up and running but how do we stop it so if we go back to our code we'll go into our terminal and we're going to hit the buttons control and c and that's going to cancel the running and if we go back to our browser again refresh you can see the application has stopped the fact you're taking this
28:00 - 28:30 course probably already means that you know spring boot is a framework for building Java applications and you may know that a framework is a chunk of code that sits on top of the language's core library to solve common problems and those common problems can be things like connecting to a database or exposing a rest API so different parts of a system can communicate now if we really get down into the nitty-gritty one such framework for doing this is the spring framework
28:30 - 29:00 which is different from Spring boot so spring framework is a thing that does a lot of the hard work for you so connecting to databases and exposing rest apis all of that is done or can be done directly with spring framework and spring boot is a layer that's actually on top of spring framework spring boot is built on top of spring framework and you might find that confusing but of course the purpose of a layer is to provide additional functionality to solve a specific problem and the thing about spring framework
29:00 - 29:30 used by itself is that it's highly configurable which is great because you can configure just about anything in Spring framework to be exactly how you want it to be but the downside to this of course is that it takes a lot of effort and that's your effort as a developer every single time you start a new project so of course you can use spring framework just by itself configure everything yourself and deploy an application to production but if you choose to use spring boot it's going to do a lot of that configuration for you by convention and those conventions are
29:30 - 30:00 very well documented which of course is going to really speed along your application development but by choosing to use spring boot you do still have access to all of the flexibility of spring framework but now it's just easier to use and you might be asking well what makes it easier to use and that is a great question and we will answer it but before we can fully understand it we need to go over a few basic concepts of spring framework first so we've talked about how spring boo is a layer that sits on top of spring framework and you know what if
30:00 - 30:30 you zoom into your application you'll find that layers exist there as well so each of these layers has a specific purpose and is there to solve a specific problem and if you think about your app in terms of these layers then it's going to be easier to reason about to write and maintain and almost every single spring framework and spring boot application can be thought about in terms of these layers so let's start at the bottom with the persistence layer so the persistence layer is there to handle into interactions with our database and we'll often think of entities at this
30:30 - 31:00 level which are Java objects which represent our domain and often map to tables in a database or if you're using a nosql technology the equivalent in those Technologies we'll typically use entities at this level to interact with a database using one of a few different patterns first we have the repository pattern and then we also have data access objects which are commonly called daos and the type of functionality that's exposed by our repositories and our daos would typically be described as
31:00 - 31:30 crud which is create read update and delete which are the basics of the basics of what you need to do but of course if you do need anything a little bit more elaborate you can build those in to your repositories and your daos as well so the goal of this layer really is to handle all of the different interactions with your persistence technology like your database and then you want to expose that via some really well-defined interfaces and hypothetically because of those interfaces you could change your
31:30 - 32:00 persistence technology completely replace it and the rest of the application just wouldn't have to worry about that because the interfaces wouldn't change so now for the service layer and the goal of this layer is to use all of the functionality exposed by the persistence layer and then use it to meet the requirements that our application is being built to handle and it would typically do this through a set of interfaces and they implementing classes which are typically referred to as Services the functionality in the service layer can be as complicated as it needs to be or it can simply just be
32:00 - 32:30 pass through calls to the persistence layer but that's still important because we don't want our presentation layer talking directly to our persistance layer calls must always go via the service layer which brings us nicely onto our presentation layer and the goal of this layer is to take all of the data that's as a result of using the services in the service layer and then expose those to the user and typically that can be done via a rest API in which case You' be using the concept of controllers
32:30 - 33:00 as the implementation of that or it could be a graphql API a websockets API or any different type of API spring framework the ecosystem there's a lot of tools in there to build pretty much any type of API that's needed the wonderful thing about the presentation layer is that if we chose to present our data in a different way let's say we are moving from a rest API to a graphql API we wouldn't need to make any changes to the service layer we would only make our changes in the presentation a layer so we would take exactly the same data but
33:00 - 33:30 we would just expose it in a slightly different way this concept of layers is key and another key concept is modularity so let's now talk about the different dependencies used inside of a spring framework and spring boot application so we know that spring framework solves common problems for us and we know that spring boot makes spring framework easier to use we also know that our application code is broken up into different layers namely the persistence layer the service layer and the presentation layer and we know that
33:30 - 34:00 each of these different layers is there to solve a specific problem so now let's talk about why we don't have to solve every single problem ourself and how we can leverage Spring's massive ecosystem of dependencies or prean Solutions and how spring boot makes them so much easier to use so let's say you wanted to interact with a database by using Java objects and you choose to use spring framework directly well first of all you would need to include all of the relevant dependencies into your pum file you would then need to create several
34:00 - 34:30 beans manually including an entity manager to handle your entities a transaction manager to handle your transactions and a handful of other different beans as well and that's before you even write a line of code to do the actual logic of your application but if you're using spring boot then you would simply include the dependencies put some configuration inside of a properties file which says how to connect to the database and it would create all of the relevant beans for you so you can get straight on to writing your actual logic of your application and the way that spring boot creates these beans is by using sensible
34:30 - 35:00 defaults and this isn't just limited to the persistence layer the same could be said for the presentation layer as well or any other layer in fact if you wanted to write a rest API it's usually enough just to include the spring web dependencies and Away you go now with the general approach covered let's talk about how spring actually achieves this let's talk about dependency injection to understand dependency injection we need to get a little abstract for a moment so let's say we were going to write a class and what
35:00 - 35:30 that class is being written to do and where it lives really isn't important but let's represent that class with this green box now let's say our class depends on three other classes in order to achieve its goal and we're going to represent those with these blue yellow and red boxes now one way of handling these dependencies is that we can create them inside of our green class by using the Java new keyword perhaps in a Constructor and that's fine until we need to change these dependencies swap
35:30 - 36:00 them out perhaps and what would we need to do well we'd actually need to change the code inside of the green class and we don't want to do that just to swap out and change the dependency luckily there is a different way of handling this now let's say instead of creating those classes inside of our green class we simply just declare the different interfaces that those classes meet now the wonderful thing here is that well something would need to provide the concrete classes that meets these
36:00 - 36:30 implementations and well we can have something sat around the outside to do that such as a framework possibly spring framework and it would be up to the framework to create the concrete classes and then inject them where they're actually needed so in this way of doing things how would we swap out our dependencies how would we change that concrete class to be a different concrete class that still meets that interface well it's really really simp simple so let's put some labels on these for the moment now let's say we wanted
36:30 - 37:00 to swap out that Alpha class that blue box with a different class which still meets the interface but does it in a slightly different way well inside of our framework that gray box around the outside we would simply get rid of that Alpha class we would create a new class that still meets that interface and our framework would inject it where that interface is declared and that again could be that green class or it could be as many classes is as needed inside of your application so because the
37:00 - 37:30 ownership of the dependencies is moved from this green class to something operating a much higher level this is termed an inversion of control now there are many different patterns which sit under the umbrella of inversion of control and we needed something more specific to refer to this particular pattern and that's where Martin Fowler came up with the term dependency injection at its core spring framework is a dependency injection framework that's how we make use of all of those dependenc encies in the spring ecosystem that's how we use all of those prean
37:30 - 38:00 Solutions now if that doesn't make too much sense don't worry because we're going to get on to a worked example now starting with some beans so we know that coding to interfaces instead of concrete classes is the way to do things and we also know that we should leave up to the framework to supply the concrete classes wherever we declare our interfaces via dependency injection now we're going to use the term beans to refer to those concrete classes now on because that is the term that spring framework uses and by
38:00 - 38:30 extension spring boot now I'm going to show you how to use Beans by showing you an example spring boot application now all this spring boot application does is print out three different colors but it will show you how to use beans so here we are in intell let me show you the colors application now if we take a look at the entry point here so our spring boot application allocated class we can see that it implements command line Runner which of course makes this a
38:30 - 39:00 spring boot command line application now by implementing command line Runner I can now override this run method here now all this run method does is it creates an instance of color printer we can see it's using the Java new keyword there and it's going to print out the colors given back by color printer. print method and we can see the log. info is just simply going to print that out to the uh command line there so let's take a look at the color printer interface to begin with there's our
39:00 - 39:30 single method very nice let's look at the implementation for the color printer which we've got here our color printer imput now we can see that this has three dependencies a red printer a blue printer and a green printer and each of these classes also has a single method print which if we take a look at Red printer you can see is right there so we can see that we're doing the thing that we said we shouldn't do inside of the color printer imple
39:30 - 40:00 Constructor here we are creating a new red printer which in this Cas is the English red printer English being the language that it's going to print red out in and then we've got one for blue we've got one for green as well and then using these dependencies we simply implement the print method here to print out red blue and green one after another and for completeness let me show you one of the implementations let's take a look at the English red printer you can see it simply Returns the string red in its
40:00 - 40:30 implementation and no surprise the blue printer just Returns the string blue as well so this will absolutely work let me show you so we're going to go to the colors application class once more and I'm just going to click the play button and then run there we go and we can see that red blue and green have been printed out to the command line there but what if we wanted to swap out the implementations of our red blue and green printers
40:30 - 41:00 perhaps we wanted to print them out in Spanish for example how would we do that in this case well we would have to actually change the implementations of our classes so if we go to the color printer implementation here so we would actually need to make changes to this class even though we just wanted to swap out the dependencies that it uses so the obvious way to fix this is to change this to use beans so let's do that right now so first up we're going to identify the dependencies this class needs so if
41:00 - 41:30 we start at the colors application here we can see that actually color printer and its implementation color printer impul you could see that as a bean that we need to create now inside of color printer imple we can see that the blue red and green printers the English ones here these are all great example with dependencies these should all be beans so how are we going to create those beans one such way of doing it is via a conf configuration file now if we go back to our rout of our project here
41:30 - 42:00 create a new package and I'm just going to call this config now inside of config I'm going to create a new class here and I'm going to call this class I don't know let's call it um printer config perfect now this is going to be what's called a configuration class and we would label a configuration class with the configuration annotation like that and that tells spring to look in this class for bean declarations now if
42:00 - 42:30 we just close those other tabs where should we start I think it's probably best to start with the different printers here so the English blue printer that should be a bean so in our printer config we're going to create a method which is going to be our Bean declaration and it's going to be annotated with the bean annotation and it's going to be public and it's going to return the type blue printer we simply just call it blue
42:30 - 43:00 printer now the implementation of this method is going to return the implementation of blue printer so we're going to return a new instance of English blue printer just like that and we'll do the same for the other printers as well there we go so we now have these three
43:00 - 43:30 beans available in our spring application context these can now be injected where they're needed so we need to change the place that they're actually used to look for them in the spring context rather than create them so let's go to the color printer imple here and I am going to remove these news and inside of our Constructor I'm going to declare them so we'll start with the red printer and then we'll have the blue
43:30 - 44:00 printer and then we'll have our green printer we're declaring this in the Constructor because spring is going to use this Constructor as a way of identifying which dependencies are needed and then inject them so we'll then assign our red printer to the red printer in our Constructor arguments and the same for the blueprinter instance variable is now going to be the blue printer
44:00 - 44:30 argument and then the green printer there we go so we can now see that these dependencies are declared as needed inside of the color printer class so if we then go to where the color printer class is actually used which we can see was in colors application so our main class here we've got a red underline because well this is now needing the dependencies and we could just put the dep es in these parentheses here and just Supply them but but that's not
44:30 - 45:00 really a complete solution so what I'm going to do instead is I'm going to declare a private instance variable on this class which is a color printer and then we're going to create a Constructor for it and the Constructor is going to take an argument itself and it's going to be a color printer and we're simply going to assign
45:00 - 45:30 The Coincidence variable with the color printer argument provided in the Constructor there we go and we'll change our run method to use the color printer as provided there we go all is well but of course we now need to have this color printer available in our spring context so let's go back to our printer config and we'll create a bean and this Bean is of type color
45:30 - 46:00 printer and we're going to return a new color printer inut of course this is going to require some dependencies so how do we get access to those parentheses well there's a couple of different ways of doing this we can either use these methods directly inside of these parentheses or we can declare them as arguments inside of the color printer Bean declaration and I want to do that way so let's go Blue
46:00 - 46:30 printer and red printer and green printer see there that we need a red printer a blue printer and of course our green printer there we go so what's going to happen now when we start our application our application is going to look for configuration files it's going to find this printer config
46:30 - 47:00 it's going to create the beans for blue printer red printer and then green printer and then when it gets the color printer it's going to look in the application context for the blue printer red printer and green printer that it already has inject them into this Bean declaration and then inside of our application context we're going to have this color printer Bean which of course if we go over to our colors application here is then going to be injected into this class and we're going to use it inside a run so if we run this
47:00 - 47:30 application we should see our colors printed once more red blue and green very nice but let's demonstrate this one step further so let's create some new implementation so I'm going to create some new classes in here and we're going to call this one Spanish red printer and this Ms the red
47:30 - 48:00 printer and we just need to create our implementation for the print method now and this is going to return uh I believe Roo my Spanish isn't excellent but I should know that one so let's do the same now for the blue and green printers
48:00 - 48:30 just creating those implementations of course isn't enough we rerun our application here we can see that even though we have those Spanish implementations available we're still going to get the English uh for red blue and green on our Command line here if we go into our printer config and instead
48:30 - 49:00 of having the English blue printer we're going to have the uh Spanish blue printer we're going to have the Spanish red printer and then we're going to have the Spanish green printer we don't actually need to make any changes whatsoever to the color printer Bean declaration because these ones are going to be created first and then injected into this one if we rerun our application now we should see the Spanish equivalent of the red blue and
49:00 - 49:30 green English text here there we go so you can now see that we've got Roo Azul and Verde I apologize for my accent um but we do have those available so what's happened is we created different implementations different concrete classes different beans for the interfaces of the blue printer green printer and red printer put those inside of our configuration in has been declaration and then of course they're injected and made available to application just like that so that is
49:30 - 50:00 just one way of declaring beans but there are a number of other different ways let me show you how to do it with the at component family of annotations so we've covered one way of declaring Beans by using a configuration class but there are other ways and one such way is by using the at component annotation and its friends but more on those later let me show you how to use the at component annotation to declare beans here we are in our configuration file for our color printer class now
50:00 - 50:30 what I'm going to do is delete it completely get rid of it there we go now because in our colors application we still require our color printer when I try and run this application it should break so let's try that there we go we have a parameter of zero and Constructor color application required a bean of type color printer that could not be found so how do we clear those with a component well we'll
50:30 - 51:00 go to our color printer implementation which in this case is color printer input and on top of this class I am going to put at component and this does a couple of things first of all it says spring I am a bean so color printer impul is a bean an implementation of color printer and it should be put inside of the application context and it also says any dependencies that I require in my Constructor or any other way of declaring dependencies again more on
51:00 - 51:30 those later I want those to be injected as well so we can see here we require a red printer a blue printer and a green printer so note this error message is looking for color printer it should change to look for the red printer blue printer and green printer inside of the color printer inut class now so let's run this application there we go it's saying red printer cannot be found so what do we do
51:30 - 52:00 we can go over to our red printer here which let's choose the English red printer and again we can just put our component on top of this one great it's now moved on to blueprinter and should be no surprise looking for the green printer so let's do the green printer which is there there we go we have a successful
52:00 - 52:30 application run and it's printing out red blue and green so this is another way of declaring beans so of course if we wanted to swap out the English green printer for a Spanish one where we simply remove the at component from this class here go over to the Spanish implementation there's our component run this application once more we're expecting Verde instead of green there we go red blue and Verde so we can see
52:30 - 53:00 here the ACT component annotations on top of the implementing class Works in pretty much the same way as doing an app Bean declaration inside of a configuration class we can see that these beans are then available to inject as and when they are needed now I did mention that the ACT component annotation has some friends one such friend is the at service annotation now the at service annotation and there are others and they will come up as our course progresses does exactly
53:00 - 53:30 the same thing as at component it's perhaps just a little bit more descriptive as to what this class actually does and of course we've talked about the different layers of our spring application before and one such layer is the service layer inside of the service layer we use services so we wanted to label this particular class as a service as a bean and be able to inject this and to have dependencies injected into into this class one such way of doing it is with the at service annotation and to
53:30 - 54:00 prove this works let's run this once more and we can see that the application runs absolutely fine and if we were to for the sake of argument remove the at component annotation from the English blue printer and go over to the Spanish blue printer and then put an at service annotation on top rerun our application we're expecting aul instead of blue and there we go so we've talked about the at component annotation the at service
54:00 - 54:30 annotation and we talked about these configuration classes and bean declarations inside of them we did even mention that spring would go looking for these things when the application starts up but we didn't go into any more detail than that well this process is called component scanning and let's cover it in a little bit more detail now so let's talk a little bit about component scanning now component scanning is a process that starts when your application starts up now what happens during a component scan is that spring will look through your project
54:30 - 55:00 and it's going to look for beans and it's going to look for where beans are needed now if it looks at a bean such as our English red printer here which is declared with a component so it knows it's a bean equally if it found it inside of our configuration class with an app Bean annotation it would also know that it's a bean it's going to look at it and it's going to go does this Bean need any dependencies in this case no dependencies are declared we've done that once before by declaring them in our Constructor this of course doesn't
55:00 - 55:30 have a Constructor declared doesn't have any dependencies that it needs so what component scan will do is it will create an instance of this class and it would place it as a bean into our spring application context which you can think of as a pool of beans which when they're needed they can be plucked out and put where they need to be now what happens if it comes across a bean declaration that requires dependency one such example is our color printer
55:30 - 56:00 impul here so we can see that our color printer impul is a bean it's got the at component annotation on top but it does require dependencies a red printer a blue printer and a green printer as declared as arguments to the Constructor color printer Ino right here so what it will do is it will look in the application context look at that pool of beans and go do I have the beans that I need to meet these dependency requirements in this case it does have a red printer a blue
56:00 - 56:30 printer and a green printer so it will pluck out those beans from the application context and put them into where they're needed in this case the Constructor and that process is called dependency injection but it's also called Auto wirring which is a more spring specific term you may come across now we've already seen it a little bit before if spring finds all of the beans that it needs then the application starts up absolutely fine which in this case we can demonstrate by just running this application here there we go process finished with exit Code Zero and
56:30 - 57:00 we can see three colors printed here but what happens if spring doesn't find the beans that it needs well it fails to start up in this case if we were to go to our Spanish blueprinter and remove the service annotation we have seen this once before the application fails to start up and it gives you a helpful error message saying that parameter one of Constructor of our color printer imple required a bean of type blue printer and that could not be found because component scanning went ahead looked everywhere and could not find an
57:00 - 57:30 implementation a bean of type blueprinter available inside of the application context so let's put that annotation back so component scanning starts at a particular point in your project hierarchy it starts looking for all those beans and where beans are needed and it works its way down the tree now traditionally you would use an at component scan annotation to tell spring that start point and all of the packages under that particular start point will be searched for beans and places beans are needed in a spring boot
57:30 - 58:00 application for example we don't use that anymore we actually use the at Spring boot application annotation it happens to declare if we take a look inside of it an at component scan annotation on the top for us so what it says is start at this point here we minimize this and look for everything in this package and Below which of course includes our service package here our
58:00 - 58:30 imple package here and everything inside of these packages for example if we were to take our services directory and we were to move that I don't know let's uh move package or directory to directory and let's move that to I don't know uh comevo we can now see this lives in in a place that component scanning would never ever look so if we were to run our
58:30 - 59:00 application now we shouldn't be surprised when it doesn't find any beans there we go it cannot find color printer any longer because it's in a place that component scanning would never ever look if we then put that back to where it needed to be there we go it's found those beans once more and everything is absolutely fine quick note it's worth pointing out that yes this directory is called Maven but the fact it's called Maven is of little relevance it could be called
59:00 - 59:30 absolutely anything fact it's called Maven is a hold over from a previous rendition of this particular project but the point is this we'll declare at component scan at a point in our project and then everywhere from that point downwards would then be looked for for beans and the places that beans are needed so we did touch a little bit on our spring boot application and we can see that it does a whole lot more than just component scanning so let's look at this in a little bit more detail now so we've been using the at Spring
59:30 - 60:00 boot application annotation for a little while now originally we said it was there to label a spring boot application and while that is true we've since learned it does a lot more than that now the at Spring boot application is an alias for a number of different annotations and these are the three main ones we'll look at them a little bit more detail in a moment but let's explore what each of them do so the ACT configuration annotation we've already come across this one this identifies a configuration class which is somewhere
60:00 - 60:30 that spring should look for beans during its component scanning phase and then we have the at component scan annotation which says from this point in the project hierarchy down look for beans and places that beans are needed and then we have the at enable auto configuration annotation we've previously mention that spring boo is so powerful it makes spring framework so much easier to use by providing sensible defaults how spring boot does that is
60:30 - 61:00 via this process called autoc configuration and we're going to cover that in a moment but before we do so let me just show you the at Spring boot application annotation a little bit more detail on a project so let's flip back to our colors application we using one moment ago and here we are at the colors application main class and there's our at Spring boot application annotation on top and I'm going to use my IDE to go to this class and looking at this class we can now see that it has several annotations on there the first one we
61:00 - 61:30 were looking for was configuration which is actually Alias away under this one here we can also see that we have our component scan declared here we've already kind of covered this one once before and then we have our enable auto configuration annotation so let's cover Auto configuration in a little bit more detail now so let's talk about Auto configuration and the spring boot boot starters so autoc configuration is that process that spring boot uses when it
61:30 - 62:00 starts up to provide those sensible defaults and create all of those dependencies now the spring boot starters are a collection of those dependencies which are there in order to solve a particular problem now one such stter that we're going to take a look at at the moment is spring web so we're over here at the spring initializer so we'll go over to select Maven Java the current version go com Devo this artifact we will label starter and we'll say a demo for
62:00 - 62:30 spring boot starters select a jar Java 17 and now we're going to go over to dependencies and if we take a look through here there are various starters those collection of dependencies now we're going to use spring web for this one and we're simply going to download this and open it up in our IDE so here we are with our project opened up in our IDE so first of all let's go
62:30 - 63:00 to our pom.xml file where all of our dependencies can be found and if we look inside of our dependencies node here we'll see that front and center we have the spring boot starter web dependency in here and the spring boot starter web is the collection of dependencies that we need in order to implement a web project including spring MVC and the embedded tomc cap which is the application container that we need in order to run a web project so if we were to actually go
63:00 - 63:30 into this by command clicking or control clicking we can see that it has a collection of different dependencies and they are listed here there's the Tomcat one there's MVC there's some Json and we'll cover Json a little bit more detail a little bit later on but you can see all of those dependencies so that's the starter where does the auto configuration come in well there's actually a good way of demonstrating this so if we go down to our external libraries here we are looking for the spring boot Auto configuration
63:30 - 64:00 package here we are we can see spring boo Auto configure and if we expand this one and take a look at the classes here we can see various different packages for various different projects now if we were to scroll all the way down to web take a look in here we have some classes and this is where the spring boot magic is so these particular classes we'll take a look at all of the dependencies that we have available in our project
64:00 - 64:30 such as the ones provided by the spring boot starters they're going to create classes with sensible defaults and then Place those resultant beans into the spring application context to be used throughout our application so let me show you an example so if we went into web serlet here and let's scroll down let's take a look at the dispatcher seret Auto configuration now the details as to what these particular classes do is kind of a little bit outside of the scope of this but it will be enough to
64:30 - 65:00 say that these particular classes are needed in order to have a spring web project now in a spring framework project you would be creating these yourself configuring them yourself in a spring boot project these classes are going to create the beans and configure them for you and you can see that this class has several annotations on top Now The annotation I'd really like to draw your attention to is this at conditional on class now what this is saying is when this class is available on your class path this class the dispatcher server
65:00 - 65:30 Auto configuration should be instantiated and run now there's also some other annotations and one such annotation is conditional on bean I believe it is in this class let's go looking for it conditional one bean again is very very powerful it says when this Bean is available then this particular part of the configuration should be run the inverse is possible as well there is a conditional on missing Bean let me show you
65:30 - 66:00 this here we go and we can see that if this Bean is missing then this part of the configuration is run now don't stress too much about how spring boot does this just like you don't need to know how a Car Works in order to drive it you don't necessarily need to know all of these details in order to use spring boot but in all honesty a foundational knowledge in this sort of stuff will help you to understand spring boot more holistically so spring boot does an amazing job at configuring your application depending
66:00 - 66:30 on what dependencies you have available on your class path but there are going to be times when those sensible defaults aren't quite what you're looking for and perhaps the easiest way of changing those sensible defaults is by using configuration files so if you look here we have our quick start application from earlier so that hello world one so if we were to run this by going over to quick start application here and then clicking on the little play button we should see that Tom Cat started up on Port 880 and if we go over to a browser
66:30 - 67:00 we should now be able to hit our application on Port 880 hello and we can see that it says hello Devo so our application is up and running so let's say for the sake of argument we already have something running on Port 880 and we want this application to run on Port 8181 well it's just not enough to try and hit the application on Port 8181 if we were to try that for example we can see that the site can't be reached so
67:00 - 67:30 how do we change our application to use that Port well we can do so via the configuration files so if we take a look at our application once more we can see here in Source main resources we have this application. properties file and it's completely empty for the time being so we know that we can change the port the application runs on by putting something into this file but we don't know right now what we need to put into application properties how do we figure it out luckily it's very well documented
67:30 - 68:00 online so we go over to our browser again we can take a look at this page at the spring documentation which is our common application properties now if we take a look here we have a set of keys and then what the keys are there for so for example debug is there to enable debug logs so we can put debug equals true in our application. properties and we can get debug logs out and it's the same for pretty much anything that you can configure via spring boot here so we
68:00 - 68:30 want to run our application on a different port so I'm going to click on web properties which Scrolls me down here and there's still a lot to look through so I happen to know that it's server. Port there we go so we can see here the default is Port 880 but we can provide this in our application. properties file and have the applic run on a different port and again loads of different properties for all different things that
68:30 - 69:00 you'd ever want to configure so let's go back to our application and use server. and our application. properties file so I'm going to Simply type serverport equals 8181 and I'm going to restart the application now there we go we can see that Tom cat has started on P 8181 so if you flip back to to our browser and try hitting the application on Port 8181 again we can see that we now get hello Devo so we
69:00 - 69:30 were able to configure those sensible defaults by using a key and a value inside of our application. properties file but it doesn't have to be in properties format so if we go back here and we were to change it to be from application. properties to application. yl yaml being a different format so we can see here that properties follows this key equals value whereas yabble likes to use this indent way of doing
69:30 - 70:00 things there we go you can see it's server Port 8181 but for the sake of argument I'm just going to change that to be 8282 rerun this application we can see that it's been picked up Tom Cat started on Port 8282 and to prove that try hitting on 8181 again that's no longer working so we're going to change it to be 82 82 there we go we have hello Devo once
70:00 - 70:30 more now there are some benefits to doing this in yaml if you so choose of course you don't have to repeat the beginning of keys all the time you can simply just inden instead now worth pointing out at the moment is if we go down to the test resources file here we can also have configuration files in this directory so we to create a new file in here and then call it application do
70:30 - 71:00 properties there we go we can see that the icon is such and we have this application. properties file in Source test resources now anything we place in this file will be used in tests so the source main resources will act as a base and then anything that's provided in Source test resources that will be preferred when we're running tests now this can be really handy so for example if you're using an inmemory database inside of your test the last thing you
71:00 - 71:30 want to do is to use the actual production database configuration that you have in your Source main resources so what you can do is you can put your test database your in memory database configuration inside of source test resources and that will be the database used in your tests but that isn't the only way of getting configuration into your application you can also use environment variables let me show you that now spring boot can load its configuration from a number of different
71:30 - 72:00 places we've already seen it load it from configuration files it can load it from command line arguments and it can also load it from environment variables and this is really important because when you're run your application in things like Docker it's environment variables you'll typically use to configure your application so you can see here we have our quickart application once more our hello world application and it's using the sensible default so both applications properties and application test. properties are completely empty meaning that the application is going to run on the
72:00 - 72:30 sensible default of Port 880 to prove that let's go over to our browser go to Port 8/ hello and we can see Hello Dev Tio now let's say we want this application to run on Port 8181 but we don't want to put anything in our configuration file we want to configure it using environment variables but first it's worth covering how you would change a key as you would find in the common application property here into an environment variable and it's uh pretty straightforward as a general rule you
72:30 - 73:00 would take the key you would make it uppercase and anytime you have a delimiter such as a DOT or a hyphen you would replace that using an underscore and spring boot is going to use some fuzzy matching logic to then look for various environment variables which match that pattern so if that's not quite clear we'll take a look at server. Port here we can see that server. port 8181 is something you would typically find in an application. properties file
73:00 - 73:30 the environment variable equivalent is server underscore Port so we go back to our application here we are and let's stop this running application now the first way that I'll show you to use this environment variable is directly via intellig which is the way that we've been running things so far so we go up to the configuration here we'll go to edit configurations we can see that we have this environment variables part here so I'm going going to type in here server uncore Port equals
73:30 - 74:00 8181 clicking okay and now if we were to run the quick start application once more we can see the environment of variables been picked up and we can see that Tomcat is now running on P 8181 so let's confirm this in our browser go change that to 8181 and we have hello Devo once more so that's if you're running via intellig let me show you how you would run it via the command line so there's a number of different ways of running your application from the command line and the first one is via the maven spring
74:00 - 74:30 boot plugin so if we were to Simply put our environment variable before that command it would be picked up so if we type in here server uncore port and let's change this to use port 8282 and then we're going to use the maven wrapper spring hyphen boot colon run we should find that application starts up on Port
74:30 - 75:00 8282 there we go Tom Cat started on Port 8282 let's confirm it in our browser there you go hello Dev Tio so that's one way of doing things cancel this of course you don't necessarily need to provide it every single time you run the command if you were to export server underscore Port let's say 8383 to your environment remove that and then we'll just do Maven rapper spring boot run we should find
75:00 - 75:30 our application start up on P 8383 bring going to look at our environment for that configuration we can see that Tom Cat started on P 8383 here running absolutely fine and both of these approaches is providing your environment variable before your commands and also in your environment works when you're running via the jar file so if we were to package up our application in order to get a jar file here perfect and now go to the Target
75:30 - 76:00 directory we already have our environment variable in our environment so if I go Java hyphen jar and then we'll run our Java file which is called quick start here we should find that our application starts up on Port 8383 once more there we go Application started on P 8383 let's confirm that in our browser there we go absolutely fine application is up and running configured via
76:00 - 76:30 environment variables so we can see that we can configure just about anything that we want to when using a spring boot application in the same way that if we were using spring framework directly but what if we wanted to have some custom configuration used by our custom code but loaded in exactly the same way as all the other configuration for spring Boot and for spring framework well let me show you configuration properties so here we have the pizzza application and the pizzza application is a very basic command line application which simply
76:30 - 77:00 prints some pizza information so for example here we have some pizza config and the pizza config has go to the class three instance variables one for Source One for topping and one for crust and you can see that we have these annotations on top we've maken use of lombok so at data makes this a data class so essentially all of the gets and sets equals and hash code all of that is already implemented for us by using this
77:00 - 77:30 annotation and we have some noas Constructor and some allas Constructor already implemented for us simply by using these annotations if you want to learn more about lombok then check the description below because we do have a full course on lombok as well completely for free available on YouTube so we have this pizza config class and we can configure it with a source a topping and a crust our pizzza application simply just prints out I want a m crust pizza with M and A M sauce so if we were to
77:30 - 78:00 run this I want a thin cross pizza with mozzarella and tomato sauce you can see that information is being provided in this class right here where it's constructed using the Java new keyword let's change this to use configuration parameters and then we can pass this information in by using environment variables or the configuration file or any other way that spring boot loads its configuration so first things first let's delete the
78:00 - 78:30 pizza config new there we still do need pizza config available though so we will inject that let's create a private instance variable call this one pizzza config and then we'll need our Constructor for pizzza application and we're going to declare that we need an instance of pizza config available and we're just going to assign that to our private instance variable lovely stuff and we can see
78:30 - 79:00 here that it's picked up it's using the pizza config instance variable now and it's going to print that out but here's the thing we don't have an instance of the pizza config being available in the application context so you can see here when we run the application we're seeing that we are not finding a required Bean of type Pizza config it can't be found how do we make it so it is is found now we can declare it inside of a configuration class and that's one way of doing things but we want to load this
79:00 - 79:30 as configuration from a from a properties file or from a environment variable so we'll go over to Pizza config so we're going to add another annotation on top here and I'm going to call it a configuration properties now configuration properties annotation has a very important argument and that is the prefix this prefix is the prefix of the key that then spring will look for inside of your configuration properties file configuration yaml file environment variables anywhere that it needs to look
79:30 - 80:00 and we're just going to call this key pizza because that seems relevant for now so we've declared our pizza config class is a configuration properties class but there is one additional step that we need to do and that's that we need to put an act configuration annotation on top because we need to tell spring that hey you need to look at this class in order to find beans uh in this case it's a configuration property Bean so if we were to run this application now we can see the output is I want a
80:00 - 80:30 null cross pizza with null and null source which sounds terrible and the reason being is that it's not finding any of the keys as declared here so if we go over to the resources and application properties I'm going to type pizza. source and let's call that barbecue pizza. topping and let's call that chicken and then pizza.
80:30 - 81:00 crust and we're going to have a stuffed crust so this pizza is the prefix that we declared inside of the configuration properties annotation and we can see here Source topping and crust matches the instance variable names inside of our pizza config class Source topping and crust so if we run the application again we should see this information popular ated inside of this string here there we go I want a stuffed cross pizza with chicken and barbecue sauce
81:00 - 81:30 There we go see it's loaded that information that configuration properties is now working of course it also works in the various other ways of loading information if we were to remove pizza. Source from our application. properties and we were to go into the configuration here and we were to go into the environment variables Pizza Source all up okay and we'll change this to be uh tomato click okay run our application we
81:30 - 82:00 should see it's moved from barbecue sauce to tomato sauce I want a stuffed cross pizza with chicken and tomato sauce and that's how you can leverage all of the configuration loading behaviors of spring Boot and spring framework for your own custom code when you're building an application you typically need to store data somewhere and relational databases like postgress and SQL have been very popular choices for a very long time now although it's not the only solution you
82:00 - 82:30 can go a long way by storing your data in the rows and Columns of a database and spring framework makes it really easy to use them to understand the different tools that you have at your disposal you'll need to understand the different layers of database technology and where spring Boot and spring framework comes in So at the bottom here we have the database driver and this is pretty easy to understand any major database like my SEC or postgress will make a Java database driver available to you and this allows you to interact with the database from your Java code and the
82:30 - 83:00 major database drivers are even available from the spring initializer so next up the chain you have jdbc or Java database connectivity now we consider this a load level API and what we mean by that is that you interact with the database by using SQL queries a lot of developers love this because you get fine grain control on your SQL queries which really allows you to optimize things however you've got to handle all of the mapping to and from java objects yourself and the more complicated
83:00 - 83:30 objects get the more that you have to do and it's not exactly interesting work spring jdbc Builds on top of jdbc with some extra spring magic and gives you things like the jdbc template which makes interacting with a database using SQL even easier than just plain jdbc so next other chain you have jpa or the Java persistence API now jpa superpower is to allow you to interact with a database by using Java objects jpa handles all of the generation of the SQL
83:30 - 84:00 and the mapping to and from the Java objects for you it's worth noting that jpa is built on top of jdbc so we consider it a high level API one of the wonderful things about jpa being so high level is hypothetically you could swap the database that you're using or the persistent technology that you're using and then not have to change a lot of your code all of the quirks the individual databases is all handled for you by jpa now technically jpa is a specification the actual implementation
84:00 - 84:30 or at least the one used by the spring ecosystem is called hibernate and you'll often hear developers that use spring refer to jpa and hibernate synonymously spring data jpa again Builds on top of jpa adding some additional spring magic such as the repositories that we'll see a little bit later it's worth pointing out you may hear hibinate referred to as an o M that is an object relational mapper omm's map from SQL to Java
84:30 - 85:00 objects and then back again so in summary database driver is what you need in order to interact with a specific database jdbc is how you connect to the database and query it using SQL and jpa is how you would query that database using Java objects so let's move on to some examples of using databases from a spring boot application so first up I'm going to show you how to connect to an in memory H2 database from a spring boot application now the H2 database really is the go-to in memory database at least
85:00 - 85:30 in the spring ecosystem and it has a high degree of support there so let's go over to the spring initializer and download our skeleton project so we're going to need Maven Java is our language the general release version which at the time we're recording is 311 our group is going to be Comm Devo our artifact let's call this one database and the description we'll say a demo project for connecting to a database we'll tweak that a little bit
85:30 - 86:00 later on package name is fine packaging of Jar Java version 17 and now for dependencies first one I'm going to add is lombok because we're going to need access to a logger and potentially need to create some classes so lombok is going to make that nice and easy for us not strictly needed for anything database related mind you for the database stuff we're going to need the to database of course and we're also going to need a way of connecting to it and we're going to use the jdbc API for
86:00 - 86:30 this and that is everything that we need so let's download this and open it up in our IDE so here we are in our IDE and I've taken the liberty of changing the database application class ever so slightly so you can see here that we are injecting a data source object that object for interacting with the database and you can see there's the Constructor which does the injection and if we scroll down we can see that we have that run method so we're implementing the command line Runner and in the run
86:30 - 87:00 method here we are simply printing out the data source doing data source. twring loginfo getting our logger from our at log lombok annotation there now we're creating an instance of the jdbc template more on that a little bit later on but for the moment it's worth noting that I'm using this to query the database and I'm querying the database with the query of Select one it's not going to do anything but it is going to allow me to demonstrate that I have actually connected to this database and
87:00 - 87:30 I have managed a querium now other than that the application is completely fresh if we look at the application. properties here we'll see it's completely empty and if we go up to the database application we can see nothing extra in the way of environment variables or configuration now if we run this application you are going to see something fairly interesting so let me run this now so if we take a look at the logs down here you can see that the application is started our Hikari pool so the way that we're connecting to our
87:30 - 88:00 database is starting up here we've added our connection we've managed to connect to the database and then we've shut down so everything seems to have gone absolutely fine the thing of course is this line here we haven't specified how to connect to the inmemory H2 database but somehow it still managed to figure it out and that's because of the high level of support for the H2 in memory database there's Auto configures which if it
88:00 - 88:30 finds the H2 in memory database on the class path it will automatically create the beans needed in order to connect to this database we don't need to specify where to find it any username or password you can see it's already done all of that for us of course we can specify this information explicitly if we choose to and we can do that in the application. properties here so let me populate this with that same information that's used by default and we'll go from there so when using an inmemory HD database the configuration would
88:30 - 89:00 typically look like this so we have this first property spring data source URL where we specify where to find the database jdbc because it's a jdbc connection H2 because that's the type of database we're connecting to we're using an inmemory database rather than a database on disk which is also an option for H2 and then we're naming our database test DB we specify our driver class name we're using a H2 driver to connect to a H2 database of course and then we have our username which is sa by
89:00 - 89:30 convention and then the default password which is password so if we run this application now we should see that we are still able to connect to the H2 inmemory database there we go we can see that we've added a connection slightly different information because we are naming this one testb but you can see that it's went absolutely fine aari b as start completed and then the application shuts down so that is how you will connect to a H2 inmemory database so connecting to an inmemory
89:30 - 90:00 databases are well and good but how do you connect to a real database well let me show you how to connect to a postgress database from a spring boot application so over here at the spring initializer let's set this up as before so we're going to use Apache Maven Java the general release version of spring boom our group is going to be com Dev Tio our artifact we're going to call this one on database a demo project for connecting to a database can always tweak that
90:00 - 90:30 later package name comp interior database packaging of Jar Java version 17 and now for our dependencies as before we're going to add lombok to give us easy access to our loggers and also if we need to create any classes and now for the actual database dependencies first things first we're going to need our post SQL driver so let's select this one and we're also going to need our jdbc API so let's generate this and open
90:30 - 91:00 up in our IDE so here's our application inside of our IDE as before I've taken the liberty of updating our database application class here I've added at log in order to get easy access to a logger we are injecting the data source object here and then in the run method we are simply printing out the data source using log. info and using our rest template which is an easy way for me to interact with the database and we're executing the query select one it's not
91:00 - 91:30 going to do anything but it is going to allow me to show that I have connected to a database and execut the query other than that the application is as default the application. properties is empty and there is no additional configuration as environment variables or anything like that there is one additional file however and that is this Docker compose file down here now I've used this Docker compose file cuz it's going going to allow us to easily start up a postgress database we can see here that we're using the image postgress it's going to
91:30 - 92:00 run on Port 5432 and we're using this environment variable in order to specify the password of Change Me In prod exclamation mark So before we start this database let me show you what the application does when it can't connect to a database so we're going to go over to database application here and then run our application here we are it's failed to start up so we can see exit code one if we scroll up here it says fail to determine a suitable driver class but
92:00 - 92:30 that's not strictly what's happening here you can see that we failed to configure a data source because the URL attribute is not specified and there is no embedded data source that could be configured so essentially it's not found the configuration fair enough we don't have a running database we haven't found the configuration that's absolutely fine so we go into the application. properties here let's populate the configuration which tells this application how to connect to the database so here we are in application. properties and we can see that we've got
92:30 - 93:00 this pattern that we saw before in the H2 example spring data source URL or using jdbc postgress SQL on Local Host 5432 which is where we know our database is going to run we want to connect to the postgress database which is the default one which is always going to exist for demonstration purposes anyway the username that we're using here is postgress which is the default user and the password that we're using is the one that we specified in our Docker compost file which is change me in exclamation mark and of course we're
93:00 - 93:30 specifying that we're using the driver class name of postgress SQL using a postgress SQL driver to connect to a postgress SQL database so this should be enough information for the application to connect to the database if it was running which it currently isn't so let's click on play here to start our application to see what the error message we receive okay here we go we have a error we have a stack Trace connection
93:30 - 94:00 refused connection to Local Host 5432 has been refused check the host name and the port are correct this is expected because of course we're not running our database just yet so let's open up a terminal and let's start our database by starting our Docker compose so in the same directory as our Docker compose file we simply have to do Docker hyphen compose and up of course you will need Docker installed on your machine in order to do this there we go you can see the database system is ready to accept
94:00 - 94:30 connection let's start this application and see if it connects to the database providing of course the information we provided to it is correct go to our database application and then we'll click on play okay here we go this is interesting here so this is a slightly different output from what we've had before we can see that our application has started up Tomcat has started up and if we look down here Tomcat has started on Port 88
94:30 - 95:00 there's our Hikari Source it's started up and then it's added a connection to the postgress database and it's managed to connect absolutely fine so the connection has gone absolutely fine but it's approached it in a slightly different way from the H2 in memory database you can see here that Tomcat has been spun up in order to connect to the real postest SQL database now nevertheless this is how you connect to a post SQL database from a spring boot application so you've managed to connect
95:00 - 95:30 to a real postest SQL database which of course is great but typically you'll want to set up that database in some way you might want to create a schema and you might want to populate data actually spring boot makes that really really easy for you let me show you how that's done so here we are in the project that we've just looked at which is connecting to a postgress database however you can see there's a couple of different changes here if we go into Source main resources there is two files and by
95:30 - 96:00 convention one is called data. SQL and the other one is called schema.sql now we'll start with schema.sql essentially this allows us to set up the schema so this is run after the connection to the database is established and you can see here it's creating a table called widgets we're setting this up to be a widgets application and it's uh dropping a sequence of if it exists the widgets ID sequence and then it's creating a table called widgets which simply has an ID an
96:00 - 96:30 America ID and name of a widget and then the purpose of what that widget is for now if we look at data. SQL we can see that we're populating the widgets table with several widgets widget a through e and each of their individual purposes one's used for testing and this one enhances productivity this one is perfect for outdoor activities it's just populating the database with this data so what we want to happen is when our spring boot application start up we want for spring boot to look for schema.sql
96:30 - 97:00 run it against our database and do the same for data. SQL however this isn't all that we need to do in order for that to happen let's take a look at application. properties here so we've got all of our information for connecting to our postgress database here but we do have one additional key value pair and that is spring. SQL doin it. mode is always and that's simply saying that we always want to run schema.sql and data. SQL now in
97:00 - 97:30 production that's probably not going to be the case there are other values that you can provide to this key however for our demonstration purposes we always want to run these two SQL scripts there are alternatives to this approach however such as Flyway and liquibase but this is perhaps the simplest way of getting information into our database so let's start up our application now there we go we can see that Tomcat has started up we can see that the connection has been established and
97:30 - 98:00 everything seems to be fine here but how do we know that the data has been populated in our database well let's open up our database in a piece of software called Deaver so we can view it visually so dbeaver is free or at least the community version is free let's establish a connection to our database we are using a post SQL database here it's running on local host on the default Port we're going to connect to the postgress database everything seems fine here our
98:00 - 98:30 password is change me in prod exclamation mark let's try that again change me in prod exclamation mark Let's test that connection great the connection seems fine so let's finish this there's our postgress database let's take a look at the schemas there's our widgets table and there's our widgets data ID name and purpose this one is
98:30 - 99:00 used for testing purposes this one enhances productivity and this one is perfect for outdoor activities so we can see that the scheme has been established here we have our table and the data. SQL file has been run because it's populated this table with widgets a through e so let's cover how to interact with a database by using SE and we're going to be using the jdbc template for this so we kind of touched on the jdbc template before but we didn't go into it in too
99:00 - 99:30 much detail that's what we're going to do now so you can see here this is the project that we use to connect to our postgress SQL database go over to the palom here we can see the dependencies of spring boot started jdbc postgress SQL there was lombok and that's pretty much it if we look over on the application. properties here we can see we just have the connection information for postgress nothing more you can see here we don't have a data. SQL or a schema.sql nothing like that and if we go over to our database application we can see we don't implement the command
99:30 - 100:00 line Runner it's just a plain simple application so what do we need to do in order to get our jdbc template well we're going to create this in the configuration class way so we'll go over to our package here we're going to create the config package and inside of the config package we're going to create a class here I'm going to call this one database config so here we have database config we're going to add the at configuration
100:00 - 100:30 annotation which specifies this as a configuration class and then inside of our database config class we're going to create a bean and that bean is going to be public and it's going to be jdbc template Bean now the jdbc template requires a data source so we're going to specify that as an argument there we go and then we're going to return a new
100:30 - 101:00 instance of the jdbc template passing in the data source so it can connect to our database and just like that we have a jdbc template being available in our application context that we can now use for querying our database so one of the many different patterns that you can use to interact with your database using SQL is the Dao or data access object patter but what exactly is a Dao so let's consider this domain we have books and we have authors and an author can write
101:00 - 101:30 many books but a book will always have one author put it into database terms it might look a little bit like this a book has various different attributes has an ISBN which is a text attribute and is its unique identifier it has a title usually on the front cover and it has an author ID which we use to reference the author now the author in this case has a numeric ID its unique identifier the name of the author and then the age of the author now let's imagine there were
101:30 - 102:00 three services in our service layer which needed to interact with the database they needed to interact with the authors and the books that we store in our database in this case if we're using jdbc each of these Services we need to know about the structure of that database how to query it using SQL and then they would each need to deal with the conversion to and from java object and SQL and of course that would result in a whole bunch of duplicate codes now let's say we took all of that duplicate code and we put it into a class
102:00 - 102:30 corresponding to an entity in this case a book Dao and an author Dao it would be the responsibility of these classes to know the structure of the database in relation to their specific entity and to handle all of the mappings to and from java objects and SQL and then each of the services could inject the relevant d o which in some cases could be more than one and make use of their behaviors via a nice clean interface so really when
102:30 - 103:00 you think about it a Dao allows for that separation between the service layer and the persistence layer and allows for that extra modularity which of course makes writing the application maintaining the application and testing the application a whole lot easier so that's the theory on what a Dao is but how do we actually Implement one let's set everything up so we can do that so here we are at the project that we've just left so we can see here that we've got a jdbc template inside of our
103:00 - 103:30 configuration class this is a bean so it's available inside of our application context now we need to do a few things to set this project up so we can Implement some daos and the first thing is we need to create a schema in the database we already know how to do this so if we go over to our project here go Source main resources you're going to create a schema.sql file and to this file I'm going to create the SQL schema as we shown earlier as a
103:30 - 104:00 reminder the schema needs to look a little bit like this so we need an ISBN title and author ID on the books table and then we need an ID name and age on the author's table and we need that foreign key constraint from author ID to author so let me populate the SQL now here we go we're creating the table authors here ID name and age got constraint the primary keyy here of course the ID for authors and then we're creating our books table ISBN title author ID and then we have a constraint
104:00 - 104:30 on the ISBN for that to be unique as it's the primary key there and then we can see we've got a foreign key constraint from author ID to the ID on authors so this will create the schema that we need that is step one step two of course we need to go to our application properties and make sure that the schema is going to be run so let's add the key here we'll set this to be mode always for it to always run of course in a production application you probably don't want this
104:30 - 105:00 to run every time the app starts up okay now let's create our domain classes let's go over here let's create a directory and let's call this one a domain directory so it's Dom main package and inside of here we need to create two classes one is going to be our author class and the other one is going to be our book class so let's start with the author as a reminder our author class needs an ID which is numeric a name and an age let's
105:00 - 105:30 create these instance variables on this class and we're going to use lombok to make this easier so data create a data class so that creates our uh equals and hash code and two string and all that good stuff for us and our Getters and Setters that's the main one we'll have an allas Constructor and we'll have a noas Constructor and just in case we want to Let's create a builder for this as well so we can use the Builder pattern and we need to create it was a numeric ID so let's use a long for this I'm using long
105:30 - 106:00 capital L to use the object so it could potentially be null if we're using little L long then it will default to zero which might be a bit confusing so we're going to use the long object so it can be null then of course we need the name of the author which is going to be a string and then the a of the author which is going to be an integer capital I integer rather than int for the same reason as
106:00 - 106:30 long it could potentially be null and we'll call this one age so that's our author object now let's handle our book object so as a reminder a book needs an ISBN which is a unique identifier but this is text so it'll be a string it needs a title which is also a string text and then it will need author ID which is a numeric ID which will be a reference to the author here so data all R Constructor no R Constructor builder
106:30 - 107:00 in case we want to use that then we have a private and it was a string called ISBN we have a private string which is the title and we're going to do a private long which is going to be the author idid now you may be wondering why aren't we using an author object here well the book class that we have here is going to map pretty much directly to the
107:00 - 107:30 structure of the database and the structure of the database is such that it will have an author ID a numeric ID in the table rather than a nested author object if that makes sense so we're going to go with the author ID which is a long inside of this class rather than the author object okay with the domain objects created we'll now go ahead and create a da o package to contain our daos so inside of the Dao package we're going to create two interfaces to begin with one is going to be our book Dao
107:30 - 108:00 interface and we'll leave this empty for the time being and we'll create an author Dao also an interface leave that empty for the time being now as a bit of a convention whether it's good or not does keep things tidier so we're going to create an impo Direct Dory to contain our implementations of our interfaces and inside of here I'm going to create a author Dao
108:00 - 108:30 impul and we're going to implement the author Dao which of course doesn't have anything declared on it as an interface at the moment completely empty and we're going to do the same for the book Dao book Dao impul and that's going to implement the book Dao class now now we do know one thing about both of these classes and that's that it's going to need the jdbc template for whatever we Implement in it
108:30 - 109:00 from now on so let's create a private instance variable of jdbc template and in our Constructor we're going to declare jdbc template jdbc template and then we'll go this do J DBC template equals jdbc template and that's going to allow us to inject the jdbc template into this class or autowire it
109:00 - 109:30 into this class now because we're using the Constructor it comes with the bonus that we can make this final so it can't be uh reassigned once it's instantiated which of course makes things a lot simpler and easier to reason with we can actually go one step further and make this final as well now it's going to be pretty much the same in the other class so I'm going to copy this line go to the book Dao inut do that there and I am just going to make use of my IDE in order to
109:30 - 110:00 add that Constructor parameter for me but I am just going to add that final there we go so we now have access to the jdbc template as an instance variable inside of this class which doesn't have any methods yet we'll add those in a moment so when we're implementing our daos we absolutely want to test them so let's set up our tests now I want to do some integration test for this so what that means is we're going to start up a test version of our spring application which also is going to mean we need a
110:00 - 110:30 database now we could use a real database and use something like test containers to start that up I'm going to elect to use the H2 in memory database for this one in order to keep things simple but still get the value of testing against the real database so let's go down to our pom XML here and we can see we've got our dependencies it's got post SQL runtime so that's our production dependencies and then our test dependencies start we can tell that CU it has the scope of test there I'm going to add in the H2 in memory
110:30 - 111:00 database as a test dependency we can tell that because it has the scope of test so this won't go anywhere near our production dependencies it won't be run when our application is run it will only be used in the tests so we're going to use H2 there but of course we need to tell spring how to connect to it and the specifics on how to connect to it so we're going to go to our application. properties but we're going to do do that in Source test resources which it looks like we need to create so let's create that that's a nice little shortcut let's create application.
111:00 - 111:30 properties in here very good as an empty file so I'm going to populate this file on how to connect to an inmemory H2 database inside of tests and here we go let me talk you through this because it's ever so slightly different from what you've seen before so the H2 database has a specific mode setting so it allows it to emulate the specific quirks of some databases one such database is postgress
111:30 - 112:00 so we've got here jdbc it's a jdbc connection H2 because that's a database we're connecting to and in memory one called testb but we're saying here the mode that we want H2 to be in is the postgress SQL mode so emulate the quirks of postgress essentially and we're saying database to lower is true so we're using lowercase names uh H2 likes to have everything uppercase postgress tend to do things in lowercase and the
112:00 - 112:30 default null ordering is high so this this particular settings allows it to be the most like postgress or at least the most likee postgress that I've managed to figure out so that dependency is now available in test and we've set up the configuration on how to connect to that database inside of test when we use our spring boot test annotation so to test that now if we go to our test here which is the default one that comes with anything that comes from the spring initializer you can see this has at Spring boot test on the top which means
112:30 - 113:00 it's an integration test essentially it's going to start up a test version of our spring app when it runs so we're going to run this class and if it starts up absolutely fine it means that our H2 database is configured and in our application context and ready to go saying it can't find the H2 driver that may be because T hasn't refreshed uh from the pom file so I'm just going to click this tab on the right hand side to go to Maven and then click on this little button here to
113:00 - 113:30 reload the maven project okay let's try running this test once more great that test has passed which means that H2 is available in our tests and it looks like everything is good to go so we've just set up the skeleton of what's needed in order to implement our daos let's get on and start implementing them so previously we mentioned crud functionality so create read update and delete and we also mentioned that the persistence layer typically exposes crud
113:30 - 114:00 functionality so let's start with the create functionality so the C in crud so what we're going to do in this case is we're going to start with a unit test so we have everything set up for integration tests that will come later for here and now let's do a unit test so we're going to go over to our test directory here and I'm going to create a new package now I want this package to be a reflection of the production packages here so com Devo database already exists we're going to create the
114:00 - 114:30 Dao package and inside the Dao package we want to now create our test class so we're going to create a Dao for both the author and the book but considering that the book references the author I think we should start with the author so I'm going to create a new class in here and I'm going to call this one or author Dao impo tests cuz we're testing that implementation great stuff so here's our
114:30 - 115:00 class we need to set this up as a unit test now the author Dao impo is going to be using the jdbc template we already know that but we are writing a unit test here rather than an integration test at this point so I'm going to set this up for mocking using makito so we're going to set this up to uh use the extends with and we're going to use the makito extension class and that enables the makito functionality or at least it extends the
115:00 - 115:30 test Runner to be able to use the makito functionality and now we want to set things up so the class that we are testing is the author Dao input let's make that private and we'll call this under test as an instance variable now I'm going to place inject mock on the top of this and I'm going to create a private instance variable of the jdbc template and I'm going to place mock
115:30 - 116:00 annotation on top of this now what this will do is by using the makito extension and by putting inject mocks above the author Dao input which is our class under test and then putting mock on the jdbc template essentially before each test is run a new instance of the author Dao inut is created for us and then the dependencies the collaborators which in this case is the jdbc template a mock if that is created and then injected into our author Dao impo class now of course
116:00 - 116:30 we can do all of that manually in a setup function but this is a nice shortcut to do it all for us so let's now write our test so we're going to use the test annotation and then we're going to write public void because this test doesn't return anything and we're going to call it test that create author generates the correct SQL and we're going to write this test to make sure that the correct SQL is generated to be passed onto the database
116:30 - 117:00 so first things first let's call our under test class with the create method and then we're going to pass in an author which we'll call author and we're going to use the Builder here so we'll go author builder. build and then let's populate some information so of course's ID and then the name and the age so let's populate these
117:00 - 117:30 fields so for an ID we'll go for one and an L to denote it as a long the name will'll go for Abigail Rose and we'll go for the age of 80 there so there's our author and we're going to pass our author into the create method now you'll notice the create method is red and that's simply because it doesn't exist yet so we need to create that so let's go ahead and do that if we click on the create we get this little red icon here and then it gives us a shortcut to create the method create and we'll create it in the
117:30 - 118:00 interface there we go so the create method doesn't return anything so it's a void method and it will take an author of type author of course now let's go to the implementation we get a red squiggle because it doesn't exist in here yet so we're going to right click we're going to go to generate and then we're going to implement methods we make sure create is selected and then we'll go okay and that will create the outline of our create method for us but of course it doesn't do anything that's
118:00 - 118:30 enough for the moment let's go back to our tests great so that's now compiling we now need to assert on the Cal that's generated and the way that we do that because the create method doesn't return anything is by using the makito verify method so if we import this put a static method makito verify and we'll pass in the jdbc template now we want to verify that a certain method has called on the jdbc template with a very particular set of arguments
118:30 - 119:00 so the method that we want to verify on is update in this case because it's uh creating an object it's going to be using the update jdbc method you can see it's overloaded so there are some various different ways of cing it we're going to take this one here so we're going to pass in a SQL string and then a set of arguments and we're going to do this to create essentially a prepared statement so our SQL is going to include question marks and then the arguments as they're given to this method the underlying implementation is then going
119:00 - 119:30 to swap out the question marks with the arguments that have been provided now of course we could just pass in a SQL string and use string concatination like the plus signs to create the query using arguments but we're not going to do it that way because it's not safe by using this way by passing in the arguments to the update method and doing the prepared statement we essentially protect oursel from SE injection attacks so let's do that the SQL query that we're expecting is going to be something like insert into authors the name of the
119:30 - 120:00 table and then the column names which we know to be ID name and age the values and here's our question marks one 2 3 for ID name and age let's put that on a new new line so there's our SQL query what about our arguments well before we move on to the arguments there's a bit of a quirk with makito that we need to use matches
120:00 - 120:30 instead of the raw values now you can go some way on the raw values to make sure everything's working fine we're going to use matches in this case EQ to make sure that this variable is equal to the one so we'll use uh argument matches. EQ now EQ again we want to make sure that the arguments are are as follows basically the same as up here the ID we want to be 1 L the name well we know we want that to be
120:30 - 121:00 Abigail Rose so we'll just copy that for the moment and the AG EQ again we want to be 80 there we go and when the update method is called with exactly these variables the test will pass other wise we'll get a failed assertion and the test will fail so if we run this we should get a failing test there we go wanted but not invoked
121:00 - 121:30 insert into authors with the variables we got there actually there were zero interactions with this Mock and that shouldn't be any surprise because if we go over to the implementation here we can see that we haven't done anything yet so let's implement this method we're going to take the jdbc template we're going to call the update method on there and then we're going to write our SQL there's our query and now we're passing our arguments which we'll get from our
121:30 - 122:00 author object so author dot get ID author dot get name and then author. get age there we go so that should be everything that we need to do in order to create an author in our database so let's run our test and see if we get a pass looking good now if we were to perhaps change this run it again we should get a
122:00 - 122:30 failure looking good so that's confirming that everything is working at least from a unit test perspective so that's our create author method or implemented and working fine at least from a unit test perspective we're not yet at a point where I'm going to create an integration test that will come a little bit later on now let's implement the book create method we're going to do in exactly the same way and go down here into our Dao test package and we're going to create a Java class book Dao
122:30 - 123:00 imput tests and then we will do extends with the mikito extension like before inject Mox and then we're going to have a private instance variable with our class under test which we need know to be the book Dao input call that under test this two is going to have a jdbc template as a
123:00 - 123:30 mock and now we need to write a test which is public void test that create book generates the correct SQL very good so as before we'll do under test. create that won't exist yet we'll need a book so let's create a
123:30 - 124:00 [Music] book so ISBN title and then the author ID let's populate these with some values and now let's pass in the book to our create method great so that's not going to compile so let's create our create method which we do with that
124:00 - 124:30 shortcut go to the book Deo there we go as before it's not going to return anything it is a create method and it takes a book we go to the implementation let's implement the missing create method and of course it's empty very good so let's go back to our test now and now we'll need to verify that the jdbc template just import
124:30 - 125:00 that and this will do an update and the query we're looking for here will be insert into in this case the table books and then the column names are going to be ISBN title and it's author ID the reference of the author the values and this two is going to use the question marks three of them and the values that we're going to expect are
125:00 - 125:30 going to be use our eqs importing those that ISBN the title The Shadow in the attic and the author ID D which we know to be one there we go so let's run this test and we should get a
125:30 - 126:00 failure as expected wanted but not invoked because well it doesn't exist that implementation doesn't exist yet so let's now go over and create that implementation shall we now to uh speed things along I'm just going to copy that SQL and we're going to go over to the book Doo imple as before I'm going to call the jdbc template do update giving it that SQL I'm going to take the book get
126:00 - 126:30 ISBN book whoops get title and then book get author ID perfect and if we run our test once more we can see that everything passes if we just change the SQL just to be on the safe side we can see that was a correct green test perfect so we have created create
126:30 - 127:00 methods for both our author and our book now in the Dao style and that's the C in crud let's move on to the r in crud let's create some read methods so we've done our create methods now let's do our read methods now typically our read methods are split into a read one and a read many format so read one is typically you pass in an ID and if the entity exists in the database it's returns and if not you may
127:00 - 127:30 get a null or you may get an optional empty if you're using the Java optional now in the case of a read menu you either asked to get all of the entities of a certain type returned or you may use a query to get a subset of them and then you'll get a list of those entities returned in the case that no entities exist which meet your criteria in the database then you'll just get an empty list but you will still still get a list now we're going to implement the find one method for the books and the authors today but before we do I've noticed that this test directory doesn't fully match
127:30 - 128:00 what we have here so I'm just going to create a directory in here call it impul and then move our tests for our inut classes into that clicking on refractor that's better so let's create our find one method test first of all so we're going to again start with the author let's create our test so we're going to use the test on the public void and we're going to call this test that find one returns nope generates the
128:00 - 128:30 correct SQL there we go and we're going to go under test. find one passing in an ID which we use one L in this case let's create that method find one and we'll do that on the interface like so now here's the find one signature which currently returns nothing it's a void method we want that to return an optional I think
128:30 - 129:00 and we'll go for the optional of type author so in the case that the we find an author with the ID provided then we will get that author back wrapped in an optional however if the author doesn't exist we will get an optional back still but it will be an optional empty we do this rather than returning null little bit more type safe preferable so that is our find one method let's now go to the implementation create this
129:00 - 129:30 implementation here and it's just returning an optional. empty absolutely fine let's go back to our test we want that failing test first so let's do as before let's use that verify method so we're going to say verify jdpc template but rather than using the update method this time we're going to use the query method and you can see this is also so overloaded so the query method that we're going to use starts with a SQL query so let's start there I'm going to say
129:30 - 130:00 select and we'll declare the column names of ID name and age from table in this case is going to be authors let's stay consistent make that uppercase where and in this case we're going to say ID is equal to the ID provided now we only want one author return so I'm also going to elect to say limit one so
130:00 - 130:30 now we have a choice to make because we are using jdbc and we're using the Dao pattern we need to handle the conversion to and from SQL and Java objects ourselves there are several ways of doing this uh row mappers results extractors row callback handlers loads of different patterns in there the one that I'm going to choose today is the row mapper because I found that's the easiest way of testing for it as well at least in my opinion different people
130:30 - 131:00 tend to have different approaches to this I'm going to show you the row mappa way today so for our test at the moment we will make this better I'm just going to say any which is another matcher and I'm just going to say row mapper oh and it's rowmapper do class now of course it is a generic it does take a type we'll need to come back to that a little bit later on but bear with me and now the final argument that we need to take is going to be any arguments that we're passing in which in this case is going to be the ID so we're going to say
131:00 - 131:30 equals 1 L so you can see this isn't compiling because it's technically not matching the method signature or at least is not able to figure out which method signature it's matching because it's overloaded and it's to do with this row mapper here so before we can really get into the gut of getting a failing test we do need to do a row mapper so what we'll do then is we'll go over to our implementation we'll go to the orthod Doo impul and we'll create a row mapper
131:30 - 132:00 now the row mapper is there to convert from a result set which is something that's returned when we query the database and convert it into an object which in this case is going to be our author object now I'm going to choose to create our mapper as a class inside of our author Doo class here so a nested class we are going to create a public static class and we're going to call this author row mapper this is going to
132:00 - 132:30 implement row mapper of type author great so that's a red squiggle because we haven't implemented the methods here we do need to implement map R so you can see there it takes the result set and a row number and we're expecting an author back so I'm going to use the author Builder and an author it takes an ID a name and an age so our result set RS has some
132:30 - 133:00 methods on there that we can use in this case we can use get long and we'll use column labels so we know this one to be ID for name can use get string and for our age get int and it's age there so we can use this for as many methods as we need to inside of our uh
133:00 - 133:30 our implementing class here author Dao impul and because we do have this class name it also makes it easier to match in our matches so if we go back to our tests put that on a new line there is a bit of an incantation to make this work so I'm going to fully qualify argument matches any but I'm going to declare here the type of author Dao impul do author R
133:30 - 134:00 mapper if it seems complicated it's because it is a little bit but we're basically saying here when our argument matcher matches the author row mapper which of course we know to be a row mapper implementing the generic type of author and now that any matches at which point now is able to match this up against the right signature from the overloaded method okay no more squiggles in this class so we can now go ahead and run this in order to get our failing
134:00 - 134:30 test because we still haven't implemented any functionality in our method there oh I've missed equals on the top see this is what happens when you mix raw values with matches three matches expected two recorded So we put an EQ around the SQL query there we go so wanted but not invoked jdbc template. query and we can see up here wasn't invoked zero interactions with the mock so let's now implement it so go to our author Dao inul and let's Implement our
134:30 - 135:00 method okay so let's minimize that for the time being jdbc template. query we're going to pass in our SQL which will be a bit lazy and just take from our test here we go and for the time being I'm just going to create a new instance of the author row mapper now this is going to create a new instance every single time it runs which isn't ideal so we will we can optimize on that a little bit later on and then we need to pass in
135:00 - 135:30 the arguments which we know to be the well it's called L up here but we're going to call it the author ID in order to give it a better name there we go and then let's assign this to an instance variable and we'll call this results so we can see here we've got a list of auths which are results because we're using that author row mapper and we're doing a jdbc template. query with this particular query so we need to return now an optional of author uh perhaps the
135:30 - 136:00 easiest way of doing this is by using the stream API and we can then say find first which returns an optional of author and we can return this just like that so if we now run our test again we see we get a passing test which is fine so if we change that to be I No Limit 99 for example there we go got failing test so
136:00 - 136:30 yes that's passing absolutely fine now it is worth mentioning that we are just asserting that the query that we are building is what we expect it to be we're not actually running this against a database in our test just yet we will go onto that in a moment but first we need to implement the book version of this too so here we are in our book Doo Ino test so let's create a new test shall we this at test public void test
136:30 - 137:00 that find one generates or perhaps we will set we'll be saying find one book find one book generates the correct SQL there we go and we're going to call under test dot finds but of course doesn't exist quite yet now we need to pass in an ISBN so we're going to take this ISBN right here pass that
137:00 - 137:30 in great so fine doesn't exist but we should be able to create that now so let's create our method on the interface call this one ISBN oops we'll call this one string should I say and then name it ISBN great and as before this is not going to be a voice method is going to return an optional of type book in this case great so let's go to our implementing
137:30 - 138:00 class create that method it can just return an optional empty for the time being that's absolutely fine let's go back to our tests so we'll do verify jdbc template do query and then we need to write our query so we'll go select ISBN title author ID from books where ISBN is equal to
138:00 - 138:30 question mark and we'll also say limit of one great so we're going to have some fun with the row mapper argument matcher in a moment so we'll just leave that as is but the last argument to pass in is going to be the ISBN which is going to be the same as this one up here and let's wrap everything in eqs great so argument matches NE we do have those red squiggles because we
138:30 - 139:00 haven't declared our type there so let's create our row mapper over in our book Dao impo we'll do this in the same pattern that we did before again this may not be the most optimized of patterns but it does allow you to test it rather well and it seems to work rather well as well so we're going to go for a public static class and we're going to call this one book row mapper it's going to implement row mapper of type
139:00 - 139:30 book of course we need to implement that map row and we use the Builder again so book. builder. build whoops build ISBN title author ID and then we're going to go result set dog string ISBN result set get string and it's
139:30 - 140:00 going to be title and then result set get long and it's going to be author underscore ID and then we'll return this just like that great so that book row mapper is now available let's go back to our tests declaring the book row mappa type there great so we should now be able to run this and get our failing
140:00 - 140:30 test looking good jdbc template wanted but was not invoked zero interactions with the mock so let's now create some interactions by implementing our method jdpc template do query again let's grab that query from before and then we'll create a new book row mapper again not the most optimized we can optimize for that later put that on
140:30 - 141:00 a new line and we need to pass in our ISBN Also let's assign this to a variable which we'll call results that's a list of books so again we'll use the stream API to do a find first returning that optional of book so if we run our test again we can see that's passed
141:00 - 141:30 absolutely fine again let's just double check that by changing that to be limit 99 very good so that seems to be working as expected great so we now have implemented our create methods and our read one methods for both our books and our authors we're now at a point where we can write an integration test that provides a decent amount of value and we're going to do that right now so we've implemented create functionality and find one functionality for both our
141:30 - 142:00 author Dao and our book Dao and we've even tested that the SQL queries are as we expect them to be using unit tests what we haven't done yet is actually run this SQL against a database in memory or otherwise so what we going to do now is create an integration test and in this integration test we're going to actually run the SQL against an inmemory H2 database in postgress SQL mode so let's get started we're going to go down to test here open this up and I'm going to
142:00 - 142:30 put this test I think inside of the same directory as everything else and I'm going to call this author Dao impo integration test now the name of this particular class is important because if we did choose to go author Dao impul it capital it so if we were to call it something like this this is a convention that's used by the maven fail safe plugin so this will be an
142:30 - 143:00 integration test which once configured will run in that verify step we're not going to go through the effort of configuring that for the time being so I'm going to call it integration test which will be picked up by the maven Shire plugin which is the thing that just runs unit tests so orthod Dao impo integration tests great except for I typo there let's fix that there we go so we're going to set this up to be a spring boot test so it's
143:00 - 143:30 going to start up a test version of our application when the test runs and we're going to use the extends wi and we're going to use the spring extension class to make sure that everything is fully integrated and supported now let's write our test here so we are going to test that a author is created in the database using the create method and then we're going to use the find one method that we've implemented to retrieve that author once
143:30 - 144:00 it's been created so we're going to say public void test that author can be created and recalled great so we need an author we have already created a test author over in this test here there it is so we really want to be able to reuse that functionality if we can so I'm going to extract this Al into its own
144:00 - 144:30 method to begin with so we can go refactor extract method and we'll call this create test author this is a private static at the moment I'm going to move this into its own test data utility CL so we can reuse it and I'm going to put that at the root of here so I'm going to go new class and I'm going to call this one Testa util great a utility class usually
144:30 - 145:00 follows the pattern of being final we are not going to expose the default Constructor we don't want this class constructed at all so we're going to say desat util and it's not going to do anything and then we're going to have public static methods available on this class but I'm not going to create that manually instead I'm going to rely on our refactor tools for that so I'm going to right click here going to go refactor and then I'm going to go move members
145:00 - 145:30 and I want to move the member to we go test data util okay and then refactor great so if we now click to go to the class we can see it's a public static method and it's creating a test author that we can use in our tests so let's go ahead and use that in our test by going back to our intergation test and then creating an author so author call it author test data util do create test
145:30 - 146:00 author great that's all well and good we haven't actually got a reference to our class under test yet so let's get one of those so we'll go private author Dao impul and we'll call this one under test but that's not going to be enough to get a hold of it inside of our test so we're going to use Constructor injection for this so not going to type all that out I'm going to go public create a Constructor and the
146:00 - 146:30 Constructor is going to require an author Dao impul and then under test now we can do this because we are writing a spring boot test and an integration test and then we're going to say this dot under test equals under test there we go now in order for for the Constructor injection to work in this particular format we need to put The annotation autowired on top of this class this is actually the first time we've met Alo wide in this course
146:30 - 147:00 because everywhere that we've used Constructor injection in our main production code this is emitted nowadays you don't have to provide autowired providing you only have a single explicit Constructor like this but this of course is a test and they are required at least at the point of filming so we're going to put at alter wide on this and that's simply labels it tells spring that hey you should inject dependencies as declared in this Constructor or the Dao inut so we now have a reference to our under test so
147:00 - 147:30 let's write our test we're going to say under test dot create passing in our author which in theory should create an author in our database and then we're going to say under test. find one passing in the author ID author. get ID great and that's going to return a result which is an optional author now I'm going to assert that so this
147:30 - 148:00 particular assertion is assert J so I'm going to import assert J assertions do assert that this is a personal preference but I find it to be very readable and uh at least some really good failure messages as well when your test fail really informative so we're going to assert that the result is present that's to mean that it's not an optional. empty this does actually exist in the database and we're going to do a second assertion on here again we may want to do a separate test for a second assertion but I'd say
148:00 - 148:30 this is close enough that it warrants being in the same test so I'm going to say result do get returning the actual author that's inside of that optional and I'm going to say it's equal to the author has been created here so in theory this should pass if everything is working correctly now I do really like to see a failing test just to make sure that it is the case so I'm going to type in here 99 L passing in an
148:30 - 149:00 ID which should not exist in the database so let's run this and see a red test there we go Okay so we've got fail to resolve parameter author Dao inut okay it's because we haven't declared these as beans just yet so this is great this is exactly what we want in integration test for so let's go over to our autho imput and we're going to put at component on here that's run this test once
149:00 - 149:30 more okay so we have here expecting an optional to contain a value but it was empty there is our failing test so let's go back and change that to be the ID of the author as created get ID and now let's press play expecting a green test this time there we go everything seems to be working absolutely fine now this is equal to method of assert J is going to use the equals uh method that is on the
149:30 - 150:00 class now because we're using lumbo it's going to use every single uh instance variable on that class in order to determine if this class is equal to that class so we can feel very confident that the class as we have it created here has actually been saved in the database and recalled at least as far as we can be confident with an integration test of this type so we've done that for author now let's do it for book so we create a new class book Dao Ino integration
150:00 - 150:30 test it's a spring boot test we use the extends with passing in the spring extension class now let's get an reference to our class under test to begin with shall we so we say book Dao imple under test and we should be able to use the refactor tools to create or the generate tools to create our Constructor for us there we go let's put Auto wide on
150:30 - 151:00 top so we now have reference to that let's create our test public void test that book can be created and record okay so we need access to that book so as before in our unit test over here we do create a book right here so let's extract this out into its own method and
151:00 - 151:30 we'll call this one create test book and we'll refactor and move this over to the test data util which will also make it public as well there we go if go over to the test data util we can now have two classes one create test author One create test book very good so let's go back to our book Doo import integration test and let's get a book shall
151:30 - 152:00 we let's import our book then we'll go under test do create passing in our book and then under test dot find using the books ISBN here which of course we return an optional of type book which will say is result and then we'll assert that the result is present import SE J is
152:00 - 152:30 present and we'll assert that the result. getet is equal to the book as created great so as we did before let's just change this to be something that is absolutely not going to exist in the database and run our test making sure it's red as before we haven't got the book Doo inut as a bean so let's fix that
152:30 - 153:00 immediately at component run our test once more aha so we hit a foreign key constraint which again is fantastic that's something you get from integration test that you would never get from a unit test and it simply is the case because we have a foreign key constraint between book and author and our author doesn't exist so let's create our author shall we so we'll go back to our test here and we will now need
153:00 - 153:30 access to our author Dao so we're going to declare the author Dao interface and we're going to leave it up to the framework to determine what author Dao implementation we get because we're not testing author Doo impo specifically here we're testing the book Doo Ino so add this to our Constructor there we go we now have an author Dao available so we simply need to create our author so we're going to
153:30 - 154:00 as before create our author using test attil there's our test author now I'm going to save this author which I'm going to do by using the author Dao do create author that author now exists in the database so before we save our book we're going to set the author ID to be the author. get
154:00 - 154:30 ID great so now that author exists in the database the book references that author this should now pass in theory or at least fail but fail for the reason of uh being an optional empty because this ID doesn't exist there we go we've got an expecting optional to contain a value but it was empty so if we now make this the ISBN of the book that exists book. getet ISBN
154:30 - 155:00 click on play the test now passes absolutely fine we are able to create and recall the book so that was a really valuable integration test and picked up on a few bugs that we had in our production code well worth it so now let's move on to implementing our read many methods so we've got create endpoints and we've got a read one endpoint and we've tested those with unit test and now integration test I think it's about time to start implementing our read many endpoint so
155:00 - 155:30 it's going to be very similar to read one in a lot of ways and arguably even simpler so let's start out by going to our tests and again we'll start with author just like we've done before and let's start with our unit test here shall we so we're going to write a test here and this is going to be called public void test that find many uh generates the correct
155:30 - 156:00 SQL so we're going to say under test dot well doesn't exist yet but we're just going to say find doesn't take any arguments whatsoever let's create this cre in the interface and find is going to return not avoid but instead a list of authors great now we're going to
156:00 - 156:30 verify about the jdpc template using query again and this query is Select ID name and age from authors of course we need to use our EQ and we need to use our row mapper so we're going to go argument matches
156:30 - 157:00 any and then pass in the type of our author row mapper and let's put this on some new line so we can see it well great so there we go so this is essentially going to call find which is going to select ID name and age from authors and return all results in the database now you might not necessarily want to do this on a massive data set and things like pagination will
157:00 - 157:30 certainly help with that and we'll get on to that when we talk about uh jpa and hibernate but for the time being we're just going to return everything and we're going to use our author mappa as well so if we run this test we should get a failure because of course it doesn't do anything right now oh we haven't implemented in author da either so let's do that now by going to the implementing there we go at the very least this should
157:30 - 158:00 compile perfect let's run that test again then should get failing test great okay wanted but not invoked of course it wasn't so let's call the jdbc template War query passing in the SQL and again we're going to do a new author row mapper again we should probably do this as an instance variable on our class at some point but for the sake of these tests it should be absolutely fine we can get on to that when we start refactoring so if we now
158:00 - 158:30 return this that should be enough for our find endpoint that's looking good so let's now test this with an integration test now that we've unlocked that functionality so I'm going to go over here to the author Dao inut integration tests and we'll create a test and we're going to call this one public void test that multiple authors can be created and
158:30 - 159:00 recalled okay so we do have access to a single author here which is just like that but we don't have any other authors so we are going to Let's create those here I'm going to rename this to be create test author a I'm going to copy this method test author B test author C and I'll populate these with some
159:00 - 159:30 different information now there we go so we have Abigail Rose we have Thomas Cronin and we have Jessie a Casey so we've got some test authors to play with let's go back to our integration test and we'll name this one author a and we'll have an author B and an author C great so we have three authors now let's go ahead and create these authors in our
159:30 - 160:00 database there we go so we now have three authors in our database which allows us to do under test and then we can do find in order to get our result which is our list of authors and we're going to let's call that result we're going to assert that result has
160:00 - 160:30 size of three it's going to contain exactly three authors and let's assert that that the result contains and we'll say author a author B and author C now we can put this all on one line actually so rather than doing two asserts we can do one assert and chain them and that's the
160:30 - 161:00 magic of assert J so we can do something like that okay so let's see if this passes or fails okay we can see it passes absolutely fine so we've got three authors created and then we're able to return the authors so if we were to say I don't know has size two we get a failing test because of
161:00 - 161:30 course we get three authors returned and not two now what happens if we run the entire class in fact just for the sake of argument let's just make this green first good so we can see it passes by itself let's see what happens when we run the entire class we can see it fails and we can see it fails because of something called test pollution so if we look at the error message here we can see that we get a duplicate key exception so we are
161:30 - 162:00 creating test author a up here in this test and then in the second test we're creating test author a again so actually there test pollution in the sense that the author created here is already in the database before this test runs and we don't want that we want a fresh database every single test and you can do this with the dirties context annotation so the dirties context annotation will clean down the context so clean down any changes that you've made to the context including the database well depending on when you tell
162:00 - 162:30 it to before each test after each test at the beginning of the class and we can decide that by saying the class mode and you get some options here and I'm going to suggest we select after each test method so after every single test is run clean down the context ready for the next test to run so it's all fresh so if we run our test again we can see that they pass absolutely fine so then let's move on to implementing the book
162:30 - 163:00 Dao so we'll say at test public void test that find generates correct SQL under test do find or it appears that we have some
163:00 - 163:30 inaccuracies with the names um so we're going to refactor the base method changing that to be find one meaning that we have find here and that would be consistent with the author Dao now then let's create the method find on the book Dao here find returning a list of books Let's create that method on the
163:30 - 164:00 implementing class returning null for the time being going back to our test and then we're going to verify that the jdpc template is called with query and the query is going to be select ISBN title author ID from books and of course we have our argument matcher whoops do
164:00 - 164:30 any and we need to declare our row mapper which is going to be our book row mapper and it's easy as that so let's run this expecting a failure because of course we haven't implemented this yet oh we haven't wrapped in EQ let's do that now great okay so wanted but not invoked perfect so let's go ahead and implement this then so we go to find and we're going to say jdbc template.
164:30 - 165:00 query fact will just borrow the SQL from this test here we'll create our book row mapper again suggesting that we make that an instance variable at some point so we have a a failing test that's run again and hopefully this will go green looking good our unit tests are passing so the SQL is being passed via the jdbc template as expected so let's
165:00 - 165:30 go over to our book Dao integration tests and as before let's create a test public void test that multiple books can be created and recorded and we'll need access to our multiple books now we're going to make all of these books belong to a single author so we're going to take this line from up here creating our author in our database
165:30 - 166:00 and then of course we'll create our book which is can be done via the test data util do create test book let's go over to the test datail so create test book call that create testbook a and as before we're going to create testbook B and testbook C let me populate this data and then
166:00 - 166:30 we'll move on so there we go we have testbook a testbook b and test Book C so let's go back to our test and we'll create these test books and let's set the author ID on each of them and we'll create each of these
166:30 - 167:00 books in the database great so we now have three books in the database so we're going to go under test do find and that will return our list of books which we're going to call our
167:00 - 167:30 result and then we're going to assert that the result has size three because it's going to be three books and as before we're going to say it contains exactly book A book b and Book C so let's run this
167:30 - 168:00 test and we can see it passes fine let's just confirm that by changing that to has size two great and that goes red because of course it's three books being returned all belonging to that author with id1 so that's very good now let's run this entire class and I imagine we're also going to have some failures as a result of the context being dirty so let's figure that
168:00 - 168:30 out okay so we're going to do at dirties context and again we're going to go for the class mode of after each test method let's run them all once more looking good but I am going to open up the terminal here and then call Maven from the command line to be sure there aren't any other issues so I'm going to do Maven clean and then
168:30 - 169:00 verify build success all of our tests are passing looking good so we now have a create method a find one and a find many implemented in our Dao style I think it's time we moved on to the update method so we're going to pick up a pace a little bit now because you're probably starting to understand what we're doing let's implement then our update method shall we and we'll start with our author so we'll go over to the author do import test here we going to create a new test public void test that
169:00 - 169:30 update generates the correct SQL now we're going to go for a full update rather than a partial update we'll come on to partial updates when we talk about again hibernate and jpa so we're going to say under test do update and that's going to require an author so we need an author let's get a hold of one so update doesn't exist so let's create
169:30 - 170:00 that it's going to be a void but it is going to take an author let's go down to the implementing method let's create that okay so it's not going to do anything for the time being so let verify that the jdpc template and we're going to use update for this one and we're going to say update authors then we're going to say set ID
170:00 - 170:30 equal to question mark name equal to question mark and age equal to question mark where ID equals question mark and now for the objects so we have our author here the first question mark is going to be the author's ID which we know to be one in fact just take a look at that author once
170:30 - 171:00 more IDE of one name is Abigail Rose and the age of 80 so IDE is one name is Abigail Rose and the age is going to be 80 and then the ID of course at the end here is going to be one again again so if we run this method we can see it's wanted but not invoked so I'm going to borrow the SQL right here and we'll go over to the under test. update and we're going to go
171:00 - 171:30 jdbc template do update passing in our SQL query and then we're going to go for author. get ID author. get name author. get age and of course that ID once more if we run our test we can see it passes absolutely fine and this would be a valid method what I like to do is explicitly declare
171:30 - 172:00 the ID as an argument to this method and then that allows you to change IDs so I'm going to go for long ID then we'll go to the implementing method do the same here and now we'll make that ID which allows us to update the IDS of authors if we so choose we do need to update our test however so let's go back to there we are just going to use orthod
172:00 - 172:30 doy ID after we run the test once more now pass is absolutely fine but just be on the safe side let's go for three there we go there we go having a different ID in there is just a better test in this case so that is the unit test for our author let's create an integration test test
172:30 - 173:00 that author can be updated so of course we need to start with an author so let's create an author here so we have an author created in the database author a now I am going to go ahead here and I'm going to update author a and I'm going to set the name to be updated and then we're going to go under test. update author
173:00 - 173:30 A.G ID passing in author a which is been updated to have the name updated and uh we're going to go under test do find one using the author A.G ID and then that's going to be our result now we're going to assert that the result is present and let's assert that the
173:30 - 174:00 result. getet is equal to author a which of course has been updated to have the name updated so let's run this test and see what we get great it looks like our update is working absolutely fine so let's move on to our book now so create test public void test that update generate the
174:00 - 174:30 correct SQL we're going to go under test do update which of course doesn't exist but we'll pass in a book test book a let's pass that in there let's create this method over on our book Dao whoops of course it's the ISBN
174:30 - 175:00 that's needed for this book not the ID so it won't be a long it will be a string and there's the book for the update so let's go down to the implementing class create this method here and uh we'll just leave it at that for the time being let's go back to our test let's go verify that the jdbc template is called
175:00 - 175:30 with update and of course we're going to go for update books set ISBN equal to a question mark title equal to a question mark and author ID equals to the question mark where ISBN is equal to your ISBN provided run this test there we go wanted but not invoked
175:30 - 176:00 so let's Implement our method but let's just borrow the SQL jdpc template. update passing in our SQL there and now we need our arguments so we're going to go book. get ISBN book. getet title book doget author ID and then we're going to pass in the ISBN from the arguments of the method
176:00 - 176:30 there so let's run our test again arguments wanted but were different uh ISBN title author ID ISBN oh may have rushed that one a little bit so we just need to populate this with the of course go to testbook a there's our rbn the first one the title is the shadow in the attic and the author ID of course is one
176:30 - 177:00 and the ISBN just happens to be the same for this one so we're going to just put that there there we go Rush that one so let's play that test once more that's a bit better it's now passing so let's go ahead and write our integration test with this test public void test that book can be
177:00 - 177:30 updated so we're going to need an author to begin with so let's grab one of those from up here and now we're going to need to create a book which actually is already been done for us here so let's borrow that so we now have a book created in our database let's go ahead and update that so we're going to say book a do set title to be updated and I'm going to go under test update bouet get ISBN and then we're
177:30 - 178:00 going to pass in the updated bouet which of course has the title of updated that should update and then when we do a find one so under test do find one passing in the ISBN from book a that's going to return a result which is an optional of book and then we can assert that the result is
178:00 - 178:30 present and then we can assert that the result. getet which will return a book is equal to book a which is being updated with the title up updated so let's run this test and see what we get and there we go passing absolutely fine so we now have a update method for both our book Deo and our author Doo so of the crud acronym we have the C we have
178:30 - 179:00 the r we have the U Now we move on to the D which is delete so let's Implement that delete method now okay so let's now Implement our delete method so we're going to start over on our author here so let's go to our tests and we're going to write a new test and we're going to say public void test that delete generates the correct
179:00 - 179:30 SQL great now we'll call under test. delete and it's going to take an ID which in this case can be 1 L this method of course does not exist let's Creator void delete that's absolutely fine let's go down to the implementing method and create it there as well but
179:30 - 180:00 not doing anything no implementation verify jdbc template do update and our SQL query here is going to be delete from authors where ID is equal to question mark and of course we're going to pass in the ID as our argument which is 1 L let's run this test and see a failure there we go wanted but not inote
180:00 - 180:30 so let's now implement this okay let's run this once more and we have a passing test so let's now create an integration test for this at test public void test that author can be deleted so let us create an author in
180:30 - 181:00 the database and then we're going to go under test. delete using author A's ID and now we're going to go under test do find one again using author A's ID this will return a result if the author doesn't exist that will be an optional empty so we're going to assert that our
181:00 - 181:30 result do is empty great so if we now run this test we can see it passes absolutely fine we are deleting that author if we were to comment out the delete for the time being we should expect this to fail because of course the author should still exist there we go looking good to me so that is the author side of things done let's now do the book side of things
181:30 - 182:00 shall we so let's go over to the book Doo import tests at test public void test that book delete generates correct C equal so we're going to go under test do delete and then it's going to take an ISBN in this case so let's grab an IBN from up here this method doesn't exist
182:00 - 182:30 let's create it great let's go to the implementing class we won't do anything but let's go to the test now verify that the jdpc template is called with update and the query of delete from books where ISBN is equal to question mark and of course we'll expect
182:30 - 183:00 the ISBN to be an argument in there as well let's run this test and expect a failure looking good wanted but not a voked so we're going to borrow this go over to our delete and and then we're going to implement this with jdbc template do update passing in our query and then the ISBN great let's run this test once
183:00 - 183:30 more it's all green perfect stuff so let's go over and do an integration test for this at test public void test that book can be deleted so we're going to need an author because all books that we create in the database need an author and then we're going to create a book so we're going to borrow this from up here we could potentially extract this out into private Methods at
183:30 - 184:00 some point when we're factoring but we now have a book in our database let us call under test. delete using the ISBN from book a that should delete our book for us so if we now do a find one using book A's ISBN we should find that the result from this is now empty so we're going to go result dot is empty oh we need to of
184:00 - 184:30 course assert that otherwise it's not going to amount to much there we go I am going to comment out the actual delete for the time being so I want to see a failing test first okay and now if we uncomment that we see that it's passed absolutely fine and this is a great time for us to
184:30 - 185:00 rerun Maven clean verify everything's passing absolutely fine so we've now implemented daos with crud Behavior create read update and delete for authors and for books where an author and a book are related in the sense that an author can write many books but a book will always have one author I think we can appreciate this was a lot of work there must be an easier way to do this I mean of course this gives us access to really tweak
185:00 - 185:30 those SQL queries but you can see a lot of those queries we were using were very very basic is there a is there a better way is there an easier way yes there is and that's by using jpa and hibernate let me show you how that works now so we've made use of the jdbc template to build daos for the author and the book we've done it completely from scratch ourselves and it was a lot of work is there a better way yes there is and it's by using spring data jpa and hibernate this is a higher level API and
185:30 - 186:00 it takes care of a lot of the lowlevel details for you for example we're not even going to be touching Alina SQL when we deal with this module now the best way to demonstrate this the differences between a plain jdbc template approach and then going the fullblown spring data jpa approach is to build on the project from the last module so you're going to be using exactly the same domain of books and authors whereby a book has one author but an author can have multiple
186:00 - 186:30 books but we're going to take the code that we've written with our daos we're going to strip out the bits that we don't need and then we're going to place in all of the bits that we do need in order to implement a spring data jpa implementation of the standard create read update delete functionality in our persistence layer so here we have our project from where we implemented our daos and the first thing we're going to do is delete our schema.sql file so this was used to set up the database structure and we no longer need that
186:30 - 187:00 hibernate is going to take care of it for us let's delete that now let's go over to our daos so if we take a look here we've got our book Dao and author Dao and this is where we're exposing the create read update and delete functionality for the book and the author respectively we no longer need these so we're going to get rid of those and the implementing classes as well in fact let's just delete the whole Dao directory because all of the SQL is going to be generated for us now we'll keep the domain but we'll
187:00 - 187:30 tweak those in future and the database config with the jdbc template in there we no longer need that jdbc template so we're going to go ahead and delete that we may bring that config directory back later yep keeping the domain objects so let's go down to the test here now I'm going going to delete the unit test that we had before but I'm going to create here a new package and I'm going to call this package repositories more and why I've done that
187:30 - 188:00 later and I'm going to take the integration tests and I'm going to place those into the repositories package that may seem mysterious but you'll see why I've done that but what I am going to do is delete the Dao package I'm going to comment these out for the time being there we go so we don't have to worry about those not compiling because of course the uh deos have been deleted the database application test just does context loads can keep that and the test data util that has all of our lovely
188:00 - 188:30 test data in there let's keep that as well so as far as it goes we have some commented out tests we have our configuration for connecting to a postest SQL data base inside of our production codee inside of our test code here we're connecting to an inmemory H2 database which is in postgress SQL mode and in terms of our production code we have a domain and we have our entry point and not a lot else so let's kick things off by going
188:30 - 189:00 over to the pom.xml here and where we've got spring boot starter jdbc I'm going to change that to Spring boot starter data jpa and we'll go over to the little tab on the right hand side here and we'll refresh so we'll refresh Maven in intell here so just like that we have all of the dependencies that we need in order to use spring data jpa which is great because we can now create our repositories in production so we're going to do just that so we're going to
189:00 - 189:30 create the repositories directory and I'm going to create two interfaces here I'm going to create one which is going to be the author repository was interface not a class and I'm going to create another which is going to be the Book Repository there we go we're not going
189:30 - 190:00 to do any implementation on these at the moment we're just going to leave them as blank interfaces so the next step for us is to get started by updating our domain objects to become entities so let's get on to that right now so let's get started by modeling our domain as entities so this is what we've got we've got books we've got authors we are very familiar with these objects by now so let's flip over to our code so we've got these plain old Java objects pojos left over from our Dao
190:00 - 190:30 implementation we got one here which is an author and the other one which is a book so what do we need to do in order to change these pojos into entity so that we can use them with spring data jpa and hibernate well it's actually very straightforward and most of it is annotations so let's get started the perhaps most important one is we need to put a annotation on here which is at entity and this simply labels this object as an entity that can
190:30 - 191:00 be used with spring data jpa so that's step one now we need to say which table this maps to in the database and we are going to map this to the author's table name equals authors perfect so now we need to identify which field in here is going to be our ID our unique identifier and of course it's for the author going to be ID so we can use at ID in order to identify
191:00 - 191:30 that there we go now we have a choice to make we can either Define the ID of the author every single time when we're creating a new author we create a new ID ourselves or we can leave up to the database by using a sequence so the sequence will start at one and then when an author is created it will increment two so the next author's idea will be two the next one will be 3 4 5 6 so on so forth and the way that we would do that is by using The annotation generated value and we'll say strategy
191:30 - 192:00 here is sequence and then we give the generator a name which we're going to say is author ID sequence and just like that every time we create an author the database will create a new ID for us incrementing by one when we don't provide one ourselves so that is all we need to do in order to convert the author pojo into an author entity so let's now take a look at the book so here is our book pojo Let's
192:00 - 192:30 convert this into an entity so we'll add the at entity annotation on the top there and we'll add the at table annotation mapping this the table of books we'll now need to identify the unique identifier the ID so add the ID annotation to the string BN private instance variable here now we're going to make a design decision and the design decision is that we want to provide the ISBN every time we create a book we're not going to use a uh generated sequence or anything like that we're just going to provide it now the title we don't
192:30 - 193:00 need to do anything to but this field this field can be updated so this is the author ID field which is of type long which we use to store the ID which reference the author of this book now because we're using spring data jpa we can actually use the author object here so we're going to say author and we're going to change the name to be author and we can add some annotations to this private instance variable to make it so that we can deal with the book and its related author so we could retrieve a
193:00 - 193:30 book and also retrieve its related author object so first we need to tell spring what the relationship between these objects are and you can see here there is a many to one relationship so we're going to say at many to one on the top here so when I Define a a relationship like this I usually like to define the cascad as well and we're going to say Cascade all so what this means is if we get a book back we also retrieve the author and if we were to
193:30 - 194:00 take that author that's on the book make some changes to it those changes would then also be saved into the database so all changes everything that you do to the author retrieve via the book would then be persisted in the database so that's our many to one annotation and now we need to specify what the join column is we can do that with the join column annotation here and the join column annotation was of course author ID which we know from our Dao experience and just like that we converted our
194:00 - 194:30 author and book pojos into entities now when we were creating these we were adding a lot of information such as names of sequences in terms of the author here and we were also adding information on the book like this which is the join column but we have removed the schema.sql file so how on Earth are we going to create all of the relevant structure in the database in order for the information that we've put on these classes to be correct well hibernate can do it for you so let me show you
194:30 - 195:00 hibernate Auto ddl so hybernate can set up your database schema for you and how you enable this is really straightforward but to show you how it works we're going to need a database first so we do have this Docker composed file in the root of our project and it starts at postrest database so let's do a docker PS to see what's running we have nothing running so we're going to do Docker hyphen compose and then up and this is going to start our postgress database database system is ready to accept connections it's looking good so
195:00 - 195:30 I'm now going to connect this using D Beaver so I can show you the database structure visually no surprises it's going to be empty but let's take a look so here we are in De Beaver I'm going to create a new connection up here in the top left I'm going to select post press SQL next it's on local post the database is called postgress the username is postgress and the password is change me in prod exclamation mark let's test that connection connected looking good click on finish here so now if we go into the
195:30 - 196:00 databases into the post Christ database look at the schemas the public schema look at those tables there are no tables it's completely empty exactly what we'd expect so now that we have that set point let's have hibernate create our structure for us so let's go back to our code so like a lot of things in spring boo you can enable this feature in your properties file so if we open that up now we're not going to need spring. SQL init mode anymore we're going to need a new key for this so let's go over to the documentation in our browser and figure out which key we need so if we take a
196:00 - 196:30 look here we've got the key that we need which is spring. jpa hybernate doddl hyen auto so I'm going to copy this you can see a description of what this does here but essentially if we set this to the right value then hibernate is going to set up our database scheme schemer for us now the value I happen to know that we want to use here is update you can see that there's things like create drop and none and obviously each of these has its place but we want our schema updated when we change our entities obviously be very careful with
196:30 - 197:00 this in production so let's go back to our code now add this key and I'm going to type update as its value so remembering that our database is completely empty if we run our application we should expect now that hibernate is going to create our schema for us by using using the entities we can't expect the application to do too much but it's certainly going to create the entities for us so let's start the
197:00 - 197:30 application okay so it's exited it's connected to the database very good okay great so let's take a look at the database in Deb okay and I'm going to write click on tables and I'm going to go to refresh cool so we have both the author's table and the book books table now available so we can see here that we've got ID age and name on our authors and we have ISBN title and author ID on our books so hibernate has been so kind to create these tables for us if we take
197:30 - 198:00 a look at the sequences there's our author ID sequence so we should expect to get a new ID every time we create an author as well so that's looking pretty good but we don't have any functionality and our application that makes use of all this power just yet so let's get back to our repositories and start implementing our create endpoint so we have some entities and we have managed to use hibernate to initialize the schema in our postgress database but we don't actually have any functionality in our application just yet and we want to
198:00 - 198:30 start with a create method so where do we go for that well we've got our repositories that we've created already one for author one for book so if we open up the author one I think this is where we'll start now this is an interface and the wonderful thing about spring data jpa is you don't actually have to Prov provide an implementation for the interface it does it for you providing you extend the correct repository interface if that doesn't make sense stick with me so if we were to go into our author repository here
198:30 - 199:00 and say extends crud repository and we're dealing with an author here and the author's ID type let's just import that and the author's ID type is a long you wouldn't believe the amount of functionality we've just unlocked there is a missing piece of the puzzle however and that is the at repository interface here so at repository is very similar to at component does pretty much the same
199:00 - 199:30 thing but of course it describes this as a repository so the author repository is now a bean that can be injected anywhere that's needed so how do we test this typically you wouldn't test a repository because this has all been generated for you but we're going to to demonstrate this so we go down here to our tests we go into our repositories we've got those two leftover classes that we had from earlier so this is exactly why we've kept them so you go into the author Dao integration test here the first thing
199:30 - 200:00 I'm going to do is I'm going to re well actually I'm going to uncomment this code and I'm going to rename this to be the author repository in integration tests there we go and the class that we have under test is no longer the orthod Dao input it is the author repository and we just need to change our Constructor
200:00 - 200:30 here great so I am going to go ahead and comment out all of the methods that don't relate to creating here so we do have this method which is test that an author can be created and record sounds pretty good so we've got our under test here and we're calling create but that method doesn't exist well what if I was to tell you that actually it does and on Spring data jpa it's called save and actually we've got here under
200:30 - 201:00 test. find one but on Spring data jpa we can go find by ID and you'll see that this entire test is compiled absolutely fine so if we take a look at these individual methods here for example let's go to save to to begin with you can see exist on the crud repository here which extends repository this is the base repository and then we've got some basic crud behaviors in here including save save all that find by ID that we were using a moment ago find all
201:00 - 201:30 count delete so this is the basic crud stuff that we had before but of course we don't have to do any of the lowlevel work as we did with the Dao so if we were to run this test I wonder what would happen okay so it can't find the author ID yeah that would that would totally make sense so we are going to pass in the author instead and then we'll have that passed in instead of the author ID
201:30 - 202:00 because this is how we changed our book entity wasn't it so let's do that let's go back to our test and let's compile this okay that's compile fine let's try running this test again now you'll see that it passed absolutely fine and we didn't write a line of syall we were able to create an author and then recall it from the database pretty
202:00 - 202:30 cool right so let's do the same for our Book Repository now so we go over to Book Repository we're going to add the at repository annotation on the top we're going to extend here the crud repository and with we're dealing with a book in this case and the ID type of the book is a string because it's our ISBN so let's import book and we have a Book Repository at least with basic crud functionality so let's go over to the book Dao inut
202:30 - 203:00 integration tests on comment this and we'll need to do a few changes over here starting with the name so let's change this to be Book Repository integration tests and now we're injecting a few things so let's start with the Book Repository and call that under test and let's not bother with the author Dao let's remove it from The Constructor as well we are going to change the type in the
203:00 - 203:30 Constructor to be a Book Repository which makes that compile fine and then we have our test book can be created and recalled so let's comment out everything here and we'll see that we've got an author that's great do we need to create the author manually no we don't because we have our Cascade set up so let me show you how they work so we do need to pass in the author to the book because we've updated our utility method here for creating a testbook don't need to worry about any of that because we don't
203:30 - 204:00 need to set an ID on the book we've just set the author on the book we know that we're not using a create method in Spring data jpa we are using a save method however and we know that we're not using a find one we're using a find by ID everything else remains absolutely fine so for this to pass we should expect for the author to be created in the database in addition to the book let's see what happens let's fix those Imports
204:00 - 204:30 compile looking good let's run this and it passes absolutely fine now just to demonstrate so if we were to go over to the book here and then remove the Cascade type from The annotation here and then rerun the test you can see that the test fails because we're not cascading to the author we can't save the author there so we're unable to find the author with the
204:30 - 205:00 ID of one put it back and spring data jpa handles creating that author because it's a brand new author with a brand new ID and everything works just like that so not only have we implemented the create endpoint with no SQL whatsoever F we've also created the read one endpoint so I think what we need to do now is deal with the rest of the crud acronyms so we're going to do the read menu the update and the delete starting with the read menu so we've got our create method and
205:00 - 205:30 we've got our read one method what about our read menu well we happen to have an integration test for that before so let's go over to the author repository integration tests and we can see we have this one right here and we are creating test author a test author B and then test author C so if we were to save these we have three authors here and instead of find to return the list of all authors we are going to go find all
205:30 - 206:00 that's returning a iterable rather than a list but we can make that work and then we can assert that the result has size three and contains exactly author a b and c so if we play this test we can see that we also got the find all functionality for free with our crud repository which is pretty cool what about the Book Repository let's go over there and let's uncomment this
206:00 - 206:30 test and make the same update so we do need an author we don't need to create it don't need to set the author ID we do need to pass the author in to the care create testbook a b and c methods we can remove setting the author ID and instead of create we are going to call
206:30 - 207:00 Save instead of find we're going to call find all and that returns an iterable okay so if we now click play here we find that we do get this find all functionality for free on the book as well while we're here we might as well just update the remaining tests let's update the update methods so let's uncomment the update method on the author
207:00 - 207:30 here rather than create we're simply going to go save going to go save rather than update but with author a like that and then we're going to go find by ID so save is used for both creating and updating in Spring data jpa so essentially what we're doing here is we're creating an author we're saving that author we're updating the author with a brand new name updated in this case we're resaving it and then we're
207:30 - 208:00 finding by ID or using the author's ID and we're asserting that the result is present so asserting that we did find an author and then we're making sure that the author matches or the result matches are author a with our updated name so we run this it passes just like on our Dao so if we go over to the Book Repository and do exactly the same thing
208:00 - 208:30 here so we do need an author pass that in it's when we create bouet don't need to set the author ID we're going to call Save and save once more and then find by ID of course we don't need to pass in the isbm for this method it gets it from the object there we go so let's click on run looking good that's working absolutely fine let's move on to our
208:30 - 209:00 delete methods so the last of the C functionality of course is the delete so we're in the author repository integration test here let's uncomment this and uh we're creating an author so that we may delete it so we've got several options here we can either delete passing in the author entity or we can delete by ID delete by ID is probably the most similar to what we were doing before so let's go author A.G
209:00 - 209:30 ID and it's not find one that we're using of course it's find by ID so if we run this test we can see that it passes absolutely fine let's do the same for the book uncomment this we don't need to create our author because we're going to pass it in to our test till here and then via a Cascade we're going to have that Crea for us let's go
209:30 - 210:00 save and then we're going to delete by ID and then we're going to pass in the ISBN instead of find one we're going to find by ID and we're going to run our test and it passes absolutely fine so we have create read update and delete functionality and we've tested it via our integration tests if we go down here and we run our Maven rapper clean and verify let's make sure everything's working
210:00 - 210:30 fine we have a build success all of our tests have passed so just like that we have implemented exactly the same functionality that we did with our daos writing all of our SQL queries manually with what seems to be under 10 lines most of them being Imports so we have a repository for our authors here and we have a repository for our books and we have for create read update and delete functionality with all of the SQL being generated for us by Spring data jpa now
210:30 - 211:00 this only scratches the surface of what's possible with spring data jpa so let me show you how to do a more complex query so spring data jpa does a lot of hard work for us and one thing which I find really impressive is the way that you can create queries just by naming a method inside of a repository so to demonstrate this we're going to need a test I think so let's go down to our test or our integration test and we're going to create this one in the author
211:00 - 211:30 repository integration tests we're not going to bother with the book for this one just the author so we go at test public void test that um get authors with age less than and for this we're going to need some authors so let's get test data util create author a let's assign that to a variable we'll do the same for test data till get author
211:30 - 212:00 B assign that to a variable and the same for C assigning that to a variable so we have three authors let's take a look at the implementations of these methods so we can see we've got Abigail Rose age of 80 we've got Thomas Cronin age 44 and then we have Jesse a casy age 24 so if we wanted to let's say get all of the authors with an age under 50 we
212:00 - 212:30 would expect to get test author B test author C but not test author a because Abigail Rose's age is over 50 so how would we go about doing this well first things first we need to save these into the database so we go test author a the same for B and the same for C so we have three of those authors saved in the database now we're going to say under test and we're going to say age
212:30 - 213:00 less than which is a method that doesn't exist and we're going to say 50 and we expect this to return an iterable of author because that's what things like find all Returns on the quad repository and we'll call this results or just result and we're going to assert that the
213:00 - 213:30 result contains exactly author B and test author c not a b there we go test author B test author C and no others but this method doesn't exist so let's create it which we'll do with create methods it's going to return iterable of author and this is going to be an in and it's going to be the age and we're not going to provide an implementation just this so let's run
213:30 - 214:00 this test and see what happens well it passes because spring data jpa has been clever enough to figure out that it can provide an implementation to this method because age less than the name of the method it's able to take a look at the author see that it has an age instance variable and then it's able to work out what that query should be when you pass in an argument to that method so we can see here that we got a passing test and we
214:00 - 214:30 get test author B and test author C just to prove that it does actually work if I change that to be test author a which of course is Abigail Rose age of 80 we should expect this to fail and just like that it does because we've got Thomas Cronin and Jesse a Casey returned and we're expecting our Bel Rose which of course isn't going to be the case really very clever spring dat's jpa is able to work out custom queries based on just how you name your methods in your
214:30 - 215:00 interfaces so spring data jpa being able to work out the implementation to work out the SQL for a query just based on what we named the method is really very cool but as you can imagine it has its limits and sometimes you have to kind of give it a bit of a hint on what the query should be and that doesn't necessarily mean writing SQL but it might mean writing hql so let me show you how to use the query annotation inside of spring data jpa so let's say for example we wanted to have a method
215:00 - 215:30 which done something a little bit similar to authors with age less than let's say we wanted to have an the opposite of that in fact um let's write a new test here and go public void test that git authors with age greater than Returns the correct authors I suppose so we're going to take exactly the same approach create three authors in the
215:30 - 216:00 database and we're going to go under test Dot and we're going to create a method now now I'm on purpose going to create a method name that spring data jpa won't be able to work out so we're going to call it find authors with age greater than and then we'll pass in the age which in this case we say 50 which of course will be the inverse of the last test so we should only expect to get
216:00 - 216:30 test author aack Abigail Rose we'll assign that to a variable which is going to be iterable of uh author and we'll call this one result and then we will assert that the result contains exactly test author a and no other now let's create this method in the repository here and we'll call this one H so if we
216:30 - 217:00 run this test we should expect it to fail because spring data jpa doesn't really know what to do with this method name there we go so we've got big stack trace and it's saying along the lines of no property find authors with age for type author of course there's not so what are we going to do let's go over to the implementation so let's go to find authors with age greater than we're
217:00 - 217:30 going to add an annotation which is going to be at query and inside of the query annotation we're going to add our query and now this isn't going to be SQL but hql so it's going to be a little bit different so we're going to say select a from authors or author being the Java object type A where a Doh is greater than the parameter the first parameter question mark one that
217:30 - 218:00 we have provided so if we were to play this test now we can see that everything passes absolutely fine so we've not had to write any SQL actually spring data jpa would still work out the SQL for you but if you find you can't do a simple query such as age less than and you do need to add some query in there using hql you would do so by using the at query annotation so that wraps it up for spring data jpa so we should have a
218:00 - 218:30 pretty good handle on the persistence layer by now so let's move on to creating a fullblown rest API a full project from beginning to end but before we do that we need to understand a little bit about Jason and Jackson so let's let's cover that now Jackson is a super popular library for dealing with Jason in the Java programming language and it just so happens to integrate so well with the spring framework now at its core Jackson is there to take a Java object and turn
218:30 - 219:00 it into Json through a process called marshalling and then do the opposite take some Json and then take the information and put it into a Java object in a process called unmarshaling so to start we're going to explore how spring web uses Jackson something we'll need to know to implement our rest API and then we're going to explore the Jackson object mappa in a little bit more detail so let's start with spring web so let's go over how spring web uses Jackson with an example so we have here
219:00 - 219:30 a very basic web project take a look at the dependencies we have the spring boot starter web we have lombok and not a lot else so what do we have we have a book controller we're going to get into controllers a little bit more in a moment but this is similar to how we saw in our quick start application so this exposes two endpoints a HTTP get endpoint on for/ books which is returning a book object we can see and then we have a post mapping again also at/ books and this expects a book object
219:30 - 220:00 so you can see here we've got a book object named book as an argument to the create book method which is then got that post mapping annotation and all this simply does is it's going to do a log doino with the book book and then just return that same book again as Jason so let's take a look at the book this is a very basic ISBN title author and year published in this case that is our book but that's it that is exactly
220:00 - 220:30 it so let's start our application and then we'll hit it inside of Postman okay so our application is up and running let me show you Postman so Postman is a client for rest apis graphql apis and a few other things as well but we're going to use it to hit the rest API so you can see here we're using the HTTP get method we're hitting Local Host at880 which is where our application is running and we're hitting forward SL books so if we click on send
220:30 - 221:00 here we can see that we've got adjacent object back the ISBN title the Enigma of Eternity author ARA montgomary and the year published of 2005 this is our book object but if you remember we're not returning a Json object we're returning a book object from the method here but spring web is able to use Jackson to convert that into adjacent object which is what we see
221:00 - 221:30 right here so that's our get method what about our post method well let's take this same object shall we let's change the HTTP get to a post and now we're going to go into our body we are going to send a raw body a somebody and let's paste in that same book maybe with the number two after it just to show that we've got something a little bit different and if we send this we can see that it's returned exactly the same thing the Enigma of Eternity 2 by Arya Montgomery if we I
221:30 - 222:00 don't know arya's middle name is also Arya so if we send that there we can see Arya Arya Montgomery so what's happening here is this Json object is being sent to our server it's being converted into to a Java object from a Jason object and then it's being converted from a Java object back to a Jason object and then return to us the caller so if we look at the code we can see that yes we we're expecting a Java object here and and
222:00 - 222:30 we're printing out a book I mean there it is on our uh on our logs but then we're returning a book object so seamlessly spring web is working with Jackson to convert to and from Jason and Java objects and if we just double check that book object once more there's nothing special happening on here so let's look to understand Jackson in a little bit more detail and hopefully all of this should become clear so we've seen how things were done in Spring web but let's see how to use the Jackson object mapper directly and
222:30 - 223:00 we're going to do that via a test here so we can see that we've got the code as it was before we still have the controllers there and we have the book objects now what I'm going to do is I'm going to create a test and I'm going to call that test Jack tests this is going to be a straightforward unit test I don't need to do anything too special in here and I'm going to create a test I'm going to call this one public void test that object mapper can create Json from an
223:00 - 223:30 object now this isn't a proper test we're not actually testing anything but I am going to be able to demonstrate to you how to use the Jackson object mapper by doing this so first things first we need a Jackson object mapper so let's get an object mapper let's call it object mapper equals new object mapper we have a Jackson object mapper now so we can convert to and from java objects and Json objects so we want a Java
223:30 - 224:00 object because we want to create some Json from a Java object in fact let's update that test name to be Java object let's use that book so we're going to say book let's call it book Let's import that and let's create this book which I happen to have here so we now have a book available the Enigma of Eternity ARA Montgomery great so how do we convert this into Json well it's pretty simple we go object mapper do WR value
224:00 - 224:30 is string pass in the book and we will get a result now right value a string you can see it's got a red underline and the reason for that is it throws a Json processing exception so sake of the test add that to the uh signature of our test here so we can see that we've got Json processing exception so in the case that is unable to convert the object into Json you will get a Json processing
224:30 - 225:00 exception thrown however in the case that it is able to do it we'll get this result back here and we're going to say assert that result let's import assert that is equal to and then we'll just do a string that's is it is absolutely not going to equal to begin with and let's play this test to see what we get back there we go so it's expected this
225:00 - 225:30 smiley face but actually it was a Json object that looks a little bit like this and this is exactly what we would expect that Java object to look like in Jason now this isn't a proper test but if we were to put that in there and then click play should get a green test so really to convert a Java object into adjacent object it's as simple as calling objectmapper WR value as string so we've managed to convert a Java object into ajacent object but what about the opposite how do we convert
225:30 - 226:00 ajason object into a Java object well again it's pretty simple with the object mapper let's create a new test so I can show you it and we'll call this one public void test that object mapper can create Java object from Jason object okay so we're going to need a Json object to begin with so let's say a string and let's just call this one Json
226:00 - 226:30 and we're going to take this even though it's a little bit ugly we'll take this string from up here and we'll dump it straight into that variable great so we now got some Json to play around with and we know it represents a book we want a book so we're going to say book and we'll call this one our result is equal to well we're going to need an object mapper to begin with so let's create an object mapper we can do this if this a proper test as's an instance variable in the class we're not going to object mapper object mapper
226:30 - 227:00 equals new object mapper there we go and now we're going to say object mapper dot read value and we're going to pass an adjacent as the first value and the second value is going to be the class we want to read this as which in this case is going to be book. class you can see we've as before we've got that red underlined squiggle because we haven't handled the Json processing up section so we're going to add that to our method signature there obviously in production
227:00 - 227:30 code you'd want to handle that because it's more likely that you won't be able to turn a bit of Json into a Java object rather than the reverse and now let's do our assert that result in fact why not let's just take this book from up here because we know it matches put that there and we'll say assert that the result is equal to the book and if you run this
227:30 - 228:00 test we can see that converting from a Json string into a Java object is as simple as that so you probably noticed already but if we take a look at the Json and then compare it against the Java object here we can see see that the attributes in the Json object match the instance variable names of the Java object ISBN title H got author there we got year published but what happens when you don't want them to match what happens if you want to change them for whatever reason well it's pretty easy
228:00 - 228:30 again so we're going to demonstrate this one by going over to our book and we can see here we've got the year published but let's say we just want that to be year in our Json well we would do an annotation on top of this of Json property if I can show you the arguments here see we've got these we're simply just going to do the string in here of year and just like that anytime that we read adjacent object into Java or do the
228:30 - 229:00 reverse take a Java object and put it into ajacent object year published will become year so if we go back to our class our test class and run this we should expect to get two failures okay we do have two failures and we can see unrecognized field year published so we can just change year publish to year so let's go down here change that to be year and do the same
229:00 - 229:30 up here and if we click on play we can see that the test now passed because we're now using year instead of year published in our Json so we're starting to get the basics of the object mapper and this is really good obviously any annotations that we put on the book object or Jason objects will then be respected by the object Mapp that's used by Spring web as well so bear that in mind so what happens when we get an attribute in our Json object that we just don't care about
229:30 - 230:00 well by default everything will blow up so if we go over to test that a let's change this one here so test that we can create a Java object from adjacent object now let's say that there is an additional right at the beginning here there is an additional attribute which we're going to call Foo and then the value for Foo is bar impr proper computer
230:00 - 230:30 science way of doing things so these Escape characters are always fun okay so I believe that would be valid Json so Fubar is now in our Json object that we're going to try and convert in into Java so what happens what happens when we try and pass this book we can see that we get an unrecognized property exception so there's an unrecognized field F so an exception is thrown but what happens when we just want it to pass we just want it to ignore fields that it doesn't
230:30 - 231:00 recognize well we can we can configure that we're here in our book class so all we need to do is add an annotation to the top of the class called Json ignore properties and then as an attribute in here we're going to say ignore unknown equals true the default of course is false so if we run this we can see the test now passes absolutely fine of course you can configure lots and lots of other things inside of Jackson and the object mappa but these are the ones that seem to come up most commonly so at this point you
231:00 - 231:30 should have a really solid understanding of the fundamentals of spring Boot and how it all works so we're going to take what we've learned and now we're going to do the fun bit we're going to bring it all together and we're going to build our rest API so let's write our rest API let's set the stage so the whole thing about a rest API is it's built on the concept of resources the URL structure is all about resources now we need to establish what resources we're going to use for our rest API and uh I should be no surprise
231:30 - 232:00 by now we're going to be using books and we're going to be using the authors of those books so books and authors next we're going to have to figure out where we're going to be persisting those books and those authors and uh we're going to be saving those into a postgress database today in fact we're going to build on the project that we've already got when we were putting together our spring data jpa so we already have our repositories in place we just need to build a service layer and a presentation layer in order to build our rest API we
232:00 - 232:30 already have a postgress database and it's already got a schema so this is what our rest API might look like now if you take a look here we can see what they all have in common which is this forward SL books as the prefix now bear in mind it's books plural never singular that's the convention so that's what this has in common now books is the web resource that we're dealing with in this case in the case of the author we've already seen would be for/ authors but more on that in a moment so this is our
232:30 - 233:00 crud functionality so our create read update and delete now what's particular about the book is that we're not leaving it up to the database to generate any IDs for this we are providing the ID each time and that ID is the is BN now because of this because we're providing the ISBN each time the convention is to use the HTTP put for the creation and we can see that here for/ books then providing the ISBN with a HTTP put now if we were like in the case of authors leaving up to the system to generate IDs
233:00 - 233:30 then we might use a post but more on that in a moment so we've got our create endpoint and on our successful create that will return a HTTP 2011 created and then we have our read one endpoint so you can see here using HTTP get/ books and the ISBN of that book this will return in the case that the book exists in the database the book is ajacent object and a HTTP status 200 if the book doesn't exist then you can expect an empty response body and the HTTP status
233:30 - 234:00 404 and then we move on to our read many books this will return a list of books rather than just one still using the HTTP method get but this time just for/ books no ISBN specified returning a list of books HTTP status 200 always even if it's an empty list there's no books in the database always get HTTP status 200 next we have put again so this is our update endpoint and you'll see that the URL is identical to the career endpoint
234:00 - 234:30 so that's because it is however in this case when we are updating a book rather than creating a book with put we would expect a HTTP status 200 not 2011 created but otherwise exactly the same and that's because for this particular object we're always going to provide the isbm then we have our partial update which is the HTTP patch for/ books providing that isbm now this differs from the put endpoint because the put endpoint you have to provide all of the attributes of the object and the entire
234:30 - 235:00 object will be updated in the database depending on the attributes that you have provided however in the case of the patch this is a partial update so only the attributes that you provide will then be updated on the object in the database so in the case of the book if you only provide the attribute title in your Json body only the title will be updated for that book in the database and you would get HTP status 200 back on a success for this and then finally we
235:00 - 235:30 have delete so uh Delete will delete your uh your book in the database so delete HTTP method here for/ books providing the ISBN and this will return no response body whatsoever so HTTP status 204 or nobody so that's the books Let's Take a look at the authors so this is our authors it's similar to books but not quite the same so if you look here we've got again crud functionality but to create the author we're using the HTTP post SL authors no ID in the URL and
235:30 - 236:00 this is going to return HTTP status to one created on a success and return the author object in the response body as well but because we're not providing the ID we're leaving up to the system to deter it we would use a post rather than a put like we've done on the book and then we have the read one which in the case of the author is HTTP get for/ authors with the ID exactly the same if the author is found HTP status 200 and the author or if it's not found then HB
236:00 - 236:30 status 404 and then the read many for authors this will return a list of authors just like the book htb status 200 regardless if there's no books in the database or many and uh that's that's fairly straightforward there and then we got the update for the author the full update for the author we can see we're using that HTTP put SL authors with the ID of the author so this will do a full update so whatever the author object you provide in the request body for this one will be what's updated in the database it will completely replace
236:30 - 237:00 whatever author we have in the database with whatever we provided in the request body of that HTTP put that will return a HTTP status 200 on a success and then we have a partial update which again works like the books endpoint whatever attributes that we provide in the request body of the partial update endpoint to for/ authors for/ the ID of the author will be updated in the database if we just provide the name of the author then only the name of the author will be updated in the database
237:00 - 237:30 HTTP status 200 on a success return from this one and then we have the delete endpoint HTTP method delete for/ authors the ID of the author and this will return a HTTP status 204 nobody and then delete the author in the database something you might be wondering about is well what happens if that author doesn't exist in the database well it therefore doesn't exist so the delete was I supposed successful so it will still return a HTTP 204 different schools of thought on this one but that's what our API will be doing in this case so that is the rest API
237:30 - 238:00 structure that we're going to build so with our rest API designed let's get coding now if we take a look at the different layers of our spring application we've already implemented our persistence layer so we're going to build on that so let's open up that project and our ID and get started implementing our rest API so here's our project as we left it from setting up Spring data jpa so we're going to now build our rest API where do we start so I'm going to go down to the pom.xml here and take a look at our dependencies so we already have the
238:00 - 238:30 spring boot starter data jpa so we have everything that we need in order to use spring data jpa we don't have everything that we need in order to build a rest API so we're going to bring in another starter and this one is spring boot starter web now you'll remember this because we brought this in via the spring initializer in the past for our quick start project for example but I'm just going to bring it in via the pom file here and then click on the refresh button to make sure that dependency is available in my IDE okay looks good so
238:30 - 239:00 we've already got our domain classes up there our author and our book we've got our repository that's all good so our persistance layer is handled let's start our presentation layer then so I'm going to create a new package in here here and I'm going to call it controllers controllers being the pattern that we use in order to build our presentation layer at least for a rest API so I'm going to create a new controller in here and I think we should start with the author we've been doing that so we'll go author controller we'll call that a
239:00 - 239:30 class now we're building a rest API so we're going to put The annotation on top of here of rest controller and then that allows us to start building so we're going to build crud functionality out of our rest API so this is going to have a create empo a read endpoint uh in fact several read endpoints say read one or read many it's going to have an update endpoint and we're going to do a couple of those as well we're going to have a full update and we're also going to have a partial update and we're going to have a delete endpoint and I think the best place to start in this case is our create endpoint we know from our design earlier
239:30 - 240:00 that we're going to do this using a post endpoint HTTP post endpoint so we're going to use The annotation here post mapping and then we're going to put in our endpoint for this one which we can do with the path variable of our annotation and we'll say that this one is/ authors and that's it now to create our actual method so this is going to be public and we are going to return from this method the author that we've created so we're going to say author and
240:00 - 240:30 we're going to call this create author but of course we expect a author Json on the request body for this one so it's going to be readed in it's going to be converted using Jackson into a Java object and that Java object is going to represent an author but we need to tell spring about this so going to put the at request body annotation onto that variable there and that's going to tell spring to look at the HTTP post request body for the
240:30 - 241:00 author object represented as Jason it'll convert it into Java for us and now we have to go about creating actually saving the author object in the database so that's when we get into our service layer so we've already got our persistance layer we're writing our presentation layer but we need something to to link them together we need a service layer so I'm going to go over here and I'm going to create a package for our service layer calling it Services now it makes sense I think to have an author service to deal with
241:00 - 241:30 authors so we're going to have an author service represented as our interface here add that and in the author service we are going to create a method public method of course and it's going to return an author and it's going to be called create author and it's going to take an author which of course is the author to create which seems fairly reasonable
241:30 - 242:00 because what we can then do is inside of our author controller we can inject the author service which we're going to do like so author service and we'll need a Constructor and that of course will inject our author service in order for it to be used and then we can call the author service do create
242:00 - 242:30 author okay so we haven't created the service yet but in theory this is all that you would need in order to create that author in your database however this is far from perfect and perhaps the biggest reason why is that we are using in our presentation layer the author object so if we take a look at the author object we can see that actually this is this is an entity this is this is an entity that should exist in our persistence layer and our service layer
242:30 - 243:00 but go no further than that we don't want our presentation layer to have any knowledge of how our persistance layer works so one of the ways of dealing with this is we would use a dto or a data transfer object so the ser service layer would return still our entity but in our presentation layer we would map that over to a dto and that dto would be the thing that is sent and uh also expected in things like uh request bodies on our presentation layer and then that decouples our presentation layer from
243:00 - 243:30 our business logic and our persistence layers because we have that mapping layer in between so I'm going to before implementing our service create in our domain here a new package and I'm going to call this one dto and in our dto package I'm going to create a class here and I'm going to call this one author dto now the dto is going to be a pojo a plain old Java object so it's going to
243:30 - 244:00 have that data we're using lombok again so we have all of our Getters and Setters equals hash code Etc all our Constructor we have a no Constructor because that's needed for Jackson and we will have a Builder here I mentioned Jackson for the no Constructor typically Jackson will create an object using a no arguments Constructor and then use gets and Setters in order to set the values on the object so always make sure that objects that you'll be using with Jackson have that noas Constructor but what should the author
244:00 - 244:30 dto look like well actually no surprise it should look exactly like the entity so if we go over here it should have these fields shouldn't have anything uh like at ID or at generated value or at enti of course that's all to do with spring data jpa and this object doesn't need to know anything about it so we now have this ID name and age on our author dto here excellent so we can now start to use this so we're going to go up to the author controller and rather than expect
244:30 - 245:00 an author we're in the presentation layer so we're going to expect an author dto we try and import this and we aren't returning an author we are in fact returning an author dto here's our challenge our create author method expects still an author object should we change this to be an author dto or is it okay for it to be an author object there's different schools of thought on this but ultimately I deem it okay for the service layer to deal with
245:00 - 245:30 entities it's your business logic so some knowledge of the underlying entities that the persistence layer uses isn't the end of the world if you doing something completely 110% by the book you might looked at a couple of them but I can consider it to be okay in this case but we do of course want to separate our presentation layer from our service layer and from our persistance layer via the use of the dto so we need to convert our dto to an entity in this class and just to make it super obvious that we are dealing with an entity let's go over to the author here and let's
245:30 - 246:00 rename this from author to author entity let's rename my test class as well yeah go for it let's uh let's rename all of those great great and let's do the same for our book while we're here book entity great and just keep things organized let's create a new package in here and let's call this package uh
246:00 - 246:30 entities excellent so we have our author entity and we have our author dto as well and you can see they're pretty similar now we could write the mapping from one to the other manually however as this is a fairly common pattern that people tend to use there is a lot of libraries that handle this for you automatically and one such library is the model mappa Library you can take a look at the documentation online here
246:30 - 247:00 including the getting started and the user manual But ultimately this is going to allow us to convert from our dto to our entities it's going to map from one class to the other so how do we use the model mapper well the first thing that we need to do is import it so we're going to go down to our dependencies here and uh we'll put it I don't know right here and as before let's just refresh this to make sure we have it on our class path excellent so we can now use the model mapper so the model mapper is an object so we need that in order to
247:00 - 247:30 use it and a nice clean way of doing that as we've seen in the past is create ourselves a config directory and we're going to create a new class in here and we'll call it mappa config this of course is a configuration class and we're going to create a bean and this is going to be a model mapper let's call it model mapper and we're going to return a new model mapper great and just like that we
247:30 - 248:00 have access to the model mapper inside of our application context how do we use it what's a nice way of using it now I'm going to create ourselves here a new directory and I'm going to call this one or a new package package I'm going to call this one mappers and to keep things nice and clean and to allow us to swap out to potentially use a different mapping Library later on I'm going to create a Java class which in fact I'm going to create a Java interface here and I'm going to call this mapper and this is going Toc capsulate all of the logic for
248:00 - 248:30 mapping for our application and this mappa is going to deal with two classes which could be different so we're going to use generics here so we'll have class A we'll have class B and we're going to have two methods I think on this one so we're going to have we have map two which is going to return the type B uh we'll call it map two and it's going to take a and then we'll have the inverse which is map from which of course is going to return a and it's
248:30 - 249:00 going to take a b so we can implement this interface with beans and then we can inject those beans as and when they're needed and then that allows us to swap things out so we'll need an author mapper so we're going to go up here create a new directory actually first we'll call This One Import to keep things nice and clean and we'll create a new class and we'll call this one author mapper Ino and we'll implement the mapper and we're going to go from an author entity to an author
249:00 - 249:30 dto cool let's Implement our methods here release the stops of them and now we can go ahead and Implement them proper so we're going to need that model mapper from earlier here so let's go private model mapper model mapper and then we're going to need a uh Constructor so in fact let's just generate that Constructor great so we now have access
249:30 - 250:00 to that model mapper but how do we use it well it's actually fairly straightforward so we're going to use our model mapper in here and we're going to say map and we're going to take that author entity and we want to map that to an author dto do class and we'll return that and on the other method we want to do the the inverse of that so we're going to still return still use our model mapper and we're going to map but in this case from our author dto to an
250:00 - 250:30 author. class author entity Now isn't it there we go great just like that we have a mappa for authors going from an author entity to an author dto and then back again again we want to be able to inject this so we're going to say add component on the top there there we go this is now a bean so let's just copy this and go back to our controller now in addition to our author service we're also going to want an
250:30 - 251:00 author mapper in here so we're going to declaring our type as this mapper going from author entity to Au dto we're going to call this one author mapper and we just need to make sure this is in our Constructor as well and then we'll assign this. author mapper to author mapper great so we now have our author mapper so let's use it author mapper and we will map from the author dto as
251:00 - 251:30 provided and then we'll get to pass our author entity to our create author which is going to return an author entity again which we're going to call saved author entity in this case and then we can return using the author mapper again map 2 the saved author entity which of course return an author dto which is then returned to the caller this might seem like a lot of hard work for not a
251:30 - 252:00 lot of value but as your application grows it's really important to have it as manageable as possible and decoupling your presentation layer from your service layer and your position assistance layer is going to be one of those ways that you can make it more manageable so by showing you this now you might not necessarily need this if you're doing like a really small project for yourself but it's really worthwhile knowing for when you start to work or if you are working on those bigger projects so now it's time for implementing our
252:00 - 252:30 service so we're going to go to our services here we'll create our inol [Music] directory and inside of here we're going to create an author service inut this is a service so a bean so have our author service inut and this uh implements our author
252:30 - 253:00 service great so we now have to implement our create author and we do this of course via our author [Music] repository so let's generate our structor great so we now have access to this author repository and this is an example of a past through method more or less so we're going to take our author entity and uh we're going to take author repository Dove on our author entity like that and
253:00 - 253:30 then of course that's going to return an author entity because that's the default of what spring data jpa does okay so we now have our persistance layer implemented we have our service layer implemented which just does a pass through and then we have our presentation layer implemented as well this being a rest controller with a post mapping at for/ authors So in theory everything should work now so let's start off our application and see this working inside of Postman and then I'll
253:30 - 254:00 show you how to test this with mock MVC so let's start our application so we're going to first things first make sure that we have a running database because that's something we're going to need so we're going to do Docker PS to see what's running nothing's running so we're going to Docker hyphen compose up making use of that Docker compose file on the route of the project that has a postgress database in it great that's up and it's running so we're going to go to it's currently called database application we need to rename that but let's run
254:00 - 254:30 this okay that's the application up and running let's now open up Postman so here we are in Postman and we know that our application is running on Local Host at8 and the endpoint that we need is forward / authors being called with a HTTP post so we can now see that we have an author object so remembering an author object has ID name and age we're not going to use the ID in this case because we've already set up Spring data jpa to generate those IDs for us so
254:30 - 255:00 we're going to provide the name of ARA Montgomery and the age of 80 and this should create our first author in the database so let's take a look see if this works there we go we can see we've got a HTTP 200 which which isn't necessarily what we'd want we'd want maybe a HTTP 2011 created so it's working but we can tweak that and uh We've also got here our first author created so the ID of one generated for us the name ARA Montgomery and the age of 80 so that looks really good it seems
255:00 - 255:30 to be mostly working that's absolutely great so it looks to be working but let's actually now write some tests for this so it looks like our first endpoint was working but let's now prove it so we're going to do that with an integration test using Mark MVC so first things first let's go down here and let's create for ourselves a new package in our test directory called controllers and we'll create a test in here and we'll call this one authors author controller
255:30 - 256:00 integration tests okay and this is going to be a test which was an integration test so we're going to need a running spring application will be a test version to test them so we're going to need to the spring boot test annotation now we also want this to be clean between each running so let's add our dirties context annotation um oh let's not forget our extends width to make sure that everything is nice and integrated so we need the spring extension class used in
256:00 - 256:30 there as well and we're also going to want mock MVC so we can add an annotation which is auto configure mock MVC which creates an instance of mock MVC Forest that and places it into our application context ready for use so let's get a hold of these objects and then we can actually start writing the test cuz mock MVC is a super powerful way of testing your controllers so then let's get hold of these objects so we're going to need mock MVC first of all so let's say mock MVC which is going to be private of course mock MVC mock MVC and
256:30 - 257:00 uh let's now create ourselves a Constructor because we're inside of our tests and we want to autowire this or it we're going to have to use the auto wide annotation there we go so we now have access to our mock MVC object we're also going to need a couple of others for this but let's start writing our test and we'll add those as we need them so we write our first test here and this will be a really basic one so we're
257:00 - 257:30 going to call this one test that create author successfully returns HTTP 2011 created great now we can start using mock MVC so mock MVC is a little bit complicated so let's start with mockmvc perform and inside of our perform we need to use a request Builder so the request Builder that we want to use is post in this case because we're using a HTTP post and
257:30 - 258:00 we're going to post the forward SL authors but that's not where it ends we're going to want to specify the content type which we know is uh if we go to Media type is application Json and then we want to add a request body which we can do with the content here now content takes a string and we know that we're posting adjacent object to this endpoint so we need to get a hold of adjacent object well of course we need an object mapper so let's get hold of one so we're going to declare one up
258:00 - 258:30 here private object mapper call it object mapper let's import that and now we'll need to initialize this we don't have an object mapper in our spring context so we'll just create one this. object mapper equals object mapper great so we now have access to our object mapper let's use it to generate some Json for our author object so we have our test data util and we know that we can create a test author so let's do that but let's also
258:30 - 259:00 set our test author ID to null because we now know that it auto generates it for us when we use spring data jpa so we have our author entity let's make it into Jason so we're going to go object mapper dot WR value is string passing in our test author a and that will assign that to a string called author Json and of course we'll need to add the exception to the method signature so we now have our author Json let's put that in content mock MVC also
259:00 - 259:30 throws an exception so we need to add that to the method signature there so exception should cover everything that extends exception so that's not where ends we now need to add some assertions to this so we add assertions like so we need to go down to here and then we need to go and expect and then we'll need to have a result matcher so the result matcher we're going to have in this test is status and is created and that's all
259:30 - 260:00 we're going to do for this test we can actually go ahead and write additional test use Json path so we can actually test the response body for that but we'll do that after first thing let's run this and see what we get okay we have a failing test that's what we'd expect but why is it failing and it's failing because you can see there the uh body that's being returned that's very good that's a response object HTTP status 200
260:00 - 260:30 bear in mind status expected a 2011 but was a 200 so this allows us to to update this so we're going to go over to our controller and rather than just return the author dto we're going to wrap that in a response entity and that response entity allows us to control things like the status code of the response so we can return a new response entity passing in our object but then as our second parameter
260:30 - 261:00 we can then do HTTP status created and if we were to run our test again we can see we now get a green test We Now respond with a HTTP 2011 rather than the 200 that we had before so let's go back to our test and we'll write a second one but this time using Json path so we go to integration test here and I'm going to copy this test being a
261:00 - 261:30 little bit lazy we can always refactor afterwards test create author successfully returns saved author so we're going to exactly the same thing as before we're going to uh use test author a we're going to write the value to the Json there and then we're going to post it to for/ authors we're not going to test the status in this test instead we're going to use Json path and this is where things get interesting so in Json path you would usually use an expression to
261:30 - 262:00 denote where to look in the Json we'll start with the dollar and then we'll say do ID in order to check for the ID attribute in the root object which in this case we want to do an assertion on which is uh is a number so the ID is going to be generated for us automatically so we can't necessarily assert that's going to be a specific number but a number should be enough for now now let's do another and expect and we're going to use the Json path again
262:00 - 262:30 we're going to use the name and we can use the Value method on this and we know that this is going to be equal to Abigail Rose but for the sake of a failing test let's do a uh triple question mark there so that tests our ID that tests our name let's also test our age which we know to be age and again this going to be the value that we don't really know right now so let's run this test and see what we
262:30 - 263:00 get okay we've got ourselves failing test that's good let's go down here here's our failing assertion expect did triple question marks and got Abigail Rose which is exactly what we'd expect so let's put that in there and run a test once more okay another fail that's good okay expected triple question marks
263:00 - 263:30 but got 80 which of course we know Abigail Rose to be 80 years old which of course matches our CR test author here Abigail Rose age of 18 so if we now run our test once more we should expect a passing test there we go looking good so it looks like our endpoint is working absolutely fine we we've seen that in person and we've also written mock MVC test for it uh that test both the status code is returned did a little tweak
263:30 - 264:00 there and we also make sure that a particular object structure is returned as well so all very good stuff so with the author create endpoint out the way let's quickly do the book one as well so that's the create endpoint done on the author controller let's now do the book controller so first things first we're going to need to create a controller class for us which we're going to call book controller there we go and we need to put the app rest controller annotation on the top there because of course we are dealing with a rest API controller
264:00 - 264:30 now let's create this endpoint which we know is going to be a put mapping to SL books and then the ISBN is going to be in the path so we're using that put mapping so we can specify the ISBN every time we create a book that was a design decision that we made so we then need to do a public and we will return a response entity wrapping a book well at this point we have a book entity so we will
264:30 - 265:00 put a book entity in there for the moment but let's replace that with a book dto right after we've done this method so we'll say create book and we're going to need to get a handle on the ISBN that's in the path so let's do a path the variable the name of which is ISBN and let's assign that to a string called ISBN okay now what are we going to do for the implementation well before we do the implementation let's get a hold of that book dto so we're working to the right objects here so let's go to our domain and then go into our dto and
265:00 - 265:30 inside of here we're going to create a new class we're going to call that book dto so this is going to be a plain old Java object a pojo much like our author dto so we're going to have here a data annotation using lombok and all R Constructor a no R Constructor and we'll have a builder in there why not now what is our book dto going to look like well exactly the same as our book entity so let's go over to our book
265:30 - 266:00 entity of course the difference is the book entity references the author entity whereas our book dto is going to reference our author dto so we're going to borrow this go to our book dto place that in now we're not going to need the ID that's from Spring data jpa and we're not going to need the many to one or the join columns fact let's get rid of those Imports there now instead of an author entity of course we know this is going to be an author dto but we'll still call it author because that seems relevant so we've now got our book dto let's go ahead and use it back over
266:00 - 266:30 in our controller so we're going to instead return a response entity book response entity book entity we're going to return a response entity book dto and let's import that wonderful stuff so let's start implementing our method here so first things first we're going to want to map our dto to our entities so we can use it in our service and our persistance layers so we're going to need a mapper so we go down to our mappers we've got our mapper implementation for author there let's create one for book so let's go new Java
266:30 - 267:00 class and we'll call it book mapper and this is going to implement mappa going from a book dto sorry book entity to a book dto lovely stuff and let's implement the stubs of these methods great so for this we're going to need our model mapper so let's get a handle on that as well so model mapper model mapper and we that's
267:00 - 267:30 private of course and we can then inject that with our Constructor injection so let's use our IDE to generate this Forest so we'll go generate Constructor and yep want that model mapper in there great so we now have access to our model mapper um although this isn't technically a beam quite yet so let's put a component on the top of this so we now use our model mapper in our method implementation so we're going to say return model mapper do map taking the book which is a book entity in this case
267:30 - 268:00 and then we will convert that to a book dto class that's the first one done and now for map from so we're going to say model mapper do map going from the book dto and that will map to the book entity. class let's return that great stuff so that's our mappa let's now use it in our controller so let's go back over there and let's get a handle on it so we're going to need a
268:00 - 268:30 private mapper going from book entity to book dto and we'll call this one book mapper Let's import everything that we need great and let's use our IDE to generate our Constructor for us so it's injected great so we now have our book mapper so let's get a hold of our book entity so we're going to say book mapper do map from uh we haven't yet got a
268:30 - 269:00 handle on the request body there forgotten about that so we're going to say request body and of course we expect a book dto to be put in the body of this of this call so we're going to say book dto and we'll just call this one book dto great so we now have access to that book dto so we're going to put that in the map from sign that to a variable and that is our book entity so to create a book we're going to need to interact with our service layer of which we currently
269:00 - 269:30 don't have one for books so let's go down to our services directory here and let's create in there a new interface in this case and we're going to call this one book service and book service at the moment it's going to have a single method and it's going to return a book entity which is the book that was created and we're going to call it create book and it's going to take the ISBN of the book to be created bearing in mind we specified that each time that was our design decision and then it's going to take the book entity which is the book to create
269:30 - 270:00 now if we create an implementation for this let's create a new class call this one book service impul and this of course will Implement our book service and we'll get a stub for the method and we'll put at service annotation on the top of the class there denoting it as a bean so how do we create a book in the database it's fairly straightforward we need to handle on our Book Repository so let's declare a private Book
270:00 - 270:30 Repository inside of our class there and now let's create for ourselves a Constructor using generate Constructor okay great we now have access to our Book Repository so Book Repository Dove and that will take a book however we want to make sure that the ISBN that's on the book entity object is exactly the same as the ISBN provided in the method because if they're not then we can get into a situation where we are
270:30 - 271:00 creating a book with a incorrect ISBN or at least a different ISBN specified in the book entity object and the URL and that can lead to all sorts of problems so we're going to Simply say book do set ISBN specify the ISBN that's provided and we can then be sure that the book that we say the book that we create will always have the ISBN provided in the URL the one on the body will be over in so we're going to return that and then that
271:00 - 271:30 will return our book entity and that simply is our create book method so let's go back so we're going to need to get a hold of our book service so we'll say private book service call it book service and of course we're going to need to drop this into our Constructor because we want it injected so let's say this. book service equals book service wonderful stuff we now have access to our book service so let's use it book service do create book and then we'll pass in the ISBN From the Path and then
271:30 - 272:00 we'll pass in the book entity that we converted from the book dto that was in the request body of that call so let's assign that to a variable called saved book so we now have a saved book entity we of course need to return a book dto from this so we're going to use our mapper once more book mapper do map 2 and then that will take the saved book and that is then going to be our saved book dto let's call that
272:00 - 272:30 our saved book entity just to make sure that there is no confusion so now we'll simply say return new response entity passing in the saved book dto and we're going to say HTTP status and because we are creating we are going to return HTP status created or 2011 and that is our create book method implemented so let's start our application and go over to postman to test it out actually before we do let's
272:30 - 273:00 rename this from database application to books API application there we go and let's start our application up great the start up absolutely fine let's go over to postman here we are in Postman and we can see here the request to our new endpoint so we've got here our HTTP put going to Local Host 880 where we're running and then we have for/ books and then the ISBN of the book that we want to create and then in the body here which is Jason we have an ISBN
273:00 - 273:30 a title and we're leaving the author is null now we can manipulate the nested author however we're going to leave setting up until a little bit later and just use the default configuration for the time being so we expect a book to be created with the ISBN provided and also the title so if we go ahead and click Send I'm expecting a HTTP 2011 created and for that book to be returned Okay so we've got HTTP status 2011 created that is great and here is
273:30 - 274:00 our book ISBN and then the title so something I want to double check while we're here and we're going to have to create a new book for it is that the ISBN in the URL overrides the one in the body so I'm going change this one to be let's say 999 and then I'm going to change the ISBN in the URL to be two and I expect the one in the URL to be used because that's what we set on the body of the book entity when we save it in our service layer so we're expecting a HTTP status 2011 created and for the
274:00 - 274:30 ISBN of the book to be the one specified in the URL here not the one in the body so let's try this out looking good 2011 created and it's ending in two which is the one specified in the URL everything looks to be working fine let's now write our mock MVC test for this so here we are back in our code let's go down to our test and we're going to create a new class in here and we're going to call it our book controller integration tests and we'll just put the necessary
274:30 - 275:00 annotations on the top here it's a spring boot test we're extending with a spring extension to make sure everything is nice and integrated we are our dirtiest context so our database is cleaned down with each text and we'll autoc configure our mock MVC so we can get a handle on that so that's the first place we're going to start so we'll say private and we'll say mock MVC call it mock MVC and then we're going to need to get a handle on this so let's con generate our Constructor and because we're running in
275:00 - 275:30 our test we need to specify The autowired annotation to make sure that everything is injected so now for our first test and we are going to use a test annotation here go public void and we'll call this test test that create book returns HTTP status 2011 created and now for our implementation so we are going to need to get hold of a book to create so we're going to need a book dto so if we go to our test data
275:30 - 276:00 util down here we can see that we've got much like we did have before simply got create test book a and that creates a testbook entity we of course want to create a testbook dto so I'm just going to copy this and we're going to return a book dto we're going to call this create testbook dtoa and that's of course going to require a author dto specified there
276:00 - 276:30 great so we now have a create testbook dtoa which is going to create for us a book dto it's very similar to our book entity here which I'm just going to rename to create book uh create test book entity a just to differentiate it so let's go back to our test and we'll say uh we've got here a book dto I'm going call it book dto and we'll say create um test
276:30 - 277:00 data till and we won't pass in an author so we now have our book dto but of course our mock MVC is going to expect Json so we're going to need that object mapper much like our uh author controller integration so we're going to say private object mapper call this one object mapper and we'll create it in our Constructor so this object mapper equals new object mapper great so we now have our object
277:00 - 277:30 mapper so we're going to say object mapper dot write value of string passing in our book dto now of course right value is string is going to throw an exception so I'm just going to to say throws exception we'll use the top level exception because we know that mock MVC also throws exception that should cover everything and let's assign that to a variable and we'll say we'll call that uh create book Json so we've got our
277:30 - 278:00 create book Json let's now use our mock MVC so let's go over to the author control integration test here and just borrow from there because it's quite elaborate and we're going to say mock MVC perform not a post for this one it's going to be a put and it's going to be to forward SL books and then it's going to be the ISBN so we're going to say book D.G ISBN and the content type is application Json and then we're going to pass in our book Jason there and it's
278:00 - 278:30 going to be HTTP status is created so that should be everything we need for this test let's go ahead and run it looking to me everything passes fine so that's the HTP status code let's make sure that the created book is returned in the body so let's borrow this test here and we'll say test that create book Return HP status we'll say the created book so it's going to be very
278:30 - 279:00 similar to our previous test but of course the expectations are going to be slightly different let's go back to our author controller integration test here and we will borrow the specific encount that we need for Json path and we will set it up for our books so we want to make sure that the ISBN matches the ISBN that is provided so we're going to say value and it's going to be the same one for our book dto so we'll say book dto do get
279:00 - 279:30 ISBN and we want to do another expectation here and the second expectation is going to make sure that the title of the book is exactly the same as the one speci ified there so this is going to make sure that our saved book is returned let's run this test there you go it's passing absolutely fine and there we go we have implemented and tested our create book endpoint so let's now Implement our read many endpoints on our authors here so
279:30 - 280:00 we've got the author controller let's go ahead and create a new endpoint so we know that the endpoint for read many is a get endpoint so we're going to use get mapping and the path for this is going to be/ authors just like before let's go public going to turn a list of author dto and we're going to call this one list authors don't need to do anything
280:00 - 280:30 special in the arguments this method because of course the read manyu doesn't have an ID in the URL or anything like that so we're going to take our author service let's call call it uh find all on the author service shall we and this will expect return a list of author entities and we'll call this one authors and then we'll need to convert the author entities into author dto so we'll do that with
280:30 - 281:00 authors stream.map and then we'll use the um author mapper and then we will do a map from and we'll collect two list oh of course it's a not a map from it's a map 2 in this case isn't it there we go so this will do everything it needs to to return a list of authors now bear in mind it will return everything
281:00 - 281:30 in the database which is definitely not the most optimized if you had 5 billion rows of authors in the database it would take a long time and crashes or two I imagine but we'll cover that when we get on to pagination which is a way of getting around that we'll do that a bit later though so we need to implement this find all methods so let's create the method in the author service it's going to return a list of author entities and it's just called find all go down here and let's generate okay
281:30 - 282:00 so we're going to take our author repository and we're going to go find all it returns an iterable now we could decide to use an iterable throughout this application but I prefer the list API for this case so we're going to convert this into a list and capsulating it in our service layer here so we're going to do that with this incantation so we're going to use stream support going to call do stream on there passing our spliterator and we are not going to be parallel so we'll pass in false and we'll collect to list returning
282:00 - 282:30 this and put that on a new line so we can see everything so we'll use stream support to take the spliterator from the find all which is an iterable and then we will make sure oh we don't need it parallel to the convert it so we will simply just call the collect on the stream that's produced with the two list collector so we now have a list of author entities so let's go to our author controller and all seems well there so
282:30 - 283:00 our list author's endpoint should in fact work so before we write tests for this let's just start our application and see if that's the case okay the application is up and running let's go over to postman so here we are in Postman we can see we're using our HTTP get we've got Local Host 8/ authors and uh yeah that's all we need so let's send this request and see what we get okay great we've got HTP 200 okay and
283:00 - 283:30 then we've got a list of authors and there's are ARA Montgomery id1 age of 80 that we created earlier so that seems very good indeed let's go over and write our mock MV test for this so we know that it always returns HTP status 200 so let's create a test for that so we're going to say at test public void test that list not books list authors returns HTP status 200 okay and we're going to borrow the
283:30 - 284:00 mock MVC perform from up here but we aren't using a post of course we're using a get to for/ authors and we don't have any content to send there's no point in providing that okay perform of course um throws an exception let's add that to the method signature okay great now for some expectations and expect mock MVC result matches. status and the stat of course is okay so we should
284:00 - 284:30 expect this to [Music] pass looking good so we now need to go on to the body I think so test list authors returns list of authors okay so rather than we're not going to expect on is okay in this case we are
284:30 - 285:00 instead going to follow the Json path example and we'll paste in there but of course this returns a list so rather than it be just ID it's going to be Dot Z it's going Z not do0 but dollar Z name and then dollar z. AG Zer being the first thing in the index the first object in the list but of course the list is going to be empty but let's have a
285:00 - 285:30 look okay so there's no value at that path so we need to create an object in the database because we know between each t our dirti context annotation is going to completely clean down our database so what's the best way of creating something in the database well I think the best way of doing it in this case is just to get a handle on our service layer so we're going to go private author service author service and then we will inject the author
285:30 - 286:00 service using Constructor injection and then we'll go this. author service equals author service great so we can now save entities in the database so let's do test data util do create test author enti let's assign that to a variable and then we can now go author service. create author passing an entity and we don't need to assign the uh The Entity to anything don't need to assign it to a
286:00 - 286:30 variable so providing I've got my Json path correct this should now pass because the author has been created in the database by you calling the service directly great looking absolutely fine so we now know that the object is returned as the first element in the list when it exists in the database so that is the list all or the read all or the find all endpoint for our author let's now do our book so
286:30 - 287:00 let's now Implement our list books endpoint so we're going to go over to our book controller here and we're going to go get mapping the p of course is going to be SL books and then we're going to go public list of book dto to be returned and we'll just say list books is the name of the endpoint don't need to provide any path variables or anything for this one and uh let's import the class of
287:00 - 287:30 list okay so we are going to need to call book service dot we'll call it find all I think that was the convention we're using before and that's going turn a list of book entity and we'll just call that books of course find all doesn't exist and uh it's better to use pagination but we'll use a straightforward list for the time being so we now have our list of book entities what do you want to do with them well we can use the mapper so we're
287:30 - 288:00 going to go books. stream and then we'll map them and we use our book mapper and it was map two and then we'll collect that as our list and return that let's put on some new lines great so very very similar to our authors implementation let's now Implement our find all so let's create that method returning a list of books go to the implementing class down here get
288:00 - 288:30 the sub of our method and uh we'll call Book Repository do find all again returning that iterable so we need to do the anation of stream support do stream and that expects a splitter rator we don't need to be parallel and then we will collect that to [Music] list and then return that so we now have
288:30 - 289:00 a list of all of the books in the database being returned by find all so that in theory should be enough for things to work so let's now restart our application and hit that in Postman okay let's go over to postman so here we are in Postman we can see we're using the verb HTTP get here and we've got locost atat books as our URL so if we hit send we should expect to get that one book back that we saved earlier but in list form so let's hit this there we
289:00 - 289:30 go and there is our the shadow in the attic and the Isn of the book that we created earlier so that seems to be working fine let's now write the mock MVC test for this so here here we are in the books controller integration test so we are going to write the HTTP status 200 test so every time that we go ahead and hit the Endo we expect HTTP status 200 back so we're going to say test that list books returns HTP status 200
289:30 - 290:00 okay the URL doesn't have the ISBN and we're using HTTP get of course we're not providing any content to this end point and uh we expect an is okay so this should be enough to test that okay looking good that's working absolutely fine so let's now implement
290:00 - 290:30 the test that tests for the response body so we need a new test and we'll call this one public voice test that list books returns book this will throw an exception as well okay so let's borrow this from up
290:30 - 291:00 here but of course we are going to use our matches which are similar to what we had on our create endpoint so rather than it being just just a plain object though this is going to be a list so we're going to change this to be zero but of course because of dirtyest context we need to create that book in our database and for that we're going to need our book service so let's create our book service here book service book service and we'll need to inject this
291:00 - 291:30 via our Constructor so let's do that there and then assign it this whoops this do book service equals book book service great so we now have access to our book service let's create our book so we're going to say test data util do create test book entity a not going to pass in an author we'll get on to the nested objects again in a little bit so test we have a book entity so now we're going to say book service do
291:30 - 292:00 create book passing in the ISBN which we'll get from our test data and then we'll pass in our book entity so at which point we should have our book created in the database and we should expect this test to pass so let's play this passing absolutely fine so we now have a list books endpoint let's now get on to the retrieve the find one for authors so let's now Implement our read
292:00 - 292:30 one or retrieve one on our authors's controller so let's Implement our method so we are using a git mapping and the path for this one is going to be like like before for/ authors but this one is going to have an ID in the path so we'll now need to go public returning a response entity because we want to have control over the response status code and it's going to return an author dto okay and we'll call this one get
292:30 - 293:00 author we're going to need reference to whatever the ID that's passed in in the URL so I'm going to say at path variable passing the label which we know to be ID and we're going to assign that to a long because it's a numeric ID for authors and we'll just call that ID so we now have reference to it so whatever is provided in the URL path here will be put into this variable here great so we're now going to call our author service and we're going to say find
293:00 - 293:30 one we're going to say yeah we'll say find one and uh we're going to pass in the ID of our author there and we expect this method which currently doesn't exist to return an optional because either the author will be found or it won't and we want to return an author entity because it's coming from our service layer and we are going to call this one found author there we go so we now have an
293:30 - 294:00 optional so in the case the author exists we'll get an optional with the value of the author and in the case that the author doesn't exist or can't be found then we are going to get an optional empty so let's convert this into what we expect which is a response entity so we're going to go found author do map and in there we're going to have our author entity now in the case that we have found an author we want to convert the author entity into an author dto so we can use our mapper to do that and we'll say map to passing in our author
294:00 - 294:30 entity we'll assign that to a variable author dto and then we're going to return a new response entity containing our author dto with the HP status of okay there we go and in the case that we get an optional empty we want to return a new response entity but in this case it's going to be a HTP status of not
294:30 - 295:00 found and we will return the result of that from our method like so now this is all well and good but we don't have a find one method meod in our service layer yet so let's create that so create method in our author service great so let's now go down to the implementing class get the stub for this method and it currently returns an optional empty that's no good so we're going to say author repository. find by ID and uh we'll just pass in the ID
295:00 - 295:30 there and we'll say return it is just a pass through in this case so with that being done then it looks like we are in a position to test our application so let's restart our application and uh hit it in Postman okay that's restarted absolutely fine let's flip over to postman so here we are in Postman and we can see the results of our list authors here and we
295:30 - 296:00 can see that we' got one author in the database ARA Montgomery with the ID of one so bearing that in mind I'm going to borrow the URL open up a new tab here put that in and then put the ID of one in the URL like so and if we send this we get a HTP 200 back and ARA Montgomery that's perfect but what if we were to change the ID to be let's say 99 and send that HTP 404 perfect 404 not found so it looks
296:00 - 296:30 like it's working absolutely fine let's now write the test for this so we're going to go to the auth controller integration tests and we will borrow the h P status test room up here and we'll tweak it for our need so we'll test that get author returns HTP status 404 when author exists so we're going to say for/ authors one and we expect it to be is
296:30 - 297:00 okay but of course we need an author created in the database for that so we're going to borrow from our list authors test which does that for us so this is going to create an author in our database and we should expect HTP status 200 okay here so let's run this working good let's just change that to be 99 and just see if we get a failing test okay looking good to me okay so
297:00 - 297:30 we'll now need to make sure that we get HTP 44 when it doesn't exist let's copy that let's not create anything in the database and then let's change that to be 99 author returns HTTP status 404 when no author exists and uh we expect that to be is not found let's run this and see what we get looking good so now let's write a
297:30 - 298:00 test to make sure that the response body is what we expect it to be so we are going to say test that get author returns author when author exists and we're going for author one which is the test author entity that we are creating here so Abigail Rose age of 80 id1 so that's what we expect to get and now rather than checking the status in this test I'm going to borrow the matches from up here and we will replace this assertion here and we're not expecting a list
298:00 - 298:30 we're expecting an object so we can tweak these Json paths otherwise that's what we expect and we can actually assert that the value is one in this case cuz we have already saved in the database so let's run this and see what we get looking good so this is the find one the read one endpoint for our authors implemented and tested now let's do the book so let's Implement our read one find one endpoint for our book
298:30 - 299:00 controller now so we go over to our books here we're going to need a get mapping path is going to be/ books with the ISBN provided in the path we're going to go public it's going to return a response entity of our book dto and of course we're going to need our path variable rbn and we'll sign that to a string called
299:00 - 299:30 ISBN okay so let's implement this so we're going to call our book service and we're going to say find one passing in the ISBN and we're going to expect that to return an optional of book entity and we'll call this one Found book there we go of course doesn't exist yet but that's fine and just like on the author side we are going to call find book. map and in the case that the book does exist that we do have a book
299:30 - 300:00 entity then we're going to need to call our book mapper and we're going to map two passing in our book entity which is going to return us a book dto and then we're going to return a new response entity passing in our book dto and it's going to be HTP status okay or else in the case that the book doesn't exist we're going to return a new response entity and it's going to be
300:00 - 300:30 HTP status code not found and of course we need to return like so great so that should be all that we need to do on the controller let's Implement find one in our service layer great that's looking good in our interface let's now go to our implementing class and we'll need the stub of this method and then we can call our Book Repository dot find by ID
300:30 - 301:00 passing in our ISBN and then we can return this just like that so this should be enough to make our find one our gitbook endpoint work so let's restart our application and then we can test it okay application restarted let's go over to postman okay so this is the results from our list books endpoint that we've already implemented and we can see here we have one book in our
301:00 - 301:30 database shadoow in the Attic with that isbm so I'm going to open up a new tab and we're going to go for/ books passing in that ISBN and we expect to get HTTP status 200 back with that book Json so let's send this looking good and if we were to change the ISBN to one that doesn't exist HTTP status 404 looking good so we can now Implement our mock MVC test for this because everything seems to be working absolutely fine we're going to go to our
301:30 - 302:00 book controller integration tests and we are going to implement a test test that book returns HTP status 200 okay when book exists so borrowing again creating that book in our database and we are going to say SL books plus testbook entity. get ISBN whever that may be and we expect it to
302:00 - 302:30 be okay let's run this expecting it to go green looking good and I'm going to copy this test and I'm going to say test get book returns HP status 404 when book doesn't exist and I'm simply just not going to create the book in the database but you might as well just keep the reference to that book
302:30 - 303:00 there and uh yeah so this is going to go not found let's run this test expecting it to pass looking good so we now implemented our find one our get book endpoint and that's been tested as well let's move on to the update endpoint for our author so let's now Implement our full update endpoint for our author so if we go over to the author controller here we are going to need a put mapping and the
303:00 - 303:30 part for this one is going to be SL authors and then the ID of the author we're going to call this one public and we will have a response entity and we'll return the author dto because we're going to return the updated author whatever that may be and we'll simply call this one F update author that's not all we're going to need the path variable because we need to know which ID we are dealing with so
303:30 - 304:00 ID assigning that to the long of ID and we are also going to need the request body because we are expecting a author dto and we're going to call this one author dto so this is the author information that we're going to update in our database let's now go ahead and
304:00 - 304:30 call our author service in fact before we do that let's just make sure that this author does actually exist first so we're going and say say author service do is exists passing in the ID of the author we'll say if exists in fact we'll say if it doesn't exist then we're going to return these response entity of HTP
304:30 - 305:00 status not found because of course you can't update a uh an object that doesn't exist so that's our response entity of HTP status not found we're going to have to implement this is exist method so let's create method in our author service here now go down to author service to the stub and we will implement this this again is going to be a straightforward
305:00 - 305:30 pass through so author repository dot I think it is Exist by ID passing in the ID as provided and that's going to return our Ian for us so we go back to our controller now that exists absolutely fine but what's going on here then ah missing new keyword okay great so we can now be sure that our author exist in the database that's good so let's go ahead and update it so we're going to say author service
305:30 - 306:00 dot now we get to make a design decision we can either create a method on our author service called Full update author or or we could make the current method that we have which is create author a little bit more generic so we take a look at the implementation for create author we can see it simply just saves it just updates the author in the database so what I'm going to choose to do at this point is rename that to be save still makes sense in the context of
306:00 - 306:30 our create endpoint however it now also makes sense in the context of our update endpoint so we know that our author exists in our database so let's take the dto making sure that we set the ID on it um to be the ideas provided in the path to make sure everything is nice and aligned and now we'll go ahead and convert that using our author mapper and we will map to Let's map from so we now have a author entity and
306:30 - 307:00 we'll pass that into our Save which of course is going to give us a saved author entity which we can then take the author mapper and we can map two in this case taking the saved author entity and then we can return a new response entity with the first argument being our saved author dto or updated author dto in this case and then the HTP status of
307:00 - 307:30 okay great so this should be enough to have a full update endpoint work working so I'm going to go ahead and restart our application and we'll see it working in Postman great so that's up and running let's go over to postman okay so we know that we have Arya Montgomery in our database so here's our retrieve one our find one our get author endpoint and
307:30 - 308:00 we've got ARA Montgomery in there so if we were to take this same request and change it to be a put to this endpoint with the ID in there and go over to the body Go to Raw go to Jason and then we're going to provide the Jason body but rather than Arya Montgomery we're going to say actually we've got the name wrong it's Maria Montgomery now for the sake of argument I'm going to change the idea in the body to be 99 hoping that that's also overridden and uh let's
308:00 - 308:30 click on send now okay so we have HTP status 200 the ID is still one which is what we specified in our URL perfect however we do have Maria Montgomery now so we change that to a get just to yep Maria Montgomery in the database now if we were to do a put for a author that doesn't exist for the sake of argument and it's just 99 let's make sure we get HTP status 404 back 404 not found
308:30 - 309:00 looking good so let's now write our mock MVC test for these so we're in our author controller integration tests and we're going to write a few tests for the status code first of all so so test that full update author returns HTP status 404 when no author exists I think that's a reasonable test to start with so authors 99 put uh we are going to need a test author entity I think of course we aren't going to save in the database at this point but we are going to need to
309:00 - 309:30 get the Json for it so we're going to say almost fallen into the same trap we need an author dto not so go test data util do create test author dtoa there we go write that value as string author dto Jason and we'll pass that using the content method there
309:30 - 310:00 great so we're doing a put to authors 499 that author doesn't exist in the database we happen to create the dto but certainly haven't saved it using the service so we now expect the status to be is not found let's run this and it should pass looking good now let's do the inverse where we test that full update author returns HTP status to 100 when author exists so we've got our test author dto that's all well and good but we are going to need our test data util
310:00 - 310:30 dot create test author entity a so we've got our entity and we're going to use our author service to save our author entity in our database [Music] there looking good and then we know that the dto fat before we do that let's get a reference to our saved
310:30 - 311:00 author and we will use the ID of the saved author in our L there so it definitely all exists and we are passing our test author dto let's run this and expect a green test got a fail test alt because I haven't updated this so is okay let's run that once more expecting it to go
311:00 - 311:30 green looking good that's all green so we now have those for the status code let's make sure that the update actually takes place so we're going to say at test public void test that full update updates existing author so we're going to need an existing author in the database before we can go any further so let's do that so we've got test author entity a which we know to be Abigail Rose age of 80 and
311:30 - 312:00 that's now saved in the database now let's get hold of our dto so we're going to say test data util dot uh create test author B and we'll call this one our author dto now test author B has an idea of two in this case Thomas Cronin age of 44 we're going to update we're going to Filly replace the information of our author with IDE of one which we know will be our beig girl rose with Thomas
312:00 - 312:30 cronin's information doing a full update so to do that we are going to borrow this from up here needs hold of that Json first so object mapper do WR value as string taking the author dto um author dto and then we'll set the ID though of the saved author dogit ID because that's what would happen in the real world naturally you'd want the IDS to match and then we'll add that
312:30 - 313:00 exception to our method signature maybe just making an exception because we know about our mock MVC and there is our author dto update Json which we're going to put in our method body there okay this is where it gets interesting so this should update but we want to assert that whatever is returned is from the Thomas Cronin version of the author so we're going to borrow
313:00 - 313:30 expectations there and the ID is still going to be whatever the saved author. git ID is that's not likely to change however the author dto the the the value that's returned from the updated object should be whatever was in the author dto not the original author entity and it should be the same for the age as well so let's run this test expecting it to pass
313:30 - 314:00 okay we have a failing test let's see what that is typo on my part so that's uh should be get name try again okay looking good so that is the full update endpoint implemented for the author let's now do the books so let's Implement our full update
314:00 - 314:30 for our books controller then so if we take a look here we have the create endpoint which if we look is a put request to for/ books isbm which is exactly the same path that we would expect for our full update as well and the reason being is we made a design decision that we want to specify the ISBN every single time we create a book and not leave it up to the system to generate it for us how is our fill update going to differ it's going to differ in the response code that's returned and that's pretty much it so in the case of a create it's going to be a
314:30 - 315:00 HTTP 20 so let's Implement our full update for our books controller then so if we take a look here we have the create endpoint which if we look is a put request to for/ books isbm which is exactly the same path that we would expect for our full update as well and the reason being is we made a design decision that we want to specify the ISBN every single time we create a book and not leave it up to the system to generate it for us how is our fill update going to differ it's going to differ in the response code that's returned and that's pretty much it so in
315:00 - 315:30 the case of a create it's going to be a HTTP 2011 and in the case of an update it's going to be a HTTP 200 so let's change this in order to be both a create and an update so we're going to change the name of the method to begin with create update book doesn't do anything functionally but of course is very descriptive for us now then we need to check if the book exists in the database or not because if it already exist then it's an update and if it doesn't exist then we're creating a new one so we need to call the book service and we'll have
315:30 - 316:00 a method which is called is exists and then we'll pass in the ISBN of the book there now of course method doesn't yet exist we'll need to create it now in the case that the book does exist then we have ourself an update and in the case the book doesn't exist we have ourselves a create book case let's not Implement that just yet let's see how the different paths would differ so we've got the map from a dto to an
316:00 - 316:30 entity well we're going to need to do that anyway so let's put that up there and then we have the creating of a book hm that's interesting so we would need to create a book each time more or less well would we let's take a look at the implementation well we would need to do this logic each time but we wouldn't necessarily need to create a book each time we would need to maybe create update book because we would definitely want to set the isbm provided onto the object and then we want to call the spring data jpa save so that would be
316:30 - 317:00 the same for each so that's now more descriptive as to actually what it does and we'd want to do that every single time so we're going to put that up there then mapping from the entity to the dto we're going to want to do that each time as well okay and then we have the response entity which if we take a look here yeah okay that's going to be different so let's put that in there HTTP status created let's make that HTP status okay but that's not going to be enough we need to check that the book exists before we then look to create or
317:00 - 317:30 update it right so let's put this up here and we'll say Boolean book exist equals there we go so we'll take the book dto convert into an entity we'll check if the book exists in the database using the isbm provided as the path variable here and uh we'll then look to create or update the book so we'll do a save based on whatever information is provided and
317:30 - 318:00 then we'll map that entity back to a d and then respond with either a HTP status okay in the case that the book already exists or our HTTP state is created in the case that we've created a brand new book because of course the create update book method is capable of both so before we can test this we need to implement is exists let's go over there and then get that stub great and now we'll call return Book Repository and we'll say Exist by ID lovely ISBN
318:00 - 318:30 great that's our method implemented so let's restart the application and go over to postman to test this functionality okay the application started fine let's go over to postman so we're in Postman and we can see the panel from when we created our book The Shadow in the Attic in the database and that's all well and good but let's just make sure everything works still so we're going to change the ISBN that's increase that from 1 to two and rather the shadow be in the attic I think the shadow is now in the basement
318:30 - 319:00 let's click on send and we're expecting a HTTP 21 created great 21 created the shadow in the basement but oh wait the shadow wasn't in the basement at all it was actually in the ballroom so we're going to keep the ISBN exactly the same up here and we expect it to stay the same but we expect the title to be different so if we click on send there we go the shadow is now in the ballroom with a HTTP 200 it looks like our update and our create working absolutely fine let's now write our
319:00 - 319:30 tests so we happen to now our test data youtil is set up so that the dto are the same as the entities so we're going to go test T A2 till do create test book entity a and then we won't pass in an author we will assign this to a variable which is uh test book oh entity a that will do and then we will now save this into the database we'll say book service do save no let's create update book now and we'll pass in the ISBN testbook
319:30 - 320:00 entity ISBN and then testbook entity a great we'll assign this to a variable which is called saved book entity let's just put that on a new line great so we now have this saved book in the database so we want to make sure that definitely 100% that our dto matches up so I'm just going to do uh test book a do set
320:00 - 320:30 ISBN making sure that it is the saved B entity. ISBN it should be by convention but just for document in the test and for it to be obvious and then we able to convert that into Json and then do the update here so it's not created anymore it is simply is okay so if we run this test we should expect it to pass okay looking good so that's it for the status we now need to make sure that
320:30 - 321:00 the object that's returned in the response body is what we expect it to be so again we're going to borrow this test and we're going to say test that update book returns updated book so like before we're going to have to create a book in the databas before we even start so let's uh let's borrow that and its entirety replace that there great so we now have a book in the database it's been saved and now we're looking to do an update we're making sure that what's returned is the updated
321:00 - 321:30 book so we know that both our entities and our dto from test data U should match up so let's say test book a dot set title of Simply updated there we go and uh if we take a look here the shadow in the Attic let's see that fail because we should see that the title updated is returned if this is working correctly so let's click on
321:30 - 322:00 play okay it's failing and the reason it's failing is expected the shadow in the Attic but was updated so that's a correct failure however I was taking a look here and it looks like we're using the string ISBN rather than the variable so actually that's a bit of a gure as well so let's make sure it is definitely using the ISBN as we've got here there we go and in fact I'm going to do the same for up here as well on our update great okay we'll change this to
322:00 - 322:30 be what we expected to be which is updated and we should expect this to pass looking good now we've changed a few things on here so I am going to take the liberty of running Maven on the command line to make sure that everything is still working absolutely fine so we'll do Maven clean
322:30 - 323:00 verify looking good so that is the fill up dat implemented for books Let's move on to the partial update for our author so that's the full updates done let's now move on to the partial updates so the partial updates if you remember we don't have to provide the full object in the request body we just have to provide whatever attributes that we're looking to update so in the case of the author if we only wish to update the name then we only provide the name in the Json object so let's now implement
323:00 - 323:30 this so in terms of what we're going to need we use the HTTP method patch for this the path is going to be identical to the fill update and then we have public response entity wrapping a author dto and we'll call this one partial update so we're going to need to have the path variable in use we want access to whatever is passed in in the URL here and we'll assign that to a long of ID
323:30 - 324:00 that'll be the ID of whatever author we are to update and uh we also need access to whatever is in the request body as well which of course we know to be an author dto or at least whatever fields of an author dto we care about so that is the signature dealt with what do we need to do in order to implement this well I think just like the full update we should check to see if the object actually exists in the database first and if not return a HTTP 404 that's what
324:00 - 324:30 we'll do just like above so in terms of this one we will want to first map from a dto to an entity so let's do that we'll call the author service we'll say the author service Dot and we'll say partial update I can see we've done it up here we set the ID on the object in the in the controller in the presentation layer now I feel like that's probably better done at the service layer so let's choose to do it for the partial update maybe changing it for the full update so we're going to
324:30 - 325:00 pass in the ID of the author to update and we're also going to pass in whatever the author DT provided is in order to update it with those values and that is going to return for us an author entity and we'll call that one updated author of course it's not going to be an author dto we pass in it's going to be the author entity we've converted so we've got our updated author entity so we now need to map that back so we're going to go author mapper Dot and then
325:00 - 325:30 we'll say map two passing in the updated author okay and then we'll return a new response entity passing in our author dto and then it's going to be HTTP status okay if everything has gone correctly great so this should be enough to do a partial update but the real complicated logic is going to be inside of the partial update method here so let's go inside of our interface and create
325:30 - 326:00 that looking good now let's go into our implementing class get that stub great great so the first thing I'm going to do is I'm going to take the author entity and I'm going to set the ID on it provided that's what we were doing in the controller before but actually is kind of business logic I suppose in a way I'd prefer it to be in here so here's where things get a little bit complicated in order to update what we have in the database we first need to retrieve what we have in the database and then update the attributes as provided so the first thing we're going
326:00 - 326:30 to do is we're going to use the author repository and we're going to say find by ID now we happen to know this should already exist we checked for it in order to return a HTTP 404 so what we'll do is go map and this will be what we'll call our existing author so we have our existing author how are we going to update the fields well the way that I like to do it for pretty simple objects like this is by going optional of nullable and then we can go author entity. getet and then
326:30 - 327:00 whatever we'd like to update which in this case because we're not going to do the ID but we are going to do the age and the name with this method so we're going to get the age so if the age exists so if present then we want to call the existing author and we'll say set age so what this is doing is saying if we find that the author entity as provided has an age and it's not null then we want to set that on the existing author as we found it from the database
327:00 - 327:30 and we're going to do exactly the same for the name as well so optional of nullable and we'll say author entity. getet name and we'll say if present we're going to go existing author get name sorry set no there we go and now we want to save our the existing author again just to make sure that anything that we've set on it is going to be updated in our database so we're going to say author repository do saave and then of course pass in our existing
327:30 - 328:00 author which is going to be what we return at the end here and then we will return this and in the case that the author doesn't exist in the database which we happen to know is very unlikely at this point but may be the case we're going to say or else throw and just for the moment I'm going to throw a new runtime exception and we're going to say author does not exist okay so this should be enough for
328:00 - 328:30 our partial update method let's try it out in Postman we can see that we have Maria Montgomery as renamed using our full update but we were mistaken it wasn't Maria at all it was always Arya so we're going to attempt to update this by using patch now so we'll flip this over from get to patch and then rather than Maria we're going to provide ARA but that's all we're going to provide not even the ID
328:30 - 329:00 in there just the name so we should expect what's returned here to be a the full object but we the new name of Arya Montgomery and HP status 200 let's try this out looking good it's Arya Montgomery and actually Maria was arya's middle name so we're going to do that and of course she's not yet 80 she is in fact only 79 so we're going to change that as well so let's send this expecting those two fields to be
329:00 - 329:30 updated looking good so yeah it looks like our partial update is now been implemented let's write our test for this so here we are in our auth controller integration test so we're going to test for the status code and we're also going to test that the attributes can be updated so let's start with the status code before we do so I'm just going to borrow from this test up here because it's going to be fairly similar indeed so let's create a new test and we're going to call this one public void test that partial update
329:30 - 330:00 existing author returns HTP status 200 [Music] okay great so what we have here then is we are creating our test author entity and we're saving in the database we have an existing author now of course we happen to know that our entities match up to our dto here at least when we're using our test data util so in fact let's just
330:00 - 330:30 uh throws exception so the dto matches the entity we've got our dto as Json so we're now performing but not a put but a patch to to for/ authors and then the ID of the author as saved for the sake of argument we are also going to change the test author dtoa let's set the name to be updated let's say it's not going to make a huge different in this test but it'll be closer to the real life example
330:30 - 331:00 so we're expecting it to be status okay so let's run this looking good so we get HP 200 which is what we saw inside of Postman now we're going to do the test to make sure that the body is updated so test that partial update existing author returns updated author so this is going to be very similar so we're already setting the name of the author in the dto to be updated which is how it's going to differ from the one already saved in the database we want to make sure that it is
331:00 - 331:30 updated in our Json body so we are going to borrow from up here once more replace this the ID is going to be the same the name is going to be updated and the value is going to be exactly the same age so we're going to say here test author dto a gauge so if we run this we should expect this to
331:30 - 332:00 pass great and just like that we have implemented our partial update for our author let's now do our book so let's now Implement our partial update for our books so we're in our books controller here we're looking at the full update that create an update we've got list we've got get book so let's now create a new endpoint this also using the patch mapping and the pass going to be exactly the same as the full update or the
332:00 - 332:30 create in case of the book we're then going to say public returning a response entity of the book dto [Music] and we're going to call this one partial update book let's get that path variable which of course is going to be uh ISBN and we'll assign that to a string called ISBN and then we're going to need that request body which of course is going to be a book dto and we'll just call that book dto so that's our signature now let's look to implement this so as
332:30 - 333:00 before we need to take that book dto and turn it into a book entity to work with our service layer and our persistant layer so we've done that conversion just like that now we want to check if that book exists yes just like above because if it doesn't exist then we need to return a HTTP status 404 because hey the book wasn't found you can't update a book that doesn't exist we'll say if the book does not exist which we could probably
333:00 - 333:30 inline then we want to return a response entity HP status not found okay what if our book does exist well in that case we want to do the partial update so we're going to say book service Dot and we're going to say partial update passing in the ISBN of the book and of course our book entity which will move the line down to here okay so this is going to
333:30 - 334:00 return us a book entity which we'll call uh updated book entity and then we need to map two so we'll say book mapper do map 2 passing an updated book entity and then we can return a new response entity containing our saved book dto and
334:00 - 334:30 then the HTP status of okay because the update went okay so this should be what we need to do in our controller let's take a look at implementing this partial update method shall we so let's create the method in our book service looking good to me let's now go to our implementing class and there's our method stub so as before first thing I'm going to do is
334:30 - 335:00 say book entity. set ISBN making sure it's the one provided as this argument here which comes from the Euro and now we want to do our partial update which of course means we need to get our book from the database so Book Repository and then we'll say find by ID passing in the ISBN and we'll do a map and we'll call this one existing book great so we'll now do how we did before optional of nullable checking the
335:00 - 335:30 book entity provided for uh in this case I think we'll support updating the title which we can do like so and then we'll say if present we'll say existing book set title we don't want to be able to update the ISBN and we don't really want to be dealing with the nested author in this case of course it's completely an option for you but I think we'll just make our tutorial a little bit more complicated so we'll just
335:30 - 336:00 update the title in this case and uh if the book doesn't exist so we'll say or else throw which needs a function we'll say new runtime exception and we'll say book does not exist but the chances of coming up against that are slim to none because we're checking inside of our controller at least how we're using the application now so let's return this and let's make sure that our book entity or our updated existing book
336:00 - 336:30 is Save which we can do by saying Book Repository do save passing in our existing book with all of its up upd dates and then we will say return great everything looks like it's compiling this is what we need for our partial update so let's go ahead restart our application and test this out okay the application started up let's go over to postman okay so here we are in Postman and we can see we've got a book existing in the database the shadow in the Attic with this ISBN right
336:30 - 337:00 here and let's now try this for a partial update so we'll go from get to patch go to the body and then we'll provide adjacent in the body but we're only going to provide the uh the title just like that and it's not the shadow in the Attic of course it's the shadow in the basement so if we send this we should find that everything stay the same except for the title which is now going to change to the shadow in the basement with HTP status 200 looking good that partial update
337:00 - 337:30 seems to be good for the book obviously we can update this as the book object grows out with additional attributes additional instance variables so that's all good let's now write our test for this okay so here we are in our books controller integration tests I'm going to borrow this because we're going to be using something similar in our mock MVC and now let's write a test and we'll say test public void test that partial update book returns HTTP status 200
337:30 - 338:00 okay okay and we'll say throws exception great of course we do need an existing book for this so let's get the necessary bits we need to make a book exist in the database there we go which is testbook entity a so we're going to need to send some Json in our request body for this one so let's see if we can borrow something from up here to make that easy for us this should do there we go so we can see that our testbook dtoa of course
338:00 - 338:30 matches our testbook entity that's how we've set it up and we have here the we don't set in the ISBN on the saved book entity um and then we're setting the title to be updated in this case in fact let's let's not do that let's just make sure it's just a title that's being updated here change it to book Json now we're going to make use of the patched HTTP method to books plus the ISBN of the saved book entity great and then the content of
338:30 - 339:00 course is going to be the book Json with the title being updated we're expecting is okay do we get is okay we do excellent so that seems to be working absolutely fine now let's look to yes let's assert on the response body now so we'll take this test because this next one's going to be very similar test that partial update book returns updated
339:00 - 339:30 book so creating a book and then we're updating the book dto which is then going to be different from the book in the database and then we are creating some Json from that dto and then we're patching it to the right ISBN everything is good the only thing that's going to be different is going to be our assertions so let's go down oh go up here borrow these we're not using a list we just have an object so the ISBN is going to be exactly the same ispn is our testbook
339:30 - 340:00 entity. getet ISBN however the value is going to be updated because we're updating it right here so if that's returned then our test should pass let's try again looking good so that is the partial update implemented for our book now we get to move on to the delete Ando
340:00 - 340:30 so let's Implement our delete endpoint for our author so here we are with the last letter in the the crud acronym we've done our create we've done our read one our read many we've done our update partial and our update full we now have the plain and simple delete so let's Implement our delete for our author here so we're in our author's controller we are going to need to use the delete mapping the path that's going to be absolutely the same as the path that we've used so far with the ID provided
340:30 - 341:00 in there like that now we're going to say public response entity but but we're not really going to be returning much in there but it's going to be no body we can just provide the response entity like that now we're going to call this one delete author and we're going to need to get hold of that path variable ID because we need to know which author we need to delete and now we can get to deleting our author so we're going to go
341:00 - 341:30 author service Dot and we'll say h well we don't have one yet we're going to say delete and we're going to pass in the ID of our author which is a void method it's not going to return anything so we're going to then return a new response entity and in that response entity it's just going to have an HP status of no content 204 204 no content wonderful so let's
341:30 - 342:00 Implement our delete method on our author service so we'll go create method delete void delete long ID looking good we need to go to our implementing class very nice and now we'll need to delete which of course is very easy with spring data jpa we can go delete by ID passing in the ID as provided and uh We've deleted our object we've deleted our author very nice so that is all we need to do to implement our delete method on our author controller Let's
342:00 - 342:30 test it out so let's restart our application okay that's restarted absolutely fine let's go ahead and open Postman so here we have Arya Maria Montgomery in our database one of our saved authors we do that on our G one endpoint we can see that she has returned HP status 200 everything looks fine so let's now delete this author so we go up here we'll click on delete past St exactly the same anybody that we send is going to be ignored but let's send
342:30 - 343:00 this there's our htb status 204 no content everything seems fine but to test this we need to do a get again if we get our author back then the delete didn't go through the delete failed however if we don't get anything back create HTP status 404 then our delete worked let's try this out HTP status 404 our delete endpoint Works absolutely fine let's write a test for it now okay so we're in our auth controller integration test at test we'll say public void test that delete
343:00 - 343:30 author returns HTP state 204 when that'll be enough HB status 204 so for this then we will need to Let's borrow this from up here we need to do a delete for SL authors and then the ID of an author which can be an existing author or an author that doesn't exist so we're going to say tested Elite author return uh for nonexisting author
343:30 - 344:00 and we'll simply just make up an ID because we said that actually a delete is still successful if there's nothing to delete because at the end nothing exists so that's a successful delete we'll test it out at least we test it so the content there's no content provided here but we are going to expect
344:00 - 344:30 status is no content and and we'll just add exception to our method signature so let's run this pass is absolutely fine now let's do the same but with a author that already exists when existing author so for this we'll actually need an author in our database so we can do that like so so we have test author entity a now
344:30 - 345:00 in our database so I'm going to say saved author and I'm going to say saved author. get ID making sure that it's going to try and delete the existing author so we'll click on play looking good so our delete seem to be working absolutely fine let's now move on to implementing our delet for our book so we're now going to implement our delete endpoint for our book and this might be the quickest run we'll do so let's try it out we're going to go
345:00 - 345:30 delete mapping the path is going to be exactly the same as the one that we've seen with the isbm provider and we're going to now go public response entity we're not going to specify any generics for this because nothing's going to be returned it's no content and we're going to call the method delete book now of course we need a path variable we need to know which book we're deleting we can do that by assigning it to the argument ISBN here and now we need to delete our book which we're going to do by calling the book
345:30 - 346:00 service do delete passing in the ISBN that of course is going to be a void so we need to return a new response entity and uh that response entity is going to be HTP status and we'll say no content just like before so let's now create delete on our interface then go to our implementing class and we'll want to create it there too great again it's going to be a pass through Book Repository delete by ID
346:00 - 346:30 passing in the ISBN and we're implemented so let's try this out in Postman let's restart our application okay that's restarted let's open up Postman okay so here we have our shadow in the basement book with this ISBN so if I do a get we HP status 200 if I do a delete get 204 no content if I try and do a get once more 404 not found so it looks like our delete is working fine
346:30 - 347:00 for our book let's write our test for this one so here we are in our book controller integration test and we're going say at test public void test that delete nonexisting book returns HP status 204 no content and we'll borrow this from up here we're going to provide an ID of a
347:00 - 347:30 of a book that doesn't exist and we're not going to provide any content but but we are going to say and expect result mock MVC result matches do status to be no content and of course we need to add exception to the method signature and then click on play here okay we got a failure I wonder why that is Let's Take a
347:30 - 348:00 Look expected a 204 but was a 400 because you're using patch and not delete let's try once more great that's working fine so let's copy this and we're going to say test delete existing book returns HTP status 204 no content of course we're going to need to create a book in our database which we can do by borrowing this up here and then we'll say testbook entity and then rather than this made up ISBN
348:00 - 348:30 we're going to say testbook entity. getet ISBN still expecting HTP status four uh 204 let's run this looking very good so that is US implementing a very basic crud for both our books and our authors now let's just run Maven on the entire project to make sure everything's working
348:30 - 349:00 fine got a build success so there we go so we've got a couple C of additional things that we want to clean up one of them being our nested objects and the other one being pagination so we're going to move on to those right now so so far we've shied away from manipulating nested objects when we are dealing with our crud endpoints here so what I mean by that is we haven't tried creating a book and then also creating an author we haven't tried updating a book and then also updating the author
349:00 - 349:30 that goes along with it and the reason for that is pretty simple we haven't configured our model mappers correctly yet or at least we haven't configured it to do to support this so out of the box spring data jpa allows you to update nested objects we've already seen that inside of our spring data jpa part of the tutorial here if we were to for example restart our application now I have taken the liberty of clearing down the database to make this super obvious we'll see that actually this is a mapping configuration problem and not
349:30 - 350:00 necessarily a spring data jpa problem so application's restarted let let's go over to postman so we have here an endpoint which is going to list all of the books in the database if we hit this we get a 200 but we get an empty list there's nothing in there if we do the same for the authors we get a 200 but we get an empty list because there's nothing in there so if I wanted to create a book and then also create an author something we've done quite a lot when we were dealing with our persistance layer with spring
350:00 - 350:30 data jpa which of course our presentation and service layer uses it should be easy right it should be obvious how we do that well it should be so we're going to create a book which we know we're going to do with put and then we're going to go for/ books we need to provide an ISBN we know there's nothing in the database so any ISBN will do at this point and then we're going to oh there's already an object for us that's handy let's make sure that the ISBN matches it will be updated anyway the shadow in the Attic looking good and now for our author as our nested object we
350:30 - 351:00 know that our author we don't really need to provide an ID for it so uh I'm not going to and and our author has a name we've gone with Arya so far so let's say Fred Fred the author so it has a name and the age is going to be let's say 14 Fred Fred started at 14 well Fred has published a book at 14 good going Fred what we're expecting to do when we do put here is
351:00 - 351:30 we want the book to be created but we also want the author to be created and then an ID generated for it then our author to be referenced by our book now remembering earlier in the tutorial when we set up our database manually we set some constraints in there those constraints don't exist by using hibernate autod ddl to uh generate our schema for us so we can potentially have a book without an author the the the author could be null of course that's not what we want in this case let's send this and and see what we
351:30 - 352:00 get the authors null because you've seen this quite a lot based on us implementing our crud endpoints there are authors so if we open up a new tab here go HTP local hostbooks there's our book with our author of null but if we then try and do the same for our authors there's no authors so how do we set it up to do that well it's all to do with our model mapper so we know DDOS are a good idea but the model mapping and the mapping from Two and fro is extra overhead we know that but it does pay
352:00 - 352:30 off depending on the size of the project so I'd rather show you the full-blown approach in this tutorial so the model mapper here is mapping from an author entity to an author dto looking good and then the same for the book so it's going from the uh book entity to the book dto and back again but we know that the book dto and the book entity they they reference the author entity and the author dto so why isn't it handling the nested object conversion well it's because we haven't told it to so if we
352:30 - 353:00 go up to the mappa config up here we're simply just returning a new model mappa but what happens if we were to I don't know let's assign that to a variable and then we can configure this now the particular incantation that we need for the model mapper is this so we're going to use the matching strategies loose and that's going to match supposedly nested objects and allow us to convert from one to the
353:00 - 353:30 other so what this will mean is when we send a nested object within the dto it will then be converted to a nested entity object and that is all spring data jpa needs in order to then Cascade do those saves do those updates really harness the power of those nested objects and spring data jpa so with this being done let's now restart our application back to postman and then try this again so we've already created the shadow in the Attic So let's uh let's get a new
353:30 - 354:00 ISBN and let's put that up here Shadow attic is now the shadow in the basement still Fred the author and he's published his second book at the age of 14 good going Fred so we now expect with this changeing configuration for Fred to be created as an author in the database let's give this a go okay we've got a 2011 created and we can see here ISBN shadow in the basement and now an author has been created with the idea of one generated for us Fred
354:00 - 354:30 the author age of 14 so we've now enabled the uh ability for the dto to be mapped at entities with nested objects which then means that we can harness spring data jpa to do all of those Cascades to our nested objects so if we just double check that if we go over to authors here click there's Fred the author go over to books here there's our two books our original one with a null author and then this one here our new one with Fred the author as our
354:30 - 355:00 reference author so we mentioned before our list end points return all of the entities so in the case of the list books endpoint it returns every single book in the database if that's no books if that's one book or if that's 10 billion books and obviously the more books that it needs to return the more resources that requires and that can mean things like crashed databases crashed app servers or just wait times which means that users get really bored and then go and do something else so where we can we want
355:00 - 355:30 to set limits to the number of entities that returned on those list endpoints and one of the easiest ways that I know to deal with this is by making use of pagination and pagination is built into spring data jpa and spring web it's one of those things that goes all the way out the chain it's really simple to use let me show you how to use them so we're going to start over at repository and we're going to do this in the Book Repository now remember I said before depending on what repository you extend it depends on which functionality you get access to now in the case of the
355:30 - 356:00 crud repository we get access to to crud create read update and delete now we're going to also extend putting that on a new line the paging and sorting repository dealing with our book entity and also our strings here and just like that we have access to some additional methods so we take a look in here we can see we have access to find all and uh this takes a sort we also have find all that takes a pageable and returns a page this is the one that we care about so
356:00 - 356:30 let me show you how this is used if we go to the book service so we have our find all method already we're going to overload this with a different return type so rather than a list of book entities we're going to say a page of book entities we need to import page and we'll do that and then we'll say find all and we're going to pass in here a pageable pageable there we go and this pageable
356:30 - 357:00 object contains information so it's uh things like the sort the offset there all that good stuff and the page is like a list and then there's some additional metadata around that we need the pageable in order to inform what is in the page so that's inside of our service now let's Implement our method we'll do that next to the old one and uh we'll simply call Book Repository doind all passing in our pageable and we'll just return this it
357:00 - 357:30 will be a pass through got a find all let's go up to our book [Music] controller and we'll go to our list books endpoint so list books returns a list currently we're going to turn that to a page of books and now we need access to our pageable it's pretty great because if we put pageable in here spring is going to inject that for us so we have access to our pageable thank you spring and we're
357:30 - 358:00 going to put that inside of find all it's of course not going to return a list anymore this is going to return a page and now we have to deal with our page so we have a page of book entities at the moment we want to page of book dto so we're going to map this and then to our book entity in fact we'll just go book mapper and we'll say map map two it's map two it's that way around and then we'll return
358:00 - 358:30 this just like that so in fact it's a lot simpler so we're doing that find all and uh we're returning that page in this case of book dto so let's restart our application and I'll show you how this differs okay let's go to postman okay so we'll see what books we have in our database so this is uh this is the old list books endpoint so you can see here it's just a Json array with Jason objects in there and then we've got a
358:30 - 359:00 couple of books one with an author one without so if we click on send now we you can see the structure is a little bit different we have this content node or this content attribute and it contains those two books but we also have minimize that this pageable information I have total Pages the number of elements the size which in this case is 20 and this is all of our page metadata now we only have two books in the database at the moment so I'm going to take the liberty of just creating a few more okay so there is a
359:00 - 359:30 few more now in the database so if we go down here we can see that we've got total elements of two at the moment if I hit send again scroll down to the bottom we've got a total elements this time of 40 so we have 40 in here uh or do we there certainly a lot more of them with some pretty pretty poor data in there but there is there is there is many and that's really what we want so we've got many of these we've got 40 all together and we've got 20 being returned and we
359:30 - 360:00 now have access to a couple of query parameters which allows us to control this even further so if we were to say size equals 2 and we take a look at our content here one book two book and then our pageable metadata that's it we say page equals one we only get one book per page so this is the book on page one and if we say page two we get a different book page three get well different ISBN same book with
360:00 - 360:30 uh with terrible data ultimately this allows us to control the size of the page and then which page we currently viewing which is allows us to limit the amount of elements that's being returned by our API and you can tweak these variables to return whatever you like really zero index for page uh you can see here we've asked for 100 elements we've only got 40 so we get all of them returned and if we ask page two it's going to be empty because well we're on page two or we're going to go from 100
360:30 - 361:00 up to 200 and they don't exist so we don't get them back and uh this is a much more efficient way of dealing with large quantities of data on our list end points and there are some other nice built-in extra features to this as well and one of those is sorting which is sort of about the scope of this but just know that there some additional query parameters which allow you to sort the items that returned and just like that we have pagination so if you stuck with me so far thank you so much and congratulations we've implemented a crud API and we've even talked about some additional features like the model
361:00 - 361:30 mapping for nested objects and we've even talked about pagination as well to take your API to the next level so we have an API we've built it it's great and it's running locally but how do we deploy it well let me show you one way of deploying it to AWS so we've built our rest API let's deploy it to AWS so we can hit it and show other people rest API now there are a number of different ways of doing this I'm going to choose to package up my application in a Docker container and we're going to be using AWS light sale
361:30 - 362:00 today in order to host the docker container and make it available for us to hit so first things first we need to package our application up in a Docker container and we need to go to our application here create a new file and we're going to have a Docker file here so we are now going to create ourselves a Docker file to be able to package our application up in Docker so here we have perhaps the simplest Docker file that I can think of for a spring boot application now this isn't a Docker
362:00 - 362:30 tutorial so not going to go into the myriads of different ways that you can optimize your application and believe me there are a lot lot of ways inside of your Docker file but let me just talk you through what this does so we're building on top of the open jdk version 17 we know about version 17 because that's what we've been selecting so far in our spring initializer so we want Java 17 the maintainer which in this case is deo.com and then we're going to copy inside of our Target directory our jar file into app. jar bear in mind we'll need to have a jar file available
362:30 - 363:00 before we run Docker build and our entry point is going to be Java jar and then app do jar again there are loads of different ways of doing this however this is probably the simplest and it should work so what we're going to do now is we're going to open up a terminal and we are going to say Maven clean and package and this is going to create us a jar file okay so we now look in our Target
363:00 - 363:30 directory [Music] yep we have it's called database we should probably update that by now we have our database snapshot jar file so this is what we're going to need for our jar file it exists it's in our Target directory the name of it doesn't matter too much for the time being okay so now what we're going to do is we're going to go back to our root directory of our project where our Docker file is located
363:30 - 364:00 and now we're going to go Docker build in the current directory pointing to the docker file T and then our tag is going to be Devo slash books okay now if we do Docker image LS we can see that we have the Tio books the latest version and it was built 5 seconds ago so we have our Docker container built that's great let's now get this into light cell so we can run
364:00 - 364:30 it now remember we are needing a database to run our application so we're going to need to configure that as well but let's do that so let's flip over to lightell so I've logged into my AWS account and here we are in light cell so we're now going to go to Containers here and we're going to create a container service so uh for the sake of this we are going to choose a nano is absolutely fine we're only going to need one of them of course when you're using this bear in mind there may be a cost
364:30 - 365:00 associated with it it should be very very clear and now we need to identify our service so we're going call this one Dev Tio books okay we'll set up our deployment after it started let's create our container service okay so we're at to getting started here we have our Docker container on our local machine so we have already installed Docker that's all good we already have the AWS CLI installed or at least I do make sure that you follow these instructions
365:00 - 365:30 otherwise and now we need to push our container images to light cell and this is the incantation for it here AWS light cell the region that you're running in and the service name the label and the image so going to take this and we can start filling these in so we're going to push the container image the region that we're going to push to is the region that we're running in region at the moment is EU West 2 so we're going to say EU West 2 service
365:30 - 366:00 name which we we know it's Devo books and then the label which we'll also say is Devo books and then the image which is our local container image and then the tag so we know that to be Devo books and then [Music]
366:00 - 366:30 latest okay so that is now pushed there we go and we can see it in images right there so that looking good so we now need to create a deployment before we do that let's create ourselves a database we'll have a postgress database we'll have a standard database and we'll call this one uh Devo books and then we'll create our database Theo books DB okay so that is in the process of being created okay so our database is now up and running so we need to take a
366:30 - 367:00 look at some details cuz we're going to need these a little bit later so let's go to our IDE let's open up a new [Music] file and we'll take note of the endpoint and put that in here we're going to need the username and we're going to need the password this password and this instance will be long gone by the time that you see this so don't try connecting to this so keep that password there so that's
367:00 - 367:30 our endpoint that matches up fine uh Port 5432 to public mode is disabled to only light cell resources in the same region can connect to this instance all looking good to me so that's good let's go over to our containers and we'll go into container Dev books we need to create our first deployment H we'll call the container name Devo books why not we'll choose the stored image that we've got in there
367:30 - 368:00 launch command we leave as the default inside of the docker container and we'll add now some open ports which are going to be the default Port of at80 which we know from Postman is the port that the application runs on and now for the environment variables so we mentioned before that we can inject configuration into our application by using environment variables and that's exactly what we're going to do so we're going to back to our IDE we need to know the Endo uh we need to know the username
368:00 - 368:30 and we need to know the password so let's go in fact let's go to our source main resources application properties and we can see how these match up right here so let's start with the URL so the key for this is going to be spring underscore data source underscore
368:30 - 369:00 uro and it's in this format here so we go back to our scratch and then up dat this to include and we're just going to connect to the postgress database to begin with so this should be the correct value for us now let's add another one so we now need to specify the username that we're going to be using so like an application properties it's spring data source username in fact let's do it here it's easier to see so we'll uppercase this change the dots for
369:00 - 369:30 underscores place that in there and then we'll place the value in there that was easier and then we'll do the same for the password which we know is spring data source password we'll uppercase that underscore underscore and then let's place that
369:30 - 370:00 password in there like that arguably you might want to use some kind of Secret Service we're just going to put it in there for the time being and then 8080 s Dev books on the public endpoint looking good to me we'll say for SL books and now we'll save and deploy so after quite a while the application failed to start up and the reason is the health checks didn't pass so if we go to show details here the health check simply needs to return a
370:00 - 370:30 success status code uh in order to show that the application is up and running if we look at the logs here we can see that we expand this deployment took too long and we scroll up health checks failed Port 880 is unhealthy and it's simply just not starting up fast enough and it may well be because there's not enough memory and it may be because of the settings now I can tweak the settings that may take a bit of time however I am going to choose to attempt
370:30 - 371:00 to update the uh the amount of memory used so going to go to a micro instead okay and the status looks ready so I'm going to modify and redeploy this leaving everything as it was before for/ books lists our books borish returns a HTP 200 remember so this should be okay so that's save and
371:00 - 371:30 redeploy we have a running application so I had to make a few tweaks to the settings so if we go inside of the deployment here show you some details in addition to increasing the size of the uh of the instance which then gives us some more memory to play with things then tend to run a bit faster I've I've made some tweaks here so we're still using the for/ books a health check endpoint CU that will always return a HTTP 200 um I've changed the check timeout seconds to 12 so it has up to 12
371:30 - 372:00 seconds to respond to that call and the health check interval seconds is now 12 seconds in between these are very LAX okay so uh these these These are quite forgiving in terms of settings so between 120 seconds between each check and um yeah we've got up to five five checks before it's unhealthy and I've done this because because of the size of the instance that we're using it's taking a bit of time for the application to start up and that's what it needed but yes if we go to open
372:00 - 372:30 logs we can see here's a logs V application and eventually application starts up and it connects to our postgress instance which we've got there running on Port 880 everything looks good so now our applications up running in AWS let's try hitting it in Postman so I'm going to take the public domain up here so let's attempt to create a book and an author on our application running in AWS now a little Quirk I've noticed of this is we need to change it to https and uh it will go do a put to
372:30 - 373:00 the for/ books endpoint with this ISBN and we're going to provide the title the shadow in the basement and our author is going to be Fred the author age 14 and of course no ID is going to be provided so we're expecting to get a HTTP 2011 created let's send this now okay we've got HTTP 2011 created so if we go to our authors change that to https and we'll go for/
373:00 - 373:30 authors we've got ARA Montgomery that I created as a test a moment go and then we have Fred the author right here now if we go to/ books we can see that shadow in the basement exists so our application is up and running as we built it locally but now it's running inside of AWS inside of a Docker container congratulations that brings our course to a close now if you feel you've taken some value from today's course be sure to like And subscribe because that will allow us to
373:30 - 374:00 make more courses just like this now if you do want to see another course on lombok which is a library we've used throughout this course then be sure to check it out over here it will talk you through all of the annotations how to use them and allow you to become a much more efficient Java developer I'll see you over there