<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: KUMAR NISHANT</title>
    <description>The latest articles on DEV Community by KUMAR NISHANT (@me_nishant_18).</description>
    <link>https://dev.to/me_nishant_18</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1997550%2F5f54b6c0-a722-4128-bf92-a91cbdefad2d.jpeg</url>
      <title>DEV Community: KUMAR NISHANT</title>
      <link>https://dev.to/me_nishant_18</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/me_nishant_18"/>
    <language>en</language>
    <item>
      <title>Why I Stopped Exposing JPA Entities Directly in My Spring Boot API</title>
      <dc:creator>KUMAR NISHANT</dc:creator>
      <pubDate>Mon, 09 Nov 2026 14:32:48 +0000</pubDate>
      <link>https://dev.to/me_nishant_18/why-i-stopped-exposing-jpa-entities-directly-in-my-spring-boot-api-1ne1</link>
      <guid>https://dev.to/me_nishant_18/why-i-stopped-exposing-jpa-entities-directly-in-my-spring-boot-api-1ne1</guid>
      <description>&lt;p&gt;When I started building my Student CRUD API using Spring Boot, my main focus was getting the basic operations working.&lt;/p&gt;

&lt;p&gt;Creating a student, fetching students, updating student details, and deleting a student. I had already organized my application using the &lt;strong&gt;&lt;em&gt;Controller → Service → Repository&lt;/em&gt;&lt;/strong&gt; architecture.&lt;/p&gt;

&lt;p&gt;But there was something I hadn't thought much about:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I use my JPA entity directly as the request and response object of my REST API?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Initially, I did exactly that.&lt;/p&gt;

&lt;p&gt;It worked. I could send JSON from Postman, receive data from the API, and perform database operations without any problem. However, as I started improving the project, I realized that my database entity and my API's data structure shouldn't necessarily be the same thing.&lt;/p&gt;

&lt;p&gt;That's when I introduced &lt;strong&gt;DTOs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I'll explain what DTOs are, why I decided to use them, and how I implemented them in my Student CRUD API.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. How I Initially Handled API Requests
&lt;/h2&gt;

&lt;p&gt;Let's start with the approach I used before introducing DTOs. I had a Student entity that represented the students table in my database.&lt;/p&gt;

&lt;p&gt;A simplified version looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="nd"&gt;@Table&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"students"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Student&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Constructors, getters and setters&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This class served two purposes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It represented the database entity.&lt;/li&gt;
&lt;li&gt;It was also used to receive request data and return API responses.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, my controller could accept a Student directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@PostMapping&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Student&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;Student&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nc"&gt;Student&lt;/span&gt; &lt;span class="n"&gt;savedStudent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;studentService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CREATED&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedStudent&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client could send:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Nishant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nishant@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spring Boot would use Jackson to deserialize the JSON into a Student object.&lt;/p&gt;

&lt;p&gt;The service would save that object using the repository, and the saved entity would be returned to the client.&lt;/p&gt;

&lt;p&gt;Simple, right?&lt;/p&gt;

&lt;p&gt;And technically, there's nothing inherently wrong with making a small application this way. But as an application grows, this approach can create problems.&lt;/p&gt;

&lt;p&gt;Let's understand why.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Problems With Exposing JPA Entities Directly
&lt;/h2&gt;

&lt;p&gt;Using the same class for database persistence and API communication creates a strong connection between two different responsibilities.&lt;/p&gt;

&lt;p&gt;Your entity represents how data is stored.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F712uavt8zme7mlnxny76.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F712uavt8zme7mlnxny76.png" alt="Using JPA Entities directly makes your DB tightly coupled with HTTP, creating vulnerabilities." width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your API request and response represent how clients communicate with your application. These responsibilities may overlap, but they aren't necessarily identical.&lt;/p&gt;

&lt;p&gt;Here are some problems I started considering.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 1: Exposing Internal Database Structure
&lt;/h3&gt;

&lt;p&gt;Imagine my Student entity eventually contains additional fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Student&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;internalNotes&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="n"&gt;createdAt&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now imagine returning this entity directly from an API.&lt;/p&gt;

&lt;p&gt;Depending on the serialization configuration, all these fields could become part of the JSON response. But should a client receive internalNotes?&lt;/p&gt;

&lt;p&gt;Should it know about every field stored in my database?&lt;/p&gt;

&lt;p&gt;Probably not.&lt;/p&gt;

&lt;p&gt;An API should expose only the information that clients are supposed to access. This is one reason to separate the entity from the response object.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 2: Clients Can Send Fields They Shouldn't Control
&lt;/h3&gt;

&lt;p&gt;Consider this request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Nishant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nishant@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I accept the Student entity directly, the client can attempt to send an ID along with the other fields.&lt;/p&gt;

&lt;p&gt;Depending on the entity mapping, setters, and application logic, this could create unintended behavior.&lt;/p&gt;

&lt;p&gt;For example, I generally want the database to generate the student's ID.&lt;/p&gt;

&lt;p&gt;The client shouldn't decide which database ID a newly created student receives.&lt;/p&gt;

&lt;p&gt;This is also related to a broader security concern called mass assignment: allowing incoming data to bind to fields that the client shouldn't be allowed to control.&lt;/p&gt;

&lt;p&gt;Using a dedicated request DTO helps restrict the accepted fields, provided I explicitly map only the permitted values.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 3: Request and Response Structures Can Be Different
&lt;/h3&gt;

&lt;p&gt;Consider creating a student.&lt;/p&gt;

&lt;p&gt;The client needs to send:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Asha"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"asha@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the API should return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Asha"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"asha@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the difference.&lt;/p&gt;

&lt;p&gt;The request doesn't need an ID, but the response does.&lt;/p&gt;

&lt;p&gt;If I use the same entity for both operations, I am making one Java class represent two different API contracts.&lt;/p&gt;

&lt;p&gt;This becomes harder to manage when the request and response requirements start changing independently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 4: Validation Becomes Tied to the Entity
&lt;/h3&gt;

&lt;p&gt;Different operations can have different requirements.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Creating a student requires a name, email, and age.&lt;/li&gt;
&lt;li&gt; Updating a student requires all three fields.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Partially updating a student allows only some fields to be provided.&lt;/p&gt;

&lt;p&gt;If I put all validation rules directly on the entity, it becomes difficult to express these different requirements cleanly.&lt;/p&gt;

&lt;p&gt;I wanted each operation to have its own input structure and validation rules.&lt;/p&gt;

&lt;p&gt;And that's where DTOs became useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. What Is a DTO?
&lt;/h2&gt;

&lt;p&gt;DTO stands for Data Transfer Object.&lt;/p&gt;

&lt;p&gt;A DTO is an object used to transfer data between different parts of an application or across application boundaries.&lt;/p&gt;

&lt;p&gt;In a Spring Boot REST API, DTOs are commonly used to define the data accepted from clients and the data returned to them.&lt;/p&gt;

&lt;p&gt;The important idea is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A DTO defines what data should be transferred, while a JPA entity represents how data is persisted.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client
  |
  | JSON Request
  v
CreateStudentRequest (DTO)
  |
  v
Student Entity
  |
  v
StudentRepository
  |
  v
Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When returning data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database
  |
  v
Student Entity
  |
  v
StudentResponse (DTO)
  |
  v
Client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entity remains responsible for persistence, while DTOs define the API's input and output structures.&lt;/p&gt;

&lt;p&gt;This separation gives us more control over the data entering and leaving our application.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Request DTO vs Response DTO
&lt;/h2&gt;

&lt;p&gt;Before implementing DTOs, it's important to understand that request DTOs and response DTOs serve different purposes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Request DTO&lt;/strong&gt;&lt;br&gt;
A request DTO represents the data that the client is allowed to send to the application.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;CreateStudentRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It doesn't contain the database-generated ID because the client doesn't need to provide it when creating a student.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Response DTO&lt;/strong&gt;&lt;br&gt;
A response DTO represents the data that the application chooses to return to the client.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;StudentResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This includes the ID because the client may need it to retrieve, update, or delete the student later.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2hwad5sd980hyc98j2oz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2hwad5sd980hyc98j2oz.png" alt="Difference between Request DTO and Response DTO" width="800" height="326"&gt;&lt;/a&gt;&lt;br&gt;
Instead of forcing one entity to serve every purpose, we can create DTOs according to the requirements of each operation.&lt;/p&gt;
&lt;h2&gt;
  
  
  5. Implementing DTOs in My Student CRUD API
&lt;/h2&gt;

&lt;p&gt;Now let's look at how I implemented this in my project.&lt;/p&gt;

&lt;p&gt;I created a separate dto package.&lt;br&gt;
My structure looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;com.example.crud
│
├── controller
│   └── StudentController.java
│
├── services
│   └── StudentService.java
│
├── repository
│   └── StudentRepository.java
│
├── entity
│   └── Student.java
│
└── dto
    ├── CreateStudentRequest.java
    ├── UpdateStudentRequest.java
    ├── PatchStudentRequest.java
    └── StudentResponse.java
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I created three request DTOs and one response DTO.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why three request DTOs?&lt;/strong&gt;&lt;br&gt;
Because creating, fully updating, and partially updating a student are three different operations with different input requirements.&lt;/p&gt;
&lt;h3&gt;
  
  
  A. CreateStudentRequest
&lt;/h3&gt;

&lt;p&gt;When creating a student, the client must provide a name, email, and age.&lt;/p&gt;

&lt;p&gt;Here's my implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.crud.dto&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jakarta.validation.constraints.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;CreateStudentRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;

        &lt;span class="nd"&gt;@NotBlank&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Name is required"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Size&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
              &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Name must be within 100 characters"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;

        &lt;span class="nd"&gt;@NotBlank&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Email is required"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Email&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Email must be valid email"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Size&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
              &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Email must be within 100 characters"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;

        &lt;span class="nd"&gt;@Min&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Age must be at least 1"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Max&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Age must be at most 120"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;

&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth noticing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@NotBlank&lt;/code&gt; ensures that the name and email aren't null, empty, or whitespace-only.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@Size&lt;/code&gt; restricts the maximum length.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@Email&lt;/code&gt; checks whether the email follows the expected email format.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@Min&lt;/code&gt; and &lt;code&gt;@Max&lt;/code&gt; define the allowed age range.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are Jakarta Bean Validation constraints. I'll cover validation in detail in a separate article.&lt;/p&gt;

&lt;p&gt;Notice that I haven't included the id field. The database is responsible for generating it.&lt;/p&gt;

&lt;h3&gt;
  
  
  B. UpdateStudentRequest
&lt;/h3&gt;

&lt;p&gt;A full update is different from a partial update.&lt;/p&gt;

&lt;p&gt;When using PUT, I expect the client to provide all the fields required for the update.&lt;/p&gt;

&lt;p&gt;Here's my DTO:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.crud.dto&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jakarta.validation.constraints.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;UpdateStudentRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;

        &lt;span class="nd"&gt;@NotBlank&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Name is required"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Size&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
              &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Name must be within 100 characters"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;

        &lt;span class="nd"&gt;@NotBlank&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Email is required"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Email&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Email must be a valid email"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Size&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
              &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Email must be within 100 characters"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;

        &lt;span class="nd"&gt;@NotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Age is required"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Min&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Age must be at least 1"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Max&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Age must be at most 120"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;

&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;@NotNull&lt;/code&gt; is important for age.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt;&lt;br&gt;
Because Integer is a wrapper class and can hold null.&lt;/p&gt;

&lt;p&gt;For a full update, I want the age to be provided rather than silently accepting a missing value.&lt;/p&gt;
&lt;h3&gt;
  
  
  C. PatchStudentRequest
&lt;/h3&gt;

&lt;p&gt;Now comes the interesting part.&lt;/p&gt;

&lt;p&gt;PATCH is used for partial updates. Suppose a student wants to change only their age.&lt;/p&gt;

&lt;p&gt;The client can send:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It shouldn't be necessary to send the name and email again.&lt;/p&gt;

&lt;p&gt;That's why I created a separate DTO:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.crud.dto&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;jakarta.validation.constraints.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;PatchStudentRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;

        &lt;span class="nd"&gt;@Pattern&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regexp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;".*\\S.*"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                 &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name must not be blank"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Size&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
              &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name must be at most 100 characters"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;

        &lt;span class="nd"&gt;@Pattern&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regexp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;".*\\S.*"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                 &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"email must not be blank"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Email&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"email must be a valid email address"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Size&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
              &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"email must be at most 100 characters"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;

        &lt;span class="nd"&gt;@Min&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"age must be at least 1"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Max&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"age must be at most 120"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;

&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, I don't use &lt;code&gt;@NotBlank&lt;/code&gt; because the fields are optional.&lt;/p&gt;

&lt;p&gt;If the client doesn't provide a field, its value will be null. But if the client does provide a name or email, I don't want it to contain only whitespace.&lt;/p&gt;

&lt;p&gt;That's why I used &lt;code&gt;@Pattern&lt;/code&gt; for those fields.&lt;/p&gt;

&lt;p&gt;My service checks which values are present and updates only those fields.&lt;/p&gt;

&lt;p&gt;One limitation of this implementation is worth mentioning: with ordinary nullable fields, null means "&lt;u&gt;not provided&lt;/u&gt;". So this approach cannot distinguish an omitted field from an explicitly supplied null.&lt;/p&gt;

&lt;p&gt;For my current Student API, that behavior is acceptable.&lt;/p&gt;

&lt;h3&gt;
  
  
  D. StudentResponse
&lt;/h3&gt;

&lt;p&gt;Finally, I needed a DTO to control what the API returns.&lt;/p&gt;

&lt;p&gt;Here's my implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.crud.dto&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.example.crud.entity.Student&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;StudentResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;StudentResponse&lt;/span&gt; &lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Student&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StudentResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAge&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Something interesting here is the &lt;code&gt;static from()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Instead of manually mapping the entity to a response DTO everywhere, I created one reusable conversion method.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;StudentResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It takes a Student entity and creates a StudentResponse object from it.&lt;/p&gt;

&lt;p&gt;This keeps the conversion logic in one place and makes the service methods cleaner.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. How Everything Works Together
&lt;/h2&gt;

&lt;p&gt;Now let's connect all these pieces. The architecture hasn't changed.&lt;/p&gt;

&lt;p&gt;I still use:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Controller → Service → Repository&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What changed is how data moves through these layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before DTOs&lt;/strong&gt;&lt;br&gt;
Initially, the entity was used directly for API communication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6tlem6m5xx7r05bkm2fk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6tlem6m5xx7r05bkm2fk.png" alt="Client-to-Database Student Data Flow Before DTO" width="800" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The entity was doing two jobs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Representing the database structure.&lt;/li&gt;
&lt;li&gt;Representing the API request and response structure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;After DTOs&lt;/strong&gt;&lt;br&gt;
After introducing DTOs, the flow became:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5876kfslp9xw7upm7j07.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5876kfslp9xw7upm7j07.png" alt="Client-to-Database Student Data Flow After DTO" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the responsibilities are clearer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The request DTO defines what the client can send.&lt;/li&gt;
&lt;li&gt;The service converts the request DTO into an entity.&lt;/li&gt;
&lt;li&gt;The repository handles persistence.&lt;/li&gt;
&lt;li&gt;The response DTO defines what the client receives.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;Controller → Service → Repository&lt;/code&gt; architecture remains exactly the same.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DTOs improve the data contract between the client and the application. They don't replace the existing layers.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  7. A Real Example: Creating a Student
&lt;/h2&gt;

&lt;p&gt;Let's follow a complete create operation.&lt;/p&gt;

&lt;p&gt;The client sends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /api/students
Content-Type: application/json
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Request body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Asha"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"asha@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 1: Receive the Request
&lt;/h3&gt;

&lt;p&gt;The controller receives a CreateStudentRequest.&lt;/p&gt;

&lt;p&gt;Conceptually, the method looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@PostMapping&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StudentResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nd"&gt;@Valid&lt;/span&gt; &lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;CreateStudentRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nc"&gt;StudentResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;studentService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CREATED&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@Valid&lt;/code&gt; triggers validation of the request DTO when the appropriate validation dependency is configured.&lt;/p&gt;

&lt;p&gt;I'll explain this in more detail in &lt;a href="https://dev.to/me_nishant_18/why-im-choosing-to-learn-in-public-1kmd"&gt;&lt;u&gt;&lt;strong&gt;My Next Article&lt;/strong&gt;&lt;/u&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Convert the DTO into an Entity
&lt;/h3&gt;

&lt;p&gt;The service receives the request DTO.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Transactional
public StudentResponse create(CreateStudentRequest request) {

    Student student = new Student(
            request.name(),
            request.email(),
            request.age()
    );

    Student saved = repo.save(student);

    return StudentResponse.from(saved);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that the service creates a new Student entity.&lt;/p&gt;

&lt;p&gt;The repository doesn't need to know anything about CreateStudentRequest.It only works with the entity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Save the Entity
&lt;/h3&gt;

&lt;p&gt;The repository saves the student in the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repo.save(student);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The saved entity contains the generated database ID.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Convert the Entity into a Response DTO
&lt;/h3&gt;

&lt;p&gt;The service converts the saved entity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;StudentResponse.from(saved);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is a StudentResponse object.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Return the Response
&lt;/h3&gt;

&lt;p&gt;The client receives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "id": 1,
    "name": "Asha",
    "email": "asha@example.com",
    "age": 21
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client gets exactly the information the API intends to expose.&lt;/p&gt;

&lt;p&gt;It doesn't need to know how the entity is structured internally.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. What Changed After Introducing DTOs?
&lt;/h2&gt;

&lt;p&gt;Here's a quick comparison.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff4xne24kksyt75c474kd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff4xne24kksyt75c474kd.png" alt="Before DTOs vs After DTOs comparison" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DTOs also make it easier to change the API without necessarily changing the database entity.&lt;/p&gt;

&lt;p&gt;For example, if I later want to return a student's full name instead of separate first and last names, I can change the response DTO and its mapping without necessarily changing the database structure.&lt;/p&gt;

&lt;p&gt;That's the flexibility I wanted.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. What I Learned
&lt;/h2&gt;

&lt;p&gt;Before implementing DTOs, I was mainly thinking about making my REST endpoints work.&lt;/p&gt;

&lt;p&gt;But this implementation helped me understand something important:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Just because two objects contain similar data doesn't mean they should have the same responsibility.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A JPA entity and a DTO might contain the same fields, but they serve different purposes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An entity represents persisted data.&lt;/li&gt;
&lt;li&gt;A request DTO represents accepted input.&lt;/li&gt;
&lt;li&gt;A response DTO represents exposed output.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also learned that separating these responsibilities gives me more control over my API as it grows.&lt;/p&gt;

&lt;p&gt;Of course, DTOs introduce some additional classes and mapping code. For a very small application, this can feel like extra work. But when an application has multiple endpoints, different request requirements, and changing API contracts, that separation becomes valuable.&lt;/p&gt;

&lt;p&gt;I'm still improving my Student CRUD API, and this was one of the steps that helped me understand how to structure a Spring Boot application more thoughtfully.&lt;/p&gt;

&lt;p&gt;There is still a lot to explore, and that's exactly what I'm documenting here.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;DTOs define the structure of incoming data, but they don't automatically guarantee that the data is valid.&lt;/p&gt;

&lt;p&gt;For example, what happens if someone sends an empty name, an invalid email, or an age of -5?&lt;/p&gt;

&lt;p&gt;That's where Bean Validation comes in.&lt;/p&gt;

&lt;p&gt;I'll cover that in my next article:&lt;br&gt;
&lt;strong&gt;&lt;u&gt;How I Added Input Validation to My Spring Boot REST API.&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Let's Connect! 👋
&lt;/h2&gt;

&lt;p&gt;I'm sharing my learning journey as I build projects and improve my backend development skills.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/K-Nishant-18" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;: Explore my projects&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.linkedin.com/in/kumar-nishant-dev/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;: Connect with me&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://x.com/me_nishant_18" rel="noopener noreferrer"&gt;X (Twitter)&lt;/a&gt;: Follow my journey&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kumar-nishant.is-a.dev/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;: Visit my website&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're also learning Spring Boot, follow me here on DEV.to. Let's learn and grow together!&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>dto</category>
      <category>java</category>
    </item>
    <item>
      <title>Why I'm Choosing to Learn in Public</title>
      <dc:creator>KUMAR NISHANT</dc:creator>
      <pubDate>Tue, 20 Oct 2026 22:25:44 +0000</pubDate>
      <link>https://dev.to/me_nishant_18/why-im-choosing-to-learn-in-public-1kmd</link>
      <guid>https://dev.to/me_nishant_18/why-im-choosing-to-learn-in-public-1kmd</guid>
      <description>&lt;p&gt;I want to be a better developer, and I believe that learning doesn't stop after understanding a concept. It's also about applying it, making mistakes, and learning from them.&lt;/p&gt;

&lt;p&gt;That's why I've decided to &lt;strong&gt;learn in public&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I'm not a expert, and I still have a lot to learn. But I doesn't want to wait until I know everything before sharing my journey.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I'll share.
&lt;/h3&gt;

&lt;p&gt;I'll use this space to document my learning journey, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What I learn:&lt;/strong&gt; Java, Spring Boot, and full-stack development.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mistakes and debugging:&lt;/strong&gt; Problems I face , how I solve them, and what I learn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Projects I build:&lt;/strong&gt; Challenges, decisions, and lessons from real projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DSA practice:&lt;/strong&gt; Problems I solve, approaches I try, and patterns I discover.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I want to share what I genuinely understand, not pretend to know everything.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I'm doing this.
&lt;/h3&gt;

&lt;p&gt;Writing about what I learn can help me understand concepts better ad identify gaps in my knowledge.&lt;/p&gt;

&lt;p&gt;I also hope to connect with other developers, exchange ideas, and build my professional presence by sharing my work and progress.&lt;/p&gt;

&lt;p&gt;I know that simply writing blogs won't make me a better developer. I'll still need to practice, build things, and keep improving. &lt;/p&gt;

&lt;h3&gt;
  
  
  Starting Before I'm Ready
&lt;/h3&gt;

&lt;p&gt;Sometimes, I feel I should learn more before sharing anything. But if I keep waiting until I know everything, I might never start.&lt;/p&gt;

&lt;p&gt;So, I'm starting now. I'll share what I learn, what goes wrong, and what I discover along the way.&lt;/p&gt;

&lt;p&gt;I'm here to learn, improve, and document the process - not to pretend I have all the answers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's Connect! 👋
&lt;/h3&gt;

&lt;p&gt;Follow my journey and explore what I'm building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/kumar-nishant-dev/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/K-Nishant-18" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://x.com/me_nishant_18" rel="noopener noreferrer"&gt;X (Twitter)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kumar-nishant.vercel.app/" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Follow me on DEV.to too!&lt;/strong&gt; Let's learn, build, and grow together. ❤️&lt;/p&gt;

</description>
      <category>learninginpublic</category>
      <category>beginners</category>
      <category>career</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
