# Spring Boot Project: Build a REST API for an E-commerce Platform

## Метаданные

- **Канал:** Programming with Mosh
- **YouTube:** https://www.youtube.com/watch?v=EWd3_I4X32g

## Содержание

### [0:00](https://www.youtube.com/watch?v=EWd3_I4X32g) Segment 1 (00:00 - 05:00)

Welcome to part two of the ultimate Spring Boot course. In part one, we covered the fundamentals, things like dependency injection and working with relational databases using Spring Data JPA. With that foundation in place, you're now ready to take the next step, building real world APIs. In this part of the course, we're going to build and deploy the backend for an e-commerce application. We'll build a clean, well ststructured REST API using best practices. You will learn how to implement authentication and role-based access control, how to handle payment processing with Stripe, and how to structure your codebase like a professional developer. If you're looking for a comprehensive, easy to follow, well ststructured and practical course that takes you from zero to hero, this is the right course for you. Just like part one, this course is packed with hands-on lessons, capstone projects, and real world exercises designed to help you truly absorb what you're learning. If you're serious about becoming a Springwood developer, this part will give you the experience and confidence to build and deploy production grade applications. I'm Mash Hamadani, a software engineer with over 20 years of experience. And I've taught millions how to code and become professional software engineers through my YouTube channel and online school codewithmarsh. com. If you're new here, make sure to subscribe as we upload new videos all the time. If you're ready to take your spring boot skills to the next level, let's jump in and start building. Now, let me explain how I've structured this course so you always know what's coming next and how each section builds on the last. We'll start with a quick introduction to how the web works and how Spring MVC helps us handle web requests. If you have never done web development before, this section is a great introduction and explains all the essential concepts you need to know. Next, we'll learn how to build REST APIs, which are simply the parts of your application that expose data and functionality to clients like your front end or a mobile app. Then we'll move on to validating incoming data. Making sure users don't send us invalid or incomplete information like a product with no name or a negative price. This is a critical part of building reliable APIs. After that, we'll build a shopping cart system just like you would find in a real e-commerce application. You will learn how to let users add products to their cart, update quantities, and clear the cart when they are done. Next, we'll protect our APIs so only logged in users can access certain parts of the application. You will learn how to handle user authentication, password security, and restrict access based on user roles like admin versus regular user. With authentication in place, we'll move on to building the checkout and order features. So, users will be able to place orders and we'll make sure that they can only see their own order history, not anyone else's. Then we'll integrate Stripe to process real payments. We'll generate a checkout page, handle payment results, and make sure everything updates automatically once the payment is complete. Finally, we'll take the whole project live. We'll deploy the application and database to the cloud, configure everything for production, and test the live version using Postman. This way, you will understand how real applications go from your laptop to the real world. By the end of this course, you'll have a productionready e-commerce backend with proper architecture, security, and deployment. But more importantly, you'll have the skills and confidence to build real world Spring Boot applications from scratch. Before we dive into Spring Boot, let's quickly go over the prerequisites for this course. This is an intermediate level course, so there are a few things you need to be comfortable with to follow along. First, you should have a solid understanding of Java. You should be comfortable with concepts like classes, interfaces, and object-oriented programming. If you need a refresher, I've covered all of these topics in my ultimate Java series. I put the link below this video. Next, you should have a basic understanding of relational databases. You should know concepts like tables, primary and foreign keys, relationships, and writing basic SQL queries. If you need a refresher on databases and SQL, check out my complete SQL mastery course. Again, link is below this video. Now, because this is part two of my spring boot series, you should ideally have completed part one or be familiar with concepts like dependency injection and beans, flyway migrations, entities and relationships, repositories, and writing custom queries. If you're not familiar with these concepts, I highly recommend watching part one of the course before continuing. You'll find the link below this video. Now, assuming that you are the right student for this course, now let's get started.

### [5:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=300s) Segment 2 (05:00 - 10:00)

All right. Now, let's set up our development environment and look at the source code we'll be using in this course. I've created two GitHub repositories for this course. We have the Spring API starter repository, which is the project we built in the first part of the course, but I've done some cleanup and removed some of the playground code we had before. This will be our starting point. So, you will clone this repository and code along with me. Then we have the finished repository which contains the full project we'll build by the end of the course. In this repository, we have a commit for each lesson. So in case you get stuck, you can always compare your code with the code I write in each lesson. So head over to github. com/madani/spring API starter. Now under code, let's grab the URL for this repository. I have set up SSH on my machine, so that's what I'm going to use. But in case you have not set this up properly, you can grab the https URL. Copy this. Now open a terminal window and somewhere on your machine, type git clone and paste the URL. Good. So in this folder, we have spring API starter. Now in this course, just like the first part, I'll be using IntelliJ Idea Ultimate. You can use any ID you like, but I highly recommend IntelliJ because it has built-in support for Spring Boot and makes development a lot easier. Also, throughout the course, I'll be showing you a lot of IntelligJ shortcuts and useful tools that will speed up your workflow. So, if you want to follow along, I encourage you to use Intelligj as well. And by the way, if you're using the community edition, you won't get some of the features I'm going to show you in this course. Okay, so let's go ahead and open our project. All right, here's our project. Let's open it. All right. Here's the project that we built in the first part of the course. But I've done some clean up and removed the stuff we don't need anymore. So here in the source directory, we currently have two packages, entities, and repositories. In the entities package, we have address, category, product, profile, and user. I've removed the tag entity because we're not going to use that in this course. We had it in part one only for you to practice many to many relationships. Now in the repositories package, we have a repository for each of these entities. Our repositories are empty. So we don't have any custom queries here. We'll add them as we go through this course. Okay. Now in the resources directory under migration, we have a single migration. So I merged all of the migrations that we created in the first part into a single migration for creating our database tables. Now let's go to application. yamel and update our database settings. So in this course just like the first part we are using MySQL as our database engine. So make sure you have MySQL on your machine and then set the username and password to whatever you have configured. Now let's run the application with control and R. Intelligj is suggesting to enable annotation processing. This is for Lombok. We covered this in part one. So let's enable that. Good. Now we don't have any errors. Our application started on port 8080. If we head over to localhost port 8080, we get a white label error page because we haven't built the homepage yet. Now back to Intelligj, let's verify that our database tables are created properly. So we open the database window and add a new data source to MySQL. On this window, we set our credentials and set the database name to store underline API. Now let's test the connection. Succeeded. Beautiful. Okay, here's our database. And in this database, we have seven tables. So this verifies that Flyway successfully created our database. Now let me give you a few tips on how to get the most out of this course. This is a hands-on project-based course, which means you should be coding along with Spin right from the start. There is a lot we're going to build and a lot of new concepts to absorb. This isn't a course you can just watch passively. If you really want to learn and retain the material, you need to be active. Now, to keep the course efficient and respect your time, I've edited out long pauses, repetitive typing, and other distractions. You'll also see me use Intelligj's autocomp completion a lot to write code quickly. If you're not fast with your keyboard or if you ever feel like the videos are moving too quickly, here's what I recommend. Watch the lesson once, take a few quick notes, and then go back and code it at your own pace. Now, throughout the course, you will see plenty of exercises and capstone

### [10:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=600s) Segment 3 (10:00 - 15:00)

projects. These aren't filler. They're where the real learning happens. If you just watch the videos, you might feel like you're keeping up, but unless you pause and try things on your own, you won't learn much. So, please take the exercises seriously. They will help you build confidence and make everything stick. Quite frankly, this is a big course and there's a lot to learn. Don't feel like you need to rush. Take your time, practice what you learn, and go through it at a pace that works for you. All right, now let's jump in and get started. Welcome back. In this section, we're going to explore Spring MVC. That's a framework within the Spring ecosystem that's designed for building web applications. We'll start by understanding how the web works. In this lesson, we'll cover some of the key concepts and terms used in web development. If you have never done web development before, make sure to watch this lesson. It will give you the foundational knowledge you need to follow along. After that, we'll talk about what Spring MVC is, its building blocks, and we'll see them in action. You'll learn how Spring Boot can be used to build both traditional web applications as well as modern APIs. By the end of this section, you'll have a solid understanding of how Spring MVC works and how to use it to build web applications. Now, let's jump in and get started. Before we dive into building web applications with Spring Boot, let's take a step back and understand how the web actually works. If you have never done web development before, this lesson will give you the foundational knowledge you need. When you open a website in your browser, your computer called the client sends a request to another computer called the server. The server then sends back a response which the browser displays as a web page. Now this communication happens using a protocol called HTTP which is short for hypertext transfer protocol. It's just a set of rules that computers follow to send and receive data over the internet. So every time you visit a website, your browser sends an HTTP request to fetch the page. The server processes the request and sends back an HTTP response with the content of the page. Now, what's inside a request and a response? Well, an HTTP request typically has a few key parts. It has a method which specifies what action you want to perform. The most common ones are get to retrieve data and post to send data. An HTTP request also has a URL, which is the address of the resource you are requesting, like google. com or amazon. com/roucts. An HTTP request also has headers which contain extra information sent with the request like what kind of browser you're using or authentication details. Now an HTTP request can optionally have a body that contains data for the server. This is used when we need to send information to the server like when we submit a form. Now the response from the server also has a structure. The response has a status code which tells us whether the request was successful or not. There are many status codes but the common ones are 200 which means okay everything worked. We also have 404 that means not found. You have probably seen this before. An HTTP response also has headers that include metadata about the response like the type of content being sent. An HTTP response also has a body and this is the main content returned by the server. It could be a complete web page or just some raw data depending on how the application is designed. Now let's talk about how web pages are structured and how they are delivered to the browser. Web pages are built using a language called HTML which is short for hypertext markup language. HTML defines the structure of a web page like what text appears where images go and how different elements are arranged. Now there are two ways web pages can be generated and displayed to the user. One way is for the server to generate the entire web page before sending it to the browser. This is called serverside rendering or SSR. Meaning the rendering or generation of a web page is done on the server. So the server builds the page with all its content and structure and then sends it to the client. This is how traditional web applications have worked for a long time. The advantage is that the page loads completely when it arrives and search engines can easily understand it. But there is another way modern applications work. Instead of sending a fully built web page, the server can just send the raw data and let the client or the browser generate the page itself. This approach is called client side rendering or CSR. Meaning the rendering or generation of the page is done on the client. Okay. So in this case, the server doesn't return an HTML page, but instead sends data in a format called JSON. That's short for JavaScript object notation. It's the syntax we use for representing objects in JavaScript.

### [15:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=900s) Segment 4 (15:00 - 20:00)

So we represent an object with curly braces and inside the object we have a bunch of key value pairs. So in this approach the server sends data as JSON and the JavaScript code running in the browser then takes the data and dynamically generates the web page. We use JavaScript frameworks like React, Angular and Vue to take care of rendering of the page in the browser. Now this type of interaction where the server provides raw data instead of a full page is made possible through something called an API. An API or application programming interface is simply a way for applications to communicate with each other. In this case the back end exposes an API and the front end which can be built with React, Angular, Vue or other frameworks consumes it to render web pages. But APIs aren't just for front-end applications. Other applications like mobile apps and even AI agents which are getting very popular these days can consume APIs to retrieve and process data. Now you might be asking where does Spring Boot fit into all of this. Well, with Spring Boot we can build both types of backends. We can build a server that generates and returns a full HTML page, meaning SSR, but we can also build a server that returns raw JSON data and allow clients to generate the web page. That's CSR or client side rendering. In this section, I'm going to show you both approaches. But because APIs are the modern approach, for the rest of the course, we'll primarily focus on building APIs with Spring Boot. Now that you understand how the web works, let's talk about Spring MVC. Spring MVC is a framework for building web applications. It gives us all the tools we need to handle HTTP requests, generate web pages, and return data to clients. It's part of the larger Spring ecosystem, and Spring Boot makes it really easy to use. But why is it called MVC? Well, MVC is short for model, view, controller. It's a popular design pattern for organizing our code and making it clean and maintainable. In Spring MVC, we have three main components, model, view, and controller. The model handles the data and business logic. The view is what the user sees like an HTML page displayed in the browser. And controller is the middleman. It takes a request, processes it, and decides what response to send back. Here's what happens when a user visits a web page in a Spring MVC application. Let's say the user opens example. com/books in their browser. The browser sends a request to the books endpoint. Spring MVC receives the request and passes it to a controller that's listening for requests to the books endpoint. The controller processes the request. It might talk to a database and fetch some data and then it returns a response which can be an HTML page or some JSON data. This is how Spring MVC organizes our code to handle requests efficiently. Over the next few lessons, we're going to see each of these building blocks in action. So, here is the current homepage of our website. We don't have a homepage. Now, let's see how we can use a controller and a view to build a homepage for our website. Back to our project, we go in the source directory main java and in this package we add a new package called controllers. Now Java class called home controller. Now to make this a controller, we should annotate it with the controller annotation that is defined in the stereotype package. With this annotation, we are marking this class as a bean. We talked about beans in the first part of the course. But let me give you a quick refresher. A bean is an object that is managed by a spring. So when we mark this class with the controller annotation, we're telling Spring that this is a bean. So when the application starts, Spring will be able to create an instance of this class and manage that instance. Okay. Now to handle requests sent to our homepage, we add a method here, public string. That's the name of the view that we want to return. We can call the method anything we want, but by convention, we use index for the homepage. Now here, we should return the name of our view, which should be an HTML file. So let's change this to index. html. HTML. Next, we should annotate this with request mapping and as an argument, we provide an endpoint. A forward slash represents the root of our website. So when the user sends a request to the root of our website, this method will be called and then it will return index. html to the client. Okay. Now

### [20:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=1200s) Segment 5 (20:00 - 25:00)

let's build this view. So back to our project, we go in the resources directory and add a new directory called static. This is where we add our static resources like HTML pages, CSS files, JavaScript files and so on. Now in this directory, we add a new file index. html. Now to generate HTML content, we type HTML col 5 and press tap. So here we have a basic HTML page. We press tab. And here inside the body element, we add a heading. So we type H1 and press tab. And in between these tags, we type hello world. Now don't worry if you're not familiar with HTML. We're not going to do a lot of HTML work in this course. Okay. Now let's restart our application with Ctrl and R. Good. Back to our homepage. Let's refresh. And here's our homepage. Beautiful. Now, let's add another endpoint. So, back to our home controller. Let's select these few lines and press command and D on Mac or control and D on Windows to duplicate them. Now, we're going to change the other endpoint to /hello. So, if you send a request to the hello endpoint, this other method will be called. Let's change it to say hello. Now, we can return the same view or a different view. For simplicity, I'm going to return the same view. Let's restart our application again. Now, if we hit /hello, we get the same result as before. Now, let's right click on this page and look at page source, we see the full HTML markup for this page. This is what the server has returned to the client. This is serverside rendering or SSR in action. This is how traditional web applications work. But later in the section, I'm going to show you how we can build modern APIs that return only data to the client and then it's up to the client to take that data and generate an HTML page. So, we have created a simple controller that returns a static HTML page. But this page doesn't have any dynamic content. In the next lesson, we'll talk about view templates which let us generate dynamic HTML pages. In the last lesson, we created a controller that returned a static HTML page. Now, to make this dynamic, we have to use a template engine. A template engine is a tool that allows us to create dynamic web pages by embedding variables and logic inside HTML files. Now, we have several template engines for Java applications. We have JSP, which is short for Java server pages. It's an old technology. Nobody uses that anymore. We also have Freemaker, Mustache, and Time Leaf, which is the most popular template engine for spring boot applications. So, back to our project. Let's add Time Leaf to this project. First, we should go to our palm file. To open that file, we press shift, command, and O on Mac or shift, control, and O on Windows and type pom. Now, in this file, we add a starter dependency. So we press command andn on Mac or control andn on Windows to bring up the generate context menu. Then we select add starter. And here we search for thyme leaf. By the way, it's time leaf. It's not th leaf. I've seen some people call it thy leaf. That's not the right pronunciation. So let's add this to our project. Okay. Now back to our project. Here in the resources directory, we add a new directory called templates. By default, Springwood looks for time leaf templates in this directory. Next, we should move index. html into this new directory. Okay. Now, let's open index. html. Now, time leaf has a bunch of attributes that enhances HTML. With these attributes, we can render content dynamically. But to use those attributes, first we have to define a namespace. So we go to our HTML tag and type XML NS that is short for namespace colon. Now look, Intelligj is suggesting the code we have to add. So we simply press tab to complete the code. So with this we are saying that here we're going to use attributes that will start with th and these attributes are defined by this website timeleaf. org. So now instead of rendering hello world statically we want to render it dynamically. We want to pass the name of a person and render it here. To do that we remove the content. Instead we type th here we can

### [25:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=1500s) Segment 6 (25:00 - 30:00)

see all the time leaf attributes. The one we're going to use in this lesson is text. And with this we can set the text of an HTML element dynamically. Now we set this to a time leaf expression. First we type single quotes to represent a string. Here we say hello followed by a space. Now we want to concatenate this string with the name of a person. Now we want to insert the name dynamically. To do that we type a dollar sign followed by curly braces and inside the braces we type the name of a variable. In this case name. Now this variable is not correctly initialized. In the next lesson, I'll show you how to use models to pass data from controllers to views. Now our controller to our view, we go back to our controller and we give this method a parameter of type model. Now we have two types here. One is an interface declared in this package spring framework. The other one is a class that is defined in a different package. Make sure to import the first one. So we import this. Now a model is basically a container for data. We can use it to pass data from a controller to a view. So here we call model add attribute and pass two arguments. Each attribute has a name and a value. The name of the attribute should be variable we have used in our view. So here we provide name and set the value to let's say my name mosh. Now here we have a little warning because Intelligj cannot find this view. Now that we're using time leaf views we should remove HTML here. So Intelligj knows that we are working with the time leaf template with this. If you hold down command on Mac or control on Windows and then click this we can jump directly to the view. Similarly, if you hold down command on Mac or control on Windows and click the variable will jump to the line where you have set that variable. Okay. Now, if you don't want to use your mouse, you can press command and B on Mac or control and B on Windows. Okay. Now, we don't need the second endpoint anymore. So, let's remove this and restart our application. Now, back to the homepage. Let's refresh. and here's my name. So, this is how we can use a template engine to render data dynamically. In the next lesson, I will show you how to return JSON data instead of HTML from our controller. You have learned how we can use Spring Boot to return HTML pages to clients. But what if we want to return raw data? Let me show you how to do that. Back to our project. Here in the controllers package, we add a new class called message controller. Now, we're going to annotate this with a different annotation, and that is rest controller. Now, rest has nothing to do with having a nap. It's short for representational state transfer. I know it's one of those fancy computer science terms, but in simple words, REST is a set of rules that define how web applications communicate over HTTP. Quite often you hear the terms REST or RESTful APIs. An API is just an interface that allows applications to talk to each other. A REST or a RESTful API is an API that follows a set of standard rules. Okay, so we annotate message controller with rest controller and with this we're essentially building an API. Now we're going to expose this on a particular endpoint. So just like before we add a method here. Now this method doesn't have to return a string. It can return a number or an object. Any kind of data we want to return. First let's return a string. Now let's call this say hello and expose it at slash hello. Okay. Now let's return hello world. Let's restart the application. Now if you go to our browser and hit the hello endpoint, we get hello world. But let me show you something interesting. Let's right click here and look at the page source. Look, we only have the data. Unlike before, we don't have any HTML markup. Now, in this example, we're returning a simple string, but we can return a complex object. So, back to our project. Let's wrap this string inside a message

### [30:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=1800s) Segment 7 (30:00 - 35:00)

object. We go to our project here in the entities package. Let's add a new Java class message. We give it a field private string text. Now we need a constructor and a getter. We can manually create those or we can use Lombok because we're using Lombok in this project just like part one. So we use all arcs constructor and getter. Now back to our controller. Here we wrap hello world inside a message object. Okay. And of course, we should change the return type to message. Let's restart the application. Back to the browser. Let's refresh. Look, now we have a JSON object. So, this syntax is what we use in JavaScript for representing objects. So, a curly brace represents an object. And here we have a key value pair. The key is text and the value is hello world. So, Spring Boot can automatically convert our Java objects into JSON objects. We don't have to worry about that kind of conversion. Now, here I'm using a Chrome extension. That's why my JSON object is pretty formatted. If you're not getting the same result, install this extension called JSON formatter. Okay. So, this is how we can build APIs with Spring Boot. Now, with this API in place, other applications can consume our data and do whatever they want. For example, a front-end application built with React, Angular or Vue can take this data and generate HTML pages on the client. That's one way. A mobile app can also take our data and show it to the user. But not only that, even an AI agent can take our data and use it as part of implementing an automated workflow. That is why in modern applications, we prefer to build APIs instead of returning full HTML markup to clients. So for the rest of the course, our focus will be on building APIs. In the next section, we'll go deeper into building APIs. We'll talk about handling different types of HTTP requests, processing user input, and returning meaningful responses. So I will see you in the next section. Hey guys, thanks for sticking with me so far. Just a quick break. If you're enjoying this tutorial, I wanted to let you know that this is just the first hour of my complete Spring Boot course. The full course is 9 hours long and takes you way beyond the basics. We'll build the backend for an actual e-commerce application with authentication, role-based access control, shopping cart functionality, payment processing with Stripe, and full deployment to the cloud. So after you watch this tutorial, if you want to learn more and level up your skills, you can enroll in the full course using the link in the description. All right, let's keep going. Welcome back. In this section, we're going to dive into building restful APIs with Spring Boot. If you have ever wondered how backend systems expose data to front-end applications, mobile apps, or even other services, this is where it all comes together. We'll start by creating our first RESTful API and learning how to test it using Postman. Then, we'll explore how to handle dynamic routes, set HTTP status codes, and use DTO's or data transfer objects to structure our responses properly. You will also learn how to customize API responses, extract query parameters, and work with request header and body data. From there, we'll dive into the core crowd operations, and even handle more advanced scenarios like actionbased updates. By the end of this section, you'll have a solid understanding of how to build restful APIs that can power web and mobile applications. So, let's jump in and get started. In this lesson, we're going to build our first RESTful API. We'll create an endpoint at / users that fetches all users from the database and returns them in JSON format. So, back to our project here in the controllers package, we add a new class user controller. Then, we annotate this with rest controller. Next, we define a method that returns a list. Let's import it a list of user. And this is the user class we have defined in the entities package. Now, Intelligj is suggesting to call this get all users. That's a good name. So, we press tab. Good. Now, in this method, we should use our user repository to fetch the users from the database. If I type user repository and press enter, Intelligj automatically adds this as a field in this class and initializes it using this constructor. But in this project, we are using Lombok. So this constructor is really

### [35:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=2100s) Segment 8 (35:00 - 40:00)

unnecessary. We can make our code more concise. But here we have to apply the all args constructor annotation. Now back to our method here. We call user repository. findall. find all and return the result. Now we have a compilation error because our method should return a list of user but our repository is returning an iterable of user. Now in case you are not familiar with iterables, iterable is an interface that represents a collection of elements that can be iterated over. It's the parent interface for list. So every list object is an iterable. But not every iterable is a list. Now here we have two options. One option is to convert this iterable to a list. But that's really unnecessary because we don't need any additional functionality that comes with lists. A better solution is to change the return type of the method to iterable. Okay. Now to expose this at / users, we apply request mapping and provide slash users. Now in the previous section I told you that HTTP requests have a property called method which can be get for getting data, post for creating data, put for updating data, and delete for deleting data. We're going to see examples of this throughout this section. For now, we're focusing on get. Now request mapping by default uses the get method. But here we have another annotation that's an alias for request mapping and that is get mapping. So we apply get mapping and provide / users as an argument. It's a little bit shorter than request mapping. So I prefer to use get mapping here. Okay. So this endpoint is ready. Now before testing it, let's populate our database with a couple of users. So here in the database window, we open the users table. Let's add a new user. I'm going to call this user one. User one at domain. com. Password whatever. Let's add one more. User two. User 2 at domain. com with the same password. Now we submit changes. Good. Let's restart our application. Lovely. Now back to the browser. Let's hit the users endpoint. And here are our users. But there's a big problem here. Can you see? It's the password field. Our passwords are exposed to the outside world. But don't worry, we're going to come back and fix this later in this section. So, our first endpoint is ready. Next, I'm going to show you an alternative way for testing our APIs. Now, while we can call APIs using a browser or even command line tools, a better approach is to use Postman. Postman is a very powerful tool designed for testing and interacting with APIs. So, if you don't have it on your machine, head over to postman. com/d downloads and download the latest version for your operating system. Now, let me give you a quick tour of how Postman works along with a few useful features you need to know. So here on the homepage we can click plus to add a new tab. Now up here we can see the request method. So we have get for getting data. We also have post for creating data, put for updating it, patch and so on. So we can send a get request to our new endpoint. Now down here we have a bunch of tabs for modifying our requests. So we can go to the params tab and add query parameters. We'll talk about this later in the section. We also have authorization. We have headers. On this tab, we can see all the request headers. By default, the autogenerated ones are hidden. We can click and see them. So these headers, as you can see, are key value pairs. For example, user agent represents the browser which is set to Postman runtime in this case. Now, practically speaking, we use headers for including metadata when calling APIs. A common application of this is for including API keys or authentication details. Again, we'll look at this later in this section. Here on the body tab, we can include data when calling an API. And this is useful for creating and updating data. Now, we don't need to make any changes here. So, let's send this request. Now, down here, you can see information about the response. So, the status is 200, which means okay. This is the time it took to get the response. This is the size of the response. And down here you can see the body. This is the same output we had in our browser. Right? But here we also have preview and I believe this only works if you have created an account with Postman which is free. With preview we can see the data

### [40:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=2400s) Segment 9 (40:00 - 45:00)

in the tabular format. It's pretty useful. Now we also have a tab for viewing the response headers. Again these are key value pairs. For example, we have content type that is set to application/json. This is the type of data that the server is sending to the client. So this is the basics of Postman. Going forward, we'll use this tool for calling our API. So far we have built a simple API for fetching all users. But what if we want to fetch a specific user by their ID? With restful conventions, we have to expose a new endpoint where we can pass the ID of a user. Let's see how we can implement this. So, back to our user controller. Let's add a new method that returns a user object. We call this get user and give it an ID parameter. The type of the parameter should be long because this is the same type we used as the ID of the user entity. Let's have a quick look here. So in our user class, id is a lock. Okay. Now we have to expose this at a new endpoint. So we call get mapping tab. This is our new endpoint / users / id. Now because id is a parameter, we have to wrap it in braces. And also we have to apply the pass variable annotation here. With this we'll be able to pass ID dynamically to this route. Okay. Now in this method we call user repository. Now Intelligj is suggesting the code. Let's press tab. So we call find by ID. Now in the first part of the course you learn that find by ID returns an optional object. So here we have to decide what should happen if we cannot find this user. There are two options. We can throw an exception or return an alternative value like no. In this case, we're going to call or else and provide null as an alternative value. And then finally, we return the result to the client. Now, currently, we have repeated / users in two places. This is a little bit ugly. We can make our code more concise by mapping our controller to the users endpoint. So, up here we apply request mapping. In this case, we don't want to use get mapping because later we're going to implement other methods for creating and updating users. So we cannot use get mapping. So we apply request mapping and as an argument provide / users. With this we can simplify our code. So we remove / users from here and that means we don't need to pass any arguments. So no parenthesis is needed. And down here again we remove / users. So the argument is slash id. Okay. Now let's restart our application. Back to postman. Let's hit / users / one. Okay. Here's our first user. Beautiful. Now whatever value we pass here by default is treated as a string. But under the hood, spring will automatically convert that value to a long. And that means if we pass a value that cannot be converted to a long like a, we're going to get an error. Okay. Now let's see what happens if we try to fetch a user that doesn't exist. Let's say user 10. We don't get any errors. The body of the response is empty, but the status is 200. This is not restful. In restful convention, if a resource like a user cannot be found, we have to set the status to 404. I'm going to show you how to do that next. Sometimes we need more control over the response. We might need to customize the headers or change the status code. For example, if a user is not found, we should change the status to 404, which means not found. And this is where we use the response entity class. With response entity, we can customize our responses. Now this is a generic class that is defined in org. spring framework. http package. Let's import it. And as a generic type argument, we pass user. Now we have to do a bit of surgery here. Instead of returning the result immediately, we store it in a variable. Then we check if user is null, we should return a response entity with the status of not found. Now Intelligj is suggesting some code. I don't want to use it yet. So let me show you an alternative way of returning a response entity. We can create a new instance of class. Now look this constructor has

### [45:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=2700s) Segment 10 (45:00 - 50:00)

five overloads. The first one takes a status code. Here we have an enum that is HTTP status. In this enum we have all the standard HTTP status codes like not found, accepted and so on. So one way is to create a new response entity object like this. But there is a cleaner way. The response entity class has a bunch of static factory methods for creating response entity objects. So here we can call not found. Now this method returns a headers builder object. So we can call this and if you want we can further customize our headers. We don't really need that. So instead we're going to call build to get a response entity object. And this is the code that IntelligJ was initially suggesting. Okay, that's better. So if the user is not found, we return a new response entity with the status of not found. Otherwise, we return. Once again, we can create a new response entity and pass the user object as well as the status code. We can use one of the static factory methods. So we call return response entity. Okay. And pass the user. So going forward, we're going to use this approach for creating response entity objects. Now let's restart our application. Okay. Back to Postman. If we try to fetch the user with the ID of 10, look, we get a response with a status of 404, which means not found. Otherwise, if we get the user with the ID of one, we get a response with a status of 200. Beautiful. We've built a simple API for fetching users, but our API currently has two problems. The first problem is that we're exposing our passwords. That's the first problem. The second problem is less visible. The problem is that we are returning our user entity from our API. And that means if tomorrow we decide to change our database structure and subsequently our user entity, those changes will leak to the outside and can potentially break our clients. For example, if we decide to rename the name field to full name or remove some of these fields, these changes will leak to the outside and can potentially break some of our clients. So, as a best practice, we should try to keep our APIs as stable as possible. And if we need to introduce any kind of changes, we should properly version our APIs. This is where we use data transfer objects. A data transfer object or DTO is a simple Java object used to transfer data between different layers of an application. So imagine this is our application. At the heart of our application, we have our entities. These entities are part of the domain layer of our application. At the boundary of our application, which is where we have our APIs, we'll have our DTO's. These DTOs will be the input and output from our application. So going forward, we're going to introduce a bunch of DTOs and then we'll need to find a way to map DTOS to our entities. Let's see this in action. So back to our project, let's add a new package called DTOS. And in this package, let's add a new class user DTO. And note that I'm not capitalizing DTO. I'm using the Pascal naming convention. So we are capitalizing the first letter of each word. Even though DTL is an acronym, this is the same convention used in spring. For example, in spring we don't have JPA repository all in capital. We have JPA using Pascal naming convention. Okay. So this is our DTO. Now in this class, we add the fields we want to expose to the outside. So we're going to add long id as well as string name and string email. Not the password, not the profile, nothing else. Okay. Now we need to give this a constructor. So we can use all arcs constructor. We also need a getter so spring can read the data from these fields and create JSON objects with this. Now we go back to our user controller. Instead of returning user entities, we should return user details. Let's import it. Now we need to map user entities to user details. To do that, first we have to go to our repository. So let's go to user repository and change the base type from crowd repository to JPA

### [50:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=3000s) Segment 11 (50:00 - 55:00)

repository. With this change, the find all method returns a list. So previously if you remember find all was returning an iterable but once we use a JPA repository find all returns a list. Now that we have a list we can use the stream API to map user objects to user details. Now if you're not familiar with stream API and mapping objects I covered this concept in the third part of my Java series. So here we call math and provide a function a lambda that takes a user and returns a new user dtol. Now here we should provide the arguments. So user get id, user. get name and user. get email. Okay. Now map returns a stream object. So finally we need to convert it to a list. Okay. Now we need to make the same change in the other method. So first we change the return type to user DTO and then over here first we create a user DTO and then we put it in our response user DTO. Okay, now let's restart our application. Back to Postman. Let's get all our users. There you go. Now we only have ID, name and email in the response, not the password or the address or any other fields. So this is the output from our API and we should try to keep it as stable as possible. If we change our domain model meaning our user entity, we just have to update our mapping code to make sure that the output from our API is stable. In the previous lesson, we manually mapped a user to a user DTO. While this works, it can become repetitive, especially when dealing with large DTOs with many fields. This is where we use mapping libraries. There are many mapping libraries out there, but the two most popular ones are model mapper and map. Model mapper uses reflection, that's why it's slower and harder to debug. On the other hand, map generates mapping code at compile time. That's why it's blazing fast, type- safe, and free of runtime overhead. So, in this course, we're going to use mapruck for mapping objects. Back to our project. First, let's go to our palm file. Now, we're going to add a new dependency. So, we press command and N on Mac or control and N on Windows to bring up the generate context menu. We select dependency. Here we start with the organization name that is or do mapapstruct. Now there are two libraries we need to add. One is map. The other is mapstruck-processor. First we're going to add mapstruck. Now make sure to use the same version so there are no surprises when you're following the course. Now let's add one more dependency org. mapststruct. This time we're going to add map processor. Okay. Now let's reload Maven. Good. Now back to our project. Here we're going to add a new mappers. In this package we add a new interface. Let's call this user mapper and change the type to interface. First we should annotate this with the mapper interface defined in org. mapstruct and also as an argument we have to pass component model we should set it to spring so spring can create beans of this type at runtime. Now in this interface we can declare all kinds of mapping methods. For example we can add a method for mapping a user to a user DTO. So a method that returns user DTO and we call it to DTO and pass user. Okay, the name doesn't matter. What matters is the source and target type. With this interface in place, now we can go back to our user controller and modify our mapping code. So first we add a field of type user mapper and then in this method instead of manually mapping a user to user DTO we get a user and call user mapper to DTO and then we pass the user. Now when writing lambda functions whenever we have a lambda function that takes an object and then passes that object to a function we can use a shorthand syntax. If you press alt and

### [55:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=3300s) Segment 12 (55:00 - 60:00)

enter here intelligj suggests to replace lambda with a method reference. There you go. This is much more concise and cleaner than what we had before. So we map objects and to do that we use user mapper to DTO. We should also update the mapping code in the other method. There is no need to create a user DTO here. We can simply call user mapper 2DTO and pass the user object. Now you might be wondering but what about the actual mapping code? All we have done so far is created an interface. This is the great thing about mapruck. When we compile our application, map will automatically implement this interface for us. Let me show you. So let's restart our application. All right. Now back to our project. Look here we have the target directory. Let's look at generated sources under annotations. Look, we have this class user mapper implementation. This is where we have the actual mapping code. So here's our 2D method. First we check if user is null we return null otherwise we create a user DTO with these values. So this code is autogenerated that means you should never touch it anytime you modify your source and target objects and recompile your application. Mapstro will automatically regenerate the mapping code. Now back to Postman. Let's hit our endpoint and make sure there are no errors. There you go. We get the same result as before. Sometimes we need more control over how Java objects are converted to JSON. This process is called serialization. Meaning converting a Java object into a JSON representation. Now, similarly, converting JSON back into a Java object is called des serialization. Now there are situations where we need to control how Java objects are serialized into JSON. We have a few annotations for that. We have JSON ignore for excluding fields. JSON property for renaming them. JSON include for excluding null or empty fields and JSON format for formatting values particularly dates, times, and numbers. Let's see these in action. So back to our user DTO. Let's say we want to exclude the ID field from our JSON objects. One way is to remove this field. But let's say we have some other code that is dependent on the ID field. So we cannot remove it from this class. In those situations, we can apply JSON ignore to exclude a field from our JSON object. Now let's restart our application. Now let's hit the user's endpoint. All right, look the ID field is gone. Okay, back to our code. So that was JSON ignore. We also have JSON property for renaming a field. Let's provide a different name like user underline ID. Now let's restart our application and hit the user's endpoint again. There you go. Look, ID is changed to user underline ID. Now sometimes we want to exclude null or empty fields from our JSON objects. For example, let's add another field here. Private string phone number. Now our users currently don't have a phone number. So if we restart our application and hit the users endpoint, phone number is null. Now what if we want to exclude null values from our JSON objects? That's very easy. Back to our DTO here. We apply JSON include and as an argument we supply the condition for including this field. Now Intelligj is suggesting the code. Let's press tab. So JSON include. incclude is an enumeration. In this enumeration, we have a bunch of values. The default is always. We also have non-MPT and non-null. Let's add null here and restart the application. Look, phone number is gone. Beautiful. Now the last annotation we're going to look at is JSON format for formatting data. So let me remove this new field. We don't need it anymore. Instead, we're going to add a new field of type local datetime called created at. Now, to give this some value, we have to go to our mapper. So, let's go to user mapper interface. Now, here we have to apply a special annotation for customizing the mapping code and that is mapping. Let's press tab to complete the code and import the mapping annotation. Now target we should change this to

### [1:00:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=3600s) Segment 13 (60:00 - 65:00)

create at now we don't want to ignore this instead we want to provide a value to do that we set the expression attribute to a valid Java expression let's press tab to complete the code so we set this attribute to a string and here we start with Java followed by parenthesis inside parenthesis we type a valid Java expression so here we are passing java time. Datetime do now. Okay. Now let's restart the application and hit the users endpoint. All right. Look, now each user object has a created at property. Now look at the value of this property. We have the date component followed by a t to represent the time and here's the time component. Now this is the standard ISO format. It's not very human readable. And this is where we can use the JSON format annotation for formatting this date time. So back to our DTO, we apply JSON format and press tab to complete the code. So with this pattern, we can provide a date in this format followed by the time in this format. And of course, we can always change this to fit our requirements. Now let's restart the application and hit the user's endpoint one more time. All right, look. Created ad is now reformatted. Beautiful. Now, we don't need this going forward. So, let me remove this. And also back to our mapper interface. Let's remove the mapping annotation. All right. Now, let's see how we can extract query parameters from our requests. Query parameters are key value pairs that are added to a URL and we often use them for filtering, sorting, pageionation essentially as a way to provide input to our APIs. Now here in Postman we have the params tab where we can add our query parameters. Let's add a parameter called sort and set it to name. And one more page we set it to one. Now, as you can see up here, query parameters are added after question mark and they are separated using an amperand. Now, we don't need page in this lesson. So, let's simplify things and remove this parameter. There you go. Okay. So, we have the sort parameter. Let's see how we can capture it in our API. So, back to our user controller. Here is the get all users method. First, we should give this a parameter of type string called sort. Now, the type of the parameter doesn't have to be a string. In this case, I'm using string because we are capturing the name of a field. But if you were capturing a page number, we could use byte, int, long, any kind of numeric types. Okay. Now, if the value that is provided is not convertible to the target type, we'll get a runtime exception. Okay. So, let's change this back to string. Next, we should annotate this with request param. Now, how can we sort data? Well, we talked about this in the first part of the course. Find all has an overload that takes a sort object. If we press command and P on Mac or control P on Windows, we can see all the overloads. Here is an overload that takes a sort object. We also have another that takes a pageable object. And these are only available in repositories that extend JPA repository. So let's quickly check. Let's go to user repository. This interface extends JPA repository. And this is the interface that provides sorting and pageionation. Now back to our controller. So as an argument here, we call sort. First we import it. Sort by. Now by has a few overloads. We're going to use the first one that takes one or more string objects. So we can pass our sort argument to sort the data. We can optionally call ascending or descending. We don't really need it here. So let's restart our application and hit this endpoint with sort set to name. All right, our data is sorted by name. But to verify it, we go to the console window. Look at the first query sent to our database. We are selecting all these columns from the users table and we're ordering by name. Beautiful. Now what if we provide an invalid field like name X? We get a runtime error that translates to a 500 error in HTTP. Not the best experience for our clients. A better approach is to validate the sort

### [1:05:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=3900s) Segment 14 (65:00 - 70:00)

parameter and if it's invalid, we can give it a default value. So back to our controller to do that there are various approaches. One simple way is to define a set of valid values. So we can call set first we import it set of we initialize it with name and email. Let's say these are the only valid values. Next we check if this contains the sort argument. If not then we can set sort to name by default. Let's restart the application and hit the endpoint. All right, no more errors. Beautiful. And if we check the console, here's our first query. In this query, we are ordering users by name. Perfect. Now, by default, the sort parameter is required. So, if we don't provide it, we get a bad request. We can make it optional by setting the required attribute of request param to false. Now let's restart the application again and hit this endpoint. All right. Now once again we got a runtime exception. Let's look at the console window. So we got a null pointer exception. Cannot invoke object equals because O is null. Where is this happening? This is happening in our user controller. Let's click here. This is essentially happening on this line where we are validating the sort parameter. We cannot pass null to the contains method. To fix this issue, we can give this a default value. So here we have an attribute default value. We can set it to an empty string. We could also set it to one of our valid fields like name. But I don't want to do this because if in the future we decide to change the name of this field to something else, there are two places where we have to update. So I would prefer to stick with an empty string with this. This will be an invalid value. So we'll set it to name by default. Let's restart the application and hit the end point. Okay, now our users are sorted by name. Now what if you provide sort but don't set it to a value? Our application still works. What if we set it to email? Now data is sorted by email. To verify that, let's look at the console. Well, there are so many queries here. So, let me clear this and hit this endpoint one more time. All right, take a look. Now, we are sorting users by email. Now, in case you're wondering what are these two additional queries, this is because of the eager loading, because of the relationship we have between user and profile objects. Technically, we don't need this relationship because the user entity essentially represents a user account. When working with user accounts, we don't really care about profiles. Profiles are additional information we have about our users. They have nothing to do with authentication, authorization, and so on. So, if you want to get rid of these queries, we can go to our user entity and remove the profile relationship. It's down here. We have a onetoone relationship and that's why we have eager loading by default and in hibernate if you fetch multiple objects like multiple users and we have eager loading to another entity by default hibernate sends multiple queries to the database instead of doing a join you can always optimize this using entity graph we talked about this before but anyway it doesn't really matter in this lesson so let's remove this field restart our application and hit the user's endpoint one more time Okay, now look in the console window. We have a single query for fetching the users. Now let me show you a problem with this implementation. Let's say tomorrow we decide to rename this parameter to something else like sort by. We can press shift and F6 to rename this. Let's change it to sort by. Restart the application and hit the end point. Now look in the console window. Our users are sorted by name even though we have set sort to email. The reason is obvious because we renamed this parameter. So this is no longer associated with the sort parameter here. So as a best practice whenever you try to work with a query parameter always set the name attribute we set this to sort. So if in the future we decide to rename the parameter name, our code doesn't break. Let's restart the application and hit this endpoint. Now back to the console. This time our users are sorted by

### [1:10:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=4200s) Segment 15 (70:00 - 75:00)

email. All right. Now it's time for you to practice what you have learned. So in this exercise, I want you to build two API endpoints for fetching product data. First, create an endpoint that returns a list of products. This endpoint can optionally receive a query parameter called category ID for filtering products by category. If not provided, it should return all products. Now the response should be a list of product details with these fields. ID, name, description, price, and category ID. So in this DTO we don't have a full category object. We only have category ID. Now to implement mapping between product entity and product DTO you have to add a custom annotation to your mapping method. So here we have set source to category ID which means we get the value from the source object. We go and grab category do ID and use that to set the category ID field of the target object which is product DTL. Okay, next we should build an endpoint for fetching a single product by ID. If the product exists, return a product DTO. Otherwise, return a 404 not found error. Now, I've put this PDF below this video, so you can always come back to it. Spend about 20 to 30 minutes on this exercise and then come back and see my solution. All right, I'm going to go a bit faster because I'm assuming you have worked on this exercise and just want to quickly watch how I would implement these two end points. So, I'm going to go in the controllers package and add a new class product controller. Next, we annotate this with rest controller and expose it at the products endpoint. Next, we define a method that returns a list of product DTO. We haven't created this class yet, but we can create it right here. We press alt and enter and create this class. Now, we don't want to put this in the controllers package. We want to put it in the DTO's package. Next, we add our fields. Private long ID, private string name, price. We change the type to big decimal. Then we add description as well as category ID. Okay. Now we annotate this with data instead of getter and setter. Back to our controller. We import list and call this method get all or get all products. Here we should call product repository. If you press enter, Intelligj adds this as a field in this class. and initializes it using this constructor. But we can simplify this code by removing the constructor and applying the all args constructor annotation. Now before implementing filtering, I just want to fetch all products and build a simple endpoint. So I want to do this in baby steps. So here we call find all. Next, we should map products to product DTO's. For that we have to create a mapper. So back to our project we go to the mappers package and add a new interface called product mapper. We annotate this with the mapper annotation and then add a method that returns a product detail. Product DTO and we give it a object. Let's import product. Good. Now we should customize mapping. So we apply mapping annotation. That's a target as well as source attributes. So we go in the source object which is a product entity and map category ID to the category ID field of the target object which is product DTO. Now back to our controller, we add our mapper to this class. So private final product mapper. Now we call find all. Then we use the stream API and map each product to a product detail. This returns a stream. So we convert it to a list and then return the result. Finally, we expose this using the get mapping annotation. Let's restart our application and test it up to this point. So back to Postman. Let's hit our products endpoint. Okay, here's our product. You can see that mapping is done properly. So we have category ID one, one and two. Beautiful. Now let's implement filtering. So back to our controller, we give this method a parameter of type bite category ID and annotate it with request pro. As a best

### [1:15:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=4500s) Segment 16 (75:00 - 80:00)

practice, we give it an explicit name and then we make it optional. Now here depending on if you have a category or not, you have to call two different methods of our repository. First we have to go to our repository and add a method for filtering products by category. So we return a list of product. Let's import this and call this method find by ID. Then we pass category ID. Now back to our controller. Here we declare a list of product call it products. Then we check if we do have a category we call product repository. find by category ID. Otherwise, we set products to product repository final. Now that we have a list of products, we can simply convert all of them to product DTOS. Let's restart our application. Let's hit the endpoint without any query parameters. Okay, we get all products. Lovely. What if we set category ID to an empty string? We still get all products. Great. What if you pass one as the category ID? We only see products in this category. Okay. Now, what if we pass an invalid category? We get an empty list. And that's totally fine because we don't really have a product in this category. Now, we could alternatively return a 404 error, but I think that's a little bit too much. There's really no need to do that. That makes our API a little bit angry. So, we're done with this now. Look at the console. There are a bunch of queries here. It's not quite clear what's happening. So, I'm going to clear this window and hit this endpoint one more time. All right, look. We have this query for fetching products and categories from our database. Now, what if we don't provide a category ID here? Now, we get three extra queries. Let me show you one more time. So I'm going to clear this window and hit the endpoint without a category. In this scenario, we get three queries. The first one is for fetching products. So we are fetching all these columns from the products table. And then we have two extra queries for fetching the category for each product. So in this scenario, there is no join between the products and categories tables. This is how hibernate works by default. So if you have eager loading between two entities and we retrieve a list of entities, hibernate will send additional queries for fetching the related entities. Now this is not the n plus1 problem because all these queries are sent in one session. But we can still optimize this by using a join to fetch all the products and their categories. To do that we have to go to our repository and create a new custom query method. So this method should return a list of product. We can call it find all with category to specify that we're including categories with this query. Now because this is a custom query and doesn't follow the conventions in Spring Data JPA, we have to annotate this with the query annotation, we can write a JPQL query like this. So we select P from product P and do a join with P. Cate. Alternatively, we could remove the join part and use the entity graph annotation and set attribute paths to category. Both give you the same result. Now let's go back to our controller and replace find all with category. Let's restart the application and clear this window. Now let's hit this endpoint. We have a single query for fetching the products and the categories. And here's our left join. Okay, so we are done with our first endpoint. Now, one more time, let's verify what happens if we pass a category ID here. All right, looks like earlier I made a mistake. In this scenario, we're also getting multiple queries. So, we can optimize this using the entity graph annotation. So we go to our repository and apply the entity graph annotation on this other query method. Let's restart the application. Okay. And hit this endpoint. All right. Now we have a single query to fetch the products and categories. So we're done with the first endpoint. The second endpoint is pretty

### [1:20:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=4800s) Segment 17 (80:00 - 85:00)

straightforward. It's exactly like the code we wrote for fetching a single user. So I'm not going to waste your time typing all that code by hand. If you want to compare your code with mine, we have a commit for each lesson in this repository. So, we're done with this exercise. Let's move on to the next lesson. You learn how to provide additional data in requests using query parameters. As I told you, these query parameters are often used for filtering, sorting, and pageionation. But we have another way for providing additional data in our requests and that is using request headers. These headers just like query parameters are key value pairs. Here are the seven headers that are sent by Postman by default. If you don't see these, we can toggle them up here. So these are the default headers sent by Postman. Your browser will probably send some additional headers to the back end. Now these headers are often used for metadata. They're often used for authentication, caching, and so on. So, as an example, let's add a custom header here for passing an authentication token. So, by convention, we prefix custom headers with XY. Let's call this O token and set it to 1 2 3 4. Now, to capture this, we go back to our controller. Here is get all users method. We add a new parameter here. string o token we prefix it with request header. So just like request pram we have request header. Now we give this a name that is x - oy- token. Now we have a little warning here. Intelligj is saying unknown http header. We can click this link or press alt and enter to add this custom http header. The warning is gone. Now for simplicity let's just print O token on the terminal. So south tab O token. Let's restart the application and hit the end point. All right. Now take a look in the console. So we have 1 2 3 4. Beautiful. Now this header is not case sensitive. So if we set this to token in capital look in the terminal our application is still working. But by default this is required. So if we remove this from our request and hit this endpoint we get a bad request. Meaning we didn't provide the necessary data for calling our endpoint. But we can easily make this optional just like request pram. We have the required attribute here. If we set this to false and restart our application and then hit this endpoint our application works. Beautiful. So this is how we can extract request headers. At this point, we don't need them. So to clean up our code, I'm going to remove this parameter and the print statement. So far we have covered a couple of ways for providing data with our requests. We can use query parameters for providing simple values often used in sorting, filtering, and pageionation. We can use request headers for providing metadata like authentication tokens, caching and so on. But there is a third way and that is using request body. With this we can send the actual data or content to our back end. This is often used for creating or updating objects. So let's see how we can use this to send the user object to our back end. Now for creating objects, we cannot use the get method. This is only used for getting data. So we should change this to post. Now we don't need the query parameter here. So we send a post request to the user's endpoint. Now here on the body tab let's change the type to raw. Now in this dropown list we can provide the type of data we want to send to the server. We can send text like a string. We can send JavaScript code, JSON objects, HTML and so on. Most of the time we use JSON. Now in this box we provide a valid JSON object. So we add curly braces and one or more key value pairs. Our keys should be surrounded with double quotes. So let's send a user object with the name set to mosh or whatever you want and email set to mosh atcodewithmsh. com. Now if we send this to our back end we get an error with the status of 405 which means method not allowed because we haven't implemented an endpoint that receives post requests. So back to our user controller let's add a method public for now let's just return

### [1:25:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=5100s) Segment 18 (85:00 - 90:00)

a user DTO object but the return type can be anything. Let's call this create user and give it a parameter of type detail and we can call this data. Now to receive the request body, we should annotate this with request body. This is a common source of errors. Make sure to include it. Otherwise, you're going to get null values on your back end. Okay. Now, because we're using the post method, we should annotate this with post mapping. For now, let's just return data to the client. So, whatever we send to this endpoint, we'll get it in the response. Now, let's restart the application and send this request again. All right, look what we get. ID set to null because we didn't provide it up here. We only have name and email. Now, if we use an invalid property like email X, again, Spring is not able to initialize the email field. That's why we get no. Now, as a refresher, this process, the process of converting a JSON object to a Java object is called des serialization. And the other process which is converting a Java object back to a JSON object is called serialization. Okay. So, this is how we can send data using request body. In the next lesson, I'm going to show you how we can actually create a user object. Now let's see how we can create objects or resources in restful terms. So we're going to send a post request to the user's endpoint. And in the body of the request, we're going to include a valid user object. So we should include the name, the email, and the password. Back to our controller. Now we have a problem. In this method, we are receiving a user DTO object in this class. We don't have the password field. We had it earlier, but we had to remove it because our passwords were leaking outside of our APIs. Now, you might be wondering if we can add the password field here, private string password, and annotate it with JSON ignore. This is not going to solve our problem because this annotation is applied both during serialization and des serialization. So that means if you have this annotation here, spring will not read the password property of our JSON objects and put it into this DTO. Okay, so this is not going to solve our problem. Earlier we talked about the architecture of our application. I told you that our entities are at the heart of our application and API models or DTO's are at the boundary. With this separation, we allow the DTO's and entities to evolve independently. Here is another example where we need a separate DTO for creating new users. In that DTO, we're going to have the password field and also we are not going to have the ID field. This is not needed when creating a new user object. Right? So back to our project here in the DTOS package, let's add a new class. We can call this register user DTO. Alternatively, we can replace DTO with request. That's another convention a lot of people follow. This better aligns with the request response model of HTTP. So this class essentially encapsulates all the data we need for sending a request to register a new user. What fields do we need? We need name, the email and the password and not the ID field. Right now we should annotate this with getter and setter. So spring can initialize these fields using the request data. Alternatively, we can apply the data annotation which is the combination of getter setter to string and two hash code. It makes our code a little bit cleaner. Now up here let's remove the unused import statements. Good. So we have three fields. Now we need to provide the mapping between our new DTO and user entity. And for that we go to our user mapper interface. Here we add a new method that returns a user object. We can call that to entity and give it a register user request object. Okay. Now let's go back to our controller and change the type of the parameter to register user request. And for consistency I would prefer to rename the parameter to request as well. Now at this point we don't want to return the same request. So let's return null. We'll come back to this momentarily. First let's map this request to a user entity. Print that entity on the

### [1:30:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=5400s) Segment 19 (90:00 - 95:00)

terminal and make sure everything works up to this point before going further. So always do one baby step at a time. So here we call mapper dot to entity and provide the request object. We get a user and then print it on the terminal. Now let's go to our user class and see if we have the two string annotation. We don't have it here. So let's add it temporarily. Now Intelligj is suggesting to exclude lazy loaded fields. This is for performance reasons. We talked about this in the first part of the course. Let's just go ahead with the suggestion. Again, this is just a temporary solution. We just want to inspect the user object in the terminal before saving it to the database. So, let's restart the application and send this request. All right. Obviously, we don't see anything in the response. The status is 200, which means no error happened. Now, here in the terminal, we have this user object. ID is null obviously because we haven't provided it. But we have the name and email fields. Where is password? Well, I just realized that in part one of the course, we implemented the tworing method in this class. So, it's right here. We didn't have to apply the two string annotation. In this implementation, we are not including the password. Again, as a temporary solution, I just want to add the password here. So, let's set password to password. And before we forget, let's remove the two string annotation on the top. Not needed. Let's restart the application and send this request. Okay. Now look in the terminal. All right. Here's the password. So our mapping is working properly. Now before going forward, I want to undo the changes we made to the user class. So we go to the commit window, select the user class and roll back the changes. Okay. Now back to our controller. Once we have a user, we can save it using our repository. So user repository save user. The database will assign the ID to this user. Next, we should map that to a user detail and return it from this method. So we can create a user detail by calling usermapper dot dodtol and then return it at the end. Now intellig is suggesting that this local variable is redundant. We can combine these two lines. That's absolutely right. But don't do this yet. We're going to come back to this momentarily. Let's restart the application and make sure that we can successfully save the user to the database. So send. All right. Here's a new user with the ID of three. Currently, our database doesn't have a unique constraint on the email. So, we can register multiple users with the same email. That's not the right way to do it. We'll come back and fix this in the future. But what I want to point out is that every time we send this request, we get a new user with a different ID. Beautiful. Now, there is one more piece that we have to implement before we finish this. When creating resources in REST APIs, we should set the status to 2011, which means created. To do that, we have to change the return type of this method to response entity and then at the end we call response entity. created. Now look at the parameter of this method. It requires a URI. This is the location of the new object or the new resource that is created. So if you have a user with the ID of five, that's going to be users /5. Now, how can we generate that URL? Well, back to this method. Let me put this on a new line so you can see clearly. We're going to give this a second parameter of type URI components builder. Now, let's simplify the name of the parameter. Let's change it to URI builder. That's better. Now once we map this user to a DTL we can call URI builder path provide the path to our resource. So / users/ id as a parameter and then we call build and expand and provide the id of the new user as an argument. And finally we call dot to uri. Let's press tab. This returns a URI object. We can store it here. And then at the end we call response entity created. We pass the URI. Now this method returns a bodybuilder. Funny name. It's not a response entity. To convert this to a response entity we call dot body and provide our user detail in the body of

### [1:35:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=5700s) Segment 20 (95:00 - 100:00)

the response. User detail. Okay. Now let's restart the application and see what happens. So let's create one more user. All right. This time we got the status of 2011. Now look in the headers tab. So HTTP responses just like requests also have headers. Here we have a header that is location. It's a standard HTTP header. And this is set to the URL of the new resource or new user. Now quite frankly a lot of people don't implement this step. They don't set the status to 2011. So here we could get away with generating the URI and simply return the user DTO. That's totally fine for internal APIs, but if you're building an API for public to use, it's best to follow standard REST conventions. All right, now let's talk about updating resources. To update a resource, first we should change our request method to either put or patch. What is the difference? We use put for replacing an entire resource and patch for patching or updating one or more properties. Quite often we use put. So let's change it to put. Now when updating a resource, we should reference a particular resource. So like the user with the ID of one. Now just like creating resources here in the body of the request we should include some data to send to the server. Now when updating users we don't want to include the password because the process of updating a user's password is often different from updating basic account information. When updating a user's password for security reasons we should provide both the old and the new password. We don't want to add two password fields here like old password and new password because the user may only want to update their name and email, not the password. So, we want to handle these two scenarios separately. In this lesson, we're only going to focus on updating basic account information. So, let's remove the password property. Now, back to our controller, let's add a new method, public. For now, let's just return a user DTO and call this update user. Now, here we shall annotate this with put mapping and provide the ID parameter. Now, because our route or endpoint has a parameter here, we should add a parameter of type long id and annotate it with path variable. Now, as a best practice, we should also give it an explicit name. So if tomorrow we decide to rename this parameter to something else like user ID, our code will not break. Now here we should also add another parameter for reading the request body. So let me put this on a new line so we can see clearly. Now here we have two options. One option is to use user detail. Let's see if that makes sense. The user detail has ID, name, and email. It's possible to use this DTO for updating users. Even though we don't need to provide the ID in the request body, but I'm a bit reluctant to use this DTO because in the future we might add additional fields here that may not quite apply to the process of updating user accounts. So it's better to create a separate DTO for updating users. So here in this package, let's add a new Java class update user request. Now what fields do we need here at this moment? Only name and email. So tab and tab. Let's annotate this with data. Beautiful. Now back to our controller. Let's change the type of this parameter to update user request and also make sure to annotate it with request body otherwise it's not going to work. Now when updating resources first we have to do some validation and make sure that resource exists. If not we should return a 404 error. So here we can simply press tab to add all this code. We are using the user repository to find the user with this ID. If not found we return null and at this point we should return a 404 error to the client. So let's change the return type of this method to response entity of userdl. And here we call response entity do not found build. Otherwise if you have this user in our database we should update it with the data in our request. One way is to do manual mapping like this. But I don't want to do this because this is only suitable for small objects. So let's go to our user mapper interface and add a method for updating

### [1:40:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=6000s) Segment 21 (100:00 - 105:00)

an existing user with a DTO. In this method, we don't need to return any objects because we are not creating a new object. We can call this update or whatever we want. We should give it two parameters. Update user request and user. Now here we should also annotate this target entity with mapping target. If you don't apply this, you're going to get a compile time error. Now with this method in place, we can go back to our controller. And once we have a user object, we can call user mapper update. We provide our request and user entity. Next, we call user repository. save. And finally, we map this user to a user DTO and return it in a response. Pretty straightforward. Now, let's run the application. Now, let's look at our database. So here's our users table. Here's our first user. I'm going to change the name and email of this user to mosh with mosh at code with mosh. Okay. So we're sending a put request to user one. And here's our data. Beautiful. Send. Okay. We got a 200 response. And here in the body of the response, you can see the updated user object. Now if you go back to our database and refresh the data, you can see that the first user is successfully updated. Now to test our error handling logic, let's update a user that doesn't exist, like the user with the ID of 100. Okay, we get a standard 404 error. Beautiful. Next, we're going to talk about deleting resources. Deleting a resource is pretty straightforward. First we should change the request method to delete. Now just like updating a resource we should reference a particular resource like the user with ID one. But unlike the update scenario we don't need to include any data in the body of the request. So we can delete all this data. Now back to our controller let's add a new method public. For now I'm going to use void as the return type but we'll come back and change this in a second. So void delete user. we should give it a pass variable and of course a delete mapping to capture the ID. Now in this method just like the update method first we should get the user from our repository and if it doesn't exist we should return a 404 error. So let's change the return type to response entity. Now we don't want to return any data to the client. So we can pass void here. Now to save time, I'm going to borrow some code from the update method. So the first three lines where we fetch a user and return a not found error. So copy paste it here. Otherwise, if we do have a user, we call repository delete user. And finally, we return response entity nocontent. build. Let's restart our application and delete the user with the ID of one. Okay, we got a 204 response. No content. Now, let's look at our users table. Our first user is gone. Beautiful. Now, what if we try to delete a user that doesn't exist? we get a 404 error. In restful APIs, we typically use put or patch for updating resources, but some updates represent an action rather than just modifying a field. Examples are changing a user's password or submitting an approval request. In these cases, it's better to use a post request instead of put or patch. Because we're not just updating a resource, we're creating a request to perform an action. Now, let's see how we can take this concept and use it to implement an endpoint for changing a user's password. So, we're going to send a post request to a new endpoint like this users one/change password. So we are creating a new change password request. Okay, we're not updating a field. We're creating a request to perform an action. Now when hitting this endpoint in the body of the request, we should provide the old and the new password. So let's set old password to 1 2 3 4 and new to let's say 5 6 7 8. Now back to our project here in the details package. Let's add a new class change password request. We annotate this with a data annotation and give it two fields old

### [1:45:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=6300s) Segment 22 (105:00 - 110:00)

and new password. Next, we go to our user controller and define a new method for updating the password. So, public. Now for the return type, we're going to use response entity of void because we're not going to return any data in the response. We can call this change password. Next, we should annotate this with post mapping. So we provide the ID parameter and then add change password. Now because we have the ID parameter, we should add a parameter of type long here and annotate it with pass variable. We also need a parameter for reading the request body. So let me put this on a new line. And then we add the second parameter that is change password request and we should annotate it with request body. Okay. Now in this method first we should fetch the user with our repository and if we can't find it we should return a 404 error. So I'm going to borrow this piece of code from our delete method. Paste it here. Simple. Next, we should validate the old password. So we check if user get password that equals request get old password. Well, we have to inverse this condition to not equal. In this case here, we have two options. Intelligent is suggesting to return a bat request or a 400 error. But I think a more appropriate status here is unauthorized because if a client doesn't provide the correct old password, it's not authorized to perform this action. Now in this class, we don't have a factory method for setting the status to unauthorized. So we have to new up a response entity and here we use HTTP status dot unauthorized. Otherwise, if the password is correct, we should update it. Now, I'm going to go ahead with intellig suggestion. So, let's add these three lines. We simply update the user's password using the new password. And for this, we can use this single line. We don't need to update our mapper. We should use our mapper only when we are dealing with mapping large or complex objects. Then, we save the user. And finally, we return a response with no content. Now, let's restart our application. and test our new endpoint. First, I want to test a scenario where the user doesn't exist. So, user 100. We get a 404 error. Beautiful. Now, let's try user two. Now, currently in my database, the password of this user is 1 2 3 1 2 3. So, obviously the old password is incorrect. Let's send this request. We get a 401 or unauthorized response. Beautiful. Now what if we provide the correct password? We get a 204 response. No error but no content. Now if you refresh our database, we can see that the password is updated. Now currently we're storing the passwords as plain text. Obviously this is something you should avoid at all cost. But later when we talk about security, we'll come back and fix this issue. Okay, for your next exercise, I want you to implement create, update, and delete operations for products. First, implement an endpoint for creating a new product. At this endpoint, we should receive a product DTO with these fields. This is the same product DTO we created earlier in the section. So in this case we are not going to create a separate DTO for creating and updating products because in many cases the fields we need for creating or updating a resource are the same. So we don't always have to create separate DTO's for creating and updating resources. Okay. So we send a product DTO to this endpoint and then we get a 2011 response with the created product. Now updating and deleting the product is pretty straightforward. Go through this PDF. I put the link below this video. Spend about 20 to 30 minutes on this exercise and then come back and see my solution. All right. So here in product controller, we define a new method that returns a response entity of product detail. We call it create product and give it a product DTO object. Now make sure you have annotated this with request body otherwise you will not receive the data posted to the server. Now we annotate this with post mapping. Now in this method first we should map this DTO to a product entity. So we go to our product mapper interface and define a new method that returns a

### [1:50:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=6600s) Segment 23 (110:00 - 115:00)

product object. So we call it two entity and give it a product DTO. Now back to our controller. First we call product mapper dot to entity. We pass the detail and get a new product. Next, we call repository that save product. Now, before implementing the full picture, I just want to return this new product. So, at this point, I don't want to set the status to 2011. We want to implement this with baby steps. So, we call response entity. Now, there is no need to map this product to a new DTO because this DTO that we have up here has all the data that we need to send back to the client. The only thing that is missing is the ID. So after we save the product, we call product DTO set ID. And then we can simply return the same DTO back to the client. Let's restart our application back to Postman. Let's send a post request to the products endpoint. In the body of the request, I'm going to include this JSON object. We have name, price, description, and category ID. Let's send this. All right, here's what we get. Our new product ID is 13. Beautiful. Let's verify that this object is also stored in the database. So, we go to the database window and open the products table. Here's our new product. But look, category ID is missing because in our controller once we map this DTO to an entity, we lose category ID. In this DTO, we have a field called category ID. But there is no field with the same name in this entity. So to solve this issue, we have to fetch the category separately from the database. So first we call category repository. Now, Intelligj should add this as a field in this class. There you go. So, we call category repository that find by ID and here we pass product DTO that get category ID or else null. So, we retrieve the category. Now, we have to do a bit of validation. So, if category is null, then we want to return a bad request to the client. I didn't specify this in the PDF, so that's totally fine if you missed this step because in this section, our focus is not on error handling and data validation. We'll talk about that in the next section. Anyway, we get the category. Now, before saving the product, we should set the category. So, we call product set category and pass the category. Now, let's restart application and hit this endpoint one more time. Okay, back to the database. Here's our new product and category ID is successfully stored here. Now, to verify our error handling code, let's pass an invalid category ID. In this case, we get a 400 response. Beautiful. We're almost done with this method. The final step is returning a 2011 response with the URI of the new resource. To do that we have to add a second parameter here of type URI components builder. After we save the product we need to create this URI. So we call URI builder provide the path then call build and expand and finally call to URI. We get a URI object then we call response entity. created. We provide the URI and the detail in the body of the response. Let's restart and hit this endpoint one more time. We have a 2011 response and in the headers we have the location of the new resource. Beautiful. We're done with the create operation. Now let's implement the update operation. Back to our controller, we add a new method that returns a response entity of product DTO. We call it update product. Now, Intelligia is suggesting a big chunk of code. Let's just add all of that in one go. So, here we have two parameters long ID which is decorated with pass variable. That means we should also annotate this method with put mapping. We also have product DTO in the body of the request. So, first we fetch the product from our database. If it doesn't exist, we return a not found error. Otherwise, we should map this DTO to a product entity. More accurately, we should copy these values into our existing product entity. So, we go to our product mapper and add a new method void update with two parameters product detail and product. Now, we should

### [1:55:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=6900s) Segment 24 (115:00 - 120:00)

annotate this with mapping target otherwise mapping is not going to work. Now, back to our controller. Once we have a product, we call product mapper update and pass these two objects. Next, we save the product and finally we return our DTO to the client. So, product DTO. Again, there is no need to map our product entity back to a DTO. This DTO that we receive in this method has all the data we need. Okay, let's restart the application. Now here in Postman, let's send a put request to products /1. I don't have this product in my database. So now we should get a 404 error. Take a look. There you go. Beautiful. Now let's send a put request to product 4. Okay, we got an internal server error. All right, we got a hibernate exception saying identifier of an instance of product was altered from null to four. What is happening? Well, this was the tricky part of this exercise. So when we call productmapper update, something goes wrong. This product detail doesn't have an ID because in this method we are receiving the ID as a path variable. Okay, so product D is here doesn't have an ID and when we copy ID to this product, the ID of this product changes from whatever we had which was four to null. That's why we get this exception. To fix this issue, we have to go to product mapper and when updating an existing product, we should tell mapr to ignore the ID field. To do that, we customize mapping. So we add the mapping annotation. Target should be ID. And here we set ignore to true. Now let's restart the application and send this request again. All right, we got a 200 response, but the ID that we have in the response is no. That's an easy fix. Back to our controller. I told you that our product detail doesn't have an ID. So after we save this product, we can store the ID in the product DTO just like we did in the create endpoint. So we set the ID and then return this DTO to the client. Let's restart the application and send this request again. Here's the ID. Now let's verify that we have the correct data in our database. So here's product 4. All the values seem to be updated correctly. Now let's change category ID and see what happens. So I'm going to change category ID to two and send this request again. Now let's refresh. Okay, category ID is not updated for the same reason it was not stored when we created a new product. So back to our controller, we have to fetch the category separately. So here we call category repository find by ID. We get this category, store it here, category. If it doesn't exist, we return a bad request. Otherwise, we fetch the product. We do the basic mapping. Then we associate our product with this category with the new category and then save it in the database. Let's restart application and send this request one more time. Okay, no errors and we see category ID 2 in the response. Now back in the database, you can see that category ID is now updated. To verify it one more time, let's change it back to one and resend this request. Good. Now let's refresh this table. And here's the updated category. Beautiful. The final part is the delete operation. So we define a new method public response entity of void. Delete product. We give it a pass variable ID and annotated with delete mapping. In this method, first we use our repository to fetch this product. If it doesn't exist, we return a not found error. Otherwise, we delete this product from our repository and return a response with no content. Let's restart the application. Now, let's send a delete request to this endpoint. We got a 204 response with no content. If we resend this request, we get a 404 error because this product no longer exists. Hey guys, thanks for sticking with me so far. If you're enjoying this tutorial, I wanted to let you know that this is just the first hour of my complete Spring Boot course. The full course is 9 hours long and takes you way beyond the basics. We'll build the back end for an actual e-commerce application with authentication, role-based access control, shopping cart functionality

### [2:00:00](https://www.youtube.com/watch?v=EWd3_I4X32g&t=7200s) Segment 25 (120:00 - 120:00)

payment processing with Stripe, and full deployment to the cloud. So after you watch this tutorial, if you want to learn more and level up your skills, you can enroll in the full course using the link in the description.

---
*Источник: https://ekstraktznaniy.ru/video/20655*