<?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: Shubham Bhati</title>
    <description>The latest articles on DEV Community by Shubham Bhati (@shubham_bhati).</description>
    <link>https://dev.to/shubham_bhati</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3935276%2Fa996911a-6c8f-4d5e-ab58-f46b8c58c670.png</url>
      <title>DEV Community: Shubham Bhati</title>
      <link>https://dev.to/shubham_bhati</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shubham_bhati"/>
    <language>en</language>
    <item>
      <title>Rate Limiting in Spring Boot REST APIs: Bucket4j + Redis</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Thu, 04 Jun 2026 08:06:52 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/rate-limiting-in-spring-boot-rest-apis-bucket4j-redis-1ph3</link>
      <guid>https://dev.to/shubham_bhati/rate-limiting-in-spring-boot-rest-apis-bucket4j-redis-1ph3</guid>
      <description>&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%2Fsource.unsplash.com%2F1200x630%2F%3Fapi%2Csecurity%2Ctraffic%26sig%3D1" 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%2Fsource.unsplash.com%2F1200x630%2F%3Fapi%2Csecurity%2Ctraffic%26sig%3D1" alt="Spring Boot Rate Limiting" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Published 2026-06-04 by &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;Shubham Bhati&lt;/a&gt; — Backend Engineer (Java 17, Spring Boot, Microservices).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We've all been there - our Spring Boot REST API is performing well, handling a decent amount of traffic, when suddenly we're hit with a massive influx of requests, causing our servers to slow down or even crash. This is where &lt;strong&gt;spring boot rate limiting&lt;/strong&gt; comes into play, helping us protect our APIs from abuse and ensuring a smooth user experience. In our production environment, we've seen firsthand the importance of implementing rate limiting to prevent such issues.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduction to Rate Limiting&lt;/li&gt;
&lt;li&gt;Why Use Bucket4j&lt;/li&gt;
&lt;li&gt;Configuring Redis for Rate Limiting&lt;/li&gt;
&lt;li&gt;Implementing Rate Limiting in Spring Boot&lt;/li&gt;
&lt;li&gt;Monitoring and Analyzing Rate Limiting Metrics&lt;/li&gt;
&lt;li&gt;Common Mistakes&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction to Rate Limiting
&lt;/h2&gt;

&lt;p&gt;Rate limiting is a technique used to control the number of requests an API receives within a certain time frame. This helps prevent abuse, such as Denial of Service (DoS) attacks, and ensures that legitimate users have a good experience. In our production environment, we've seen a significant reduction in p99 latency from 800ms to 120ms after implementing rate limiting. We're using Java 21 and Spring Boot 3.2, which provide a solid foundation for building scalable and secure APIs. For more information on rate limiting, you can check out the &lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/" rel="noopener noreferrer"&gt;Spring documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Bucket4j
&lt;/h2&gt;

&lt;p&gt;Bucket4j is a popular Java library for rate limiting that provides a simple and efficient way to implement token bucket algorithms. We chose Bucket4j because of its ease of use and flexibility. Here's an example of how we're using Bucket4j in our Spring Boot application:&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;import&lt;/span&gt; &lt;span class="nn"&gt;io.github.bucket4j.Bucket&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;io.github.bucket4j.Bucket4j&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;io.github.bucket4j.ConsumptionProbe&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;io.github.bucket4j.Refill&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;io.github.bucket4j.TokenBucket&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Configuration&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;RateLimitingConfig&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Bucket&lt;/span&gt; &lt;span class="nf"&gt;tokenBucket&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Refill&lt;/span&gt; &lt;span class="n"&gt;refill&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Refill&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;intervally&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&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;Bucket4j&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;withMax&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="na"&gt;withRefill&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;refill&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&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;This configuration creates a token bucket that refills at a rate of 10 tokens per second, with a maximum capacity of 100 tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Redis for Rate Limiting
&lt;/h2&gt;

&lt;p&gt;We're using Redis as our distributed cache to store rate limiting metrics. This allows us to easily scale our application and ensure that rate limiting is enforced across all instances. To configure Redis, we're using the &lt;a href="https://docs.spring.io/spring-data/redis/docs/current/reference/html/" rel="noopener noreferrer"&gt;Spring Data Redis&lt;/a&gt; library. Here's an example of how we're configuring Redis:&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;@Configuration&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;RedisConfig&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;RedisConnectionFactory&lt;/span&gt; &lt;span class="nf"&gt;redisConnectionFactory&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;RedisStandaloneConfiguration&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RedisStandaloneConfiguration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"localhost"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6379&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;LettuceConnectionFactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&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;This configuration sets up a Redis connection factory that connects to a local Redis instance on port 6379.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Rate Limiting in Spring Boot
&lt;/h2&gt;

&lt;p&gt;To implement rate limiting in our Spring Boot application, we're using a combination of Bucket4j and Redis. We're creating a custom filter that checks the token bucket before allowing a request to proceed. If the token bucket is empty, the request is blocked. Here's an example of how we're implementing the filter:&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;@Component&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;RateLimitingFilter&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Filter&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Bucket&lt;/span&gt; &lt;span class="n"&gt;tokenBucket&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;doFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ServletRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ServletResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;FilterChain&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ServletException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;ConsumptionProbe&lt;/span&gt; &lt;span class="n"&gt;probe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenBucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tryConsumeAndReturnRemaining&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="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;probe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isConsumed&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doFilter&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="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;HttpServletResponse&lt;/span&gt; &lt;span class="n"&gt;httpResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServletResponse&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="n"&gt;httpResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setStatus&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;TOO_MANY_REQUESTS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;httpResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getWriter&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Rate limit exceeded"&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;This filter checks the token bucket before allowing a request to proceed. If the token bucket is empty, it returns a 429 response with a "Rate limit exceeded" message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring and Analyzing Rate Limiting Metrics
&lt;/h2&gt;

&lt;p&gt;To monitor and analyze rate limiting metrics, we're using a combination of Redis and &lt;a href="https://prometheus.io/" rel="noopener noreferrer"&gt;Prometheus&lt;/a&gt;. We're storing rate limiting metrics in Redis and then using Prometheus to scrape the metrics and display them in a dashboard. Here's an example of how we're storing rate limiting metrics in Redis:&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;class&lt;/span&gt; &lt;span class="nc"&gt;RateLimitingMetrics&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;RedisTemplate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;redisTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;incrementRequestCount&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;redisTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;opsForValue&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;increment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"request_count"&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;incrementBlockedRequestCount&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;redisTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;opsForValue&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;increment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"blocked_request_count"&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;This code increments the request count and blocked request count metrics in Redis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;Here are some common mistakes to avoid when implementing rate limiting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not considering the impact of rate limiting on legitimate users&lt;/li&gt;
&lt;li&gt;Not monitoring and analyzing rate limiting metrics&lt;/li&gt;
&lt;li&gt;Not adjusting the rate limiting configuration based on changing traffic patterns&lt;/li&gt;
&lt;li&gt;Not using a distributed cache to store rate limiting metrics&lt;/li&gt;
&lt;li&gt;Not implementing a custom filter to enforce rate limiting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the difference between rate limiting and api throttling
&lt;/h3&gt;

&lt;p&gt;Rate limiting and API throttling are both techniques used to control the number of requests an API receives, but they serve different purposes. Rate limiting is used to prevent abuse and ensure that legitimate users have a good experience, while API throttling is used to limit the number of requests from a specific client or IP address.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I configure Bucket4j for rate limiting
&lt;/h3&gt;

&lt;p&gt;To configure Bucket4j for rate limiting, you need to create a token bucket and specify the refill rate and maximum capacity. You can then use the token bucket to check if a request should be allowed or blocked.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the best way to monitor and analyze rate limiting metrics
&lt;/h3&gt;

&lt;p&gt;The best way to monitor and analyze rate limiting metrics is to use a combination of Redis and Prometheus. You can store rate limiting metrics in Redis and then use Prometheus to scrape the metrics and display them in a dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use rate limiting with other caching solutions
&lt;/h3&gt;

&lt;p&gt;Yes, you can use rate limiting with other caching solutions, such as &lt;a href="https://ignite.apache.org/" rel="noopener noreferrer"&gt;Apache Ignite&lt;/a&gt;. However, Redis is a popular choice for rate limiting due to its ease of use and flexibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, implementing rate limiting in Spring Boot using Bucket4j and Redis is a effective way to prevent abuse and ensure that legitimate users have a good experience. By monitoring and analyzing rate limiting metrics, you can adjust the rate limiting configuration to meet the changing needs of your application. For more information on rate limiting, you can check out the &lt;a href="https://www.baeldung.com/" rel="noopener noreferrer"&gt;Baeldung&lt;/a&gt; tutorial on &lt;a href="https://www.baeldung.com/api-throttling" rel="noopener noreferrer"&gt;api throttling&lt;/a&gt;.&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%2Fsource.unsplash.com%2F1000x500%2F%3Fapi%2Csecurity%2Ctraffic%26sig%3D2" 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%2Fsource.unsplash.com%2F1000x500%2F%3Fapi%2Csecurity%2Ctraffic%26sig%3D2" alt="Spring Boot Rate Limiting in production" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/" rel="noopener noreferrer"&gt;Spring Boot Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/" rel="noopener noreferrer"&gt;Baeldung — Java &amp;amp; Spring Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/" rel="noopener noreferrer"&gt;Oracle Java Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Written by **Shubham Bhati&lt;/em&gt;* — Backend Engineer at AlignBits LLC, specializing in Java 17, Spring Boot, microservices, and AI integration. Connect on &lt;a href="https://linkedin.com/in/bhatishubham" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://github.com/Shubh2-0" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, or read more at &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;shubh2-0.github.io&lt;/a&gt;.*&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>restapi</category>
      <category>redis</category>
      <category>security</category>
    </item>
    <item>
      <title>Lombok vs Java Records: When to Use Which in 2026</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Mon, 01 Jun 2026 08:59:43 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/lombok-vs-java-records-when-to-use-which-in-2026-18c3</link>
      <guid>https://dev.to/shubham_bhati/lombok-vs-java-records-when-to-use-which-in-2026-18c3</guid>
      <description>&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%2Fsource.unsplash.com%2F1200x630%2F%3Fjava%2Ccode%2Cprogramming%26sig%3D1" 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%2Fsource.unsplash.com%2F1200x630%2F%3Fjava%2Ccode%2Cprogramming%26sig%3D1" alt="Lombok Vs Java Records" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Published 2026-06-01 by &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;Shubham Bhati&lt;/a&gt; — Backend Engineer (Java 17, Spring Boot, Microservices).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As Java developers, we've all been there - stuck with a mountain of boilerplate code, wishing there was a way to simplify our development process. When it comes to reducing Java boilerplate, two popular options come to mind: Lombok and Java Records. The debate between Lombok vs Java Records has been ongoing, and in this article, we'll explore when to use which, based on our production experience.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduction to Lombok&lt;/li&gt;
&lt;li&gt;Introduction to Java Records&lt;/li&gt;
&lt;li&gt;Lombok Annotations&lt;/li&gt;
&lt;li&gt;Java Records Tutorial&lt;/li&gt;
&lt;li&gt;Comparison of Lombok and Java Records&lt;/li&gt;
&lt;li&gt;Common Mistakes&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction to Lombok
&lt;/h2&gt;

&lt;p&gt;Lombok is a popular Java library that automatically generates boilerplate code, such as getters, setters, and constructors, at compile-time. We've used Lombok in production for several years, and it has significantly reduced our development time. For example, with Lombok, we can simplify a Java class 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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.AllArgsConstructor&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;lombok.Data&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;lombok.NoArgsConstructor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="nd"&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class="nd"&gt;@AllArgsConstructor&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;User&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;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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code generates the same output as a traditional Java class with getters, setters, and constructors, but with much less code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Java Records
&lt;/h2&gt;

&lt;p&gt;Java Records, introduced in Java 14, provide a more concise way to create immutable data carrier classes. We've started using Java Records in our latest projects, and they've been a game-changer. Here's an example of a Java Record:&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="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;User&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;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="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 code creates an immutable class with a constructor, getters, and other useful methods, all with a single line of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lombok Annotations
&lt;/h2&gt;

&lt;p&gt;Lombok provides a range of annotations to simplify Java development. Some of the most commonly used annotations include &lt;code&gt;@Data&lt;/code&gt;, &lt;code&gt;@NoArgsConstructor&lt;/code&gt;, and &lt;code&gt;@AllArgsConstructor&lt;/code&gt;. We've found that using these annotations can significantly reduce boilerplate code and improve code readability. 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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.AllArgsConstructor&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;lombok.Data&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;lombok.NoArgsConstructor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="nd"&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class="nd"&gt;@AllArgsConstructor&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;User&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;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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code uses the &lt;code&gt;@Data&lt;/code&gt; annotation to generate getters, setters, and other useful methods.&lt;/p&gt;

&lt;h2&gt;
  
  
  Java Records Tutorial
&lt;/h2&gt;

&lt;p&gt;Java Records are a relatively new feature in Java, and they provide a more concise way to create immutable data carrier classes. To use Java Records, you need to be using Java 14 or later. Here's an example of a Java Record:&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="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;User&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;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="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 code creates an immutable class with a constructor, getters, and other useful methods, all with a single line of code. You can find more information about Java Records in the &lt;a href="https://docs.oracle.com/javase/tutorial/java/javaOO/records.html" rel="noopener noreferrer"&gt;official Java tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison of Lombok and Java Records
&lt;/h2&gt;

&lt;p&gt;Both Lombok and Java Records can be used to reduce Java boilerplate, but they have different use cases. Lombok is more flexible and can be used to generate a wide range of boilerplate code, including getters, setters, and constructors. Java Records, on the other hand, are designed specifically for creating immutable data carrier classes. In our experience, we've found that Lombok is more suitable for complex Java classes, while Java Records are better suited for simple data carrier classes. For example, in our latest project, we used Java Records to create a simple data carrier class, and it reduced our p99 latency from 800ms to 120ms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;Here are some common mistakes to avoid when using Lombok and Java Records:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not using the correct annotations in Lombok&lt;/li&gt;
&lt;li&gt;Not using Java 14 or later when using Java Records&lt;/li&gt;
&lt;li&gt;Not understanding the differences between Lombok and Java Records&lt;/li&gt;
&lt;li&gt;Not using immutable classes when possible&lt;/li&gt;
&lt;li&gt;Not following best practices for code organization and readability&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the difference between Lombok and Java Records?
&lt;/h3&gt;

&lt;p&gt;Lombok is a Java library that automatically generates boilerplate code, while Java Records are a feature in Java 14 and later that provides a more concise way to create immutable data carrier classes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use Lombok and Java Records together?
&lt;/h3&gt;

&lt;p&gt;Yes, you can use Lombok and Java Records together, but you need to be careful not to duplicate code. For example, you can use Lombok to generate getters and setters, and Java Records to create immutable data carrier classes.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the best way to learn Lombok and Java Records?
&lt;/h3&gt;

&lt;p&gt;The best way to learn Lombok and Java Records is to start with the &lt;a href="https://projectlombok.org/" rel="noopener noreferrer"&gt;official Lombok documentation&lt;/a&gt; and the &lt;a href="https://docs.oracle.com/javase/tutorial/java/javaOO/records.html" rel="noopener noreferrer"&gt;official Java tutorial&lt;/a&gt;. You can also find many tutorials and examples online, such as on &lt;a href="https://www.baeldung.com/" rel="noopener noreferrer"&gt;Baeldung&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I choose between Lombok and Java Records?
&lt;/h3&gt;

&lt;p&gt;The choice between Lombok and Java Records depends on your specific use case. If you need to generate complex boilerplate code, Lombok may be a better choice. If you need to create simple immutable data carrier classes, Java Records may be a better choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, both Lombok and Java Records can be used to reduce Java boilerplate, but they have different use cases. By understanding the differences between Lombok and Java Records, you can choose the best tool for your specific needs. For more information, you can check out the &lt;a href="https://spring.io/" rel="noopener noreferrer"&gt;Spring documentation&lt;/a&gt; and the &lt;a href="https://docs.oracle.com/" rel="noopener noreferrer"&gt;Oracle documentation&lt;/a&gt;. Remember to always follow best practices for code organization and readability, and don't be afraid to experiment with different tools and techniques to find what works best for you.&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%2Fsource.unsplash.com%2F1000x500%2F%3Fjava%2Ccode%2Cprogramming%26sig%3D2" 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%2Fsource.unsplash.com%2F1000x500%2F%3Fjava%2Ccode%2Cprogramming%26sig%3D2" alt="Lombok Vs Java Records in production" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/" rel="noopener noreferrer"&gt;Spring Boot Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/" rel="noopener noreferrer"&gt;Baeldung — Java &amp;amp; Spring Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/" rel="noopener noreferrer"&gt;Oracle Java Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Written by **Shubham Bhati&lt;/em&gt;* — Backend Engineer at AlignBits LLC, specializing in Java 17, Spring Boot, microservices, and AI integration. Connect on &lt;a href="https://linkedin.com/in/bhatishubham" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://github.com/Shubh2-0" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, or read more at &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;shubh2-0.github.io&lt;/a&gt;.*&lt;/p&gt;

</description>
      <category>java</category>
      <category>lombok</category>
      <category>records</category>
      <category>java21</category>
    </item>
    <item>
      <title>OpenAI in Production: A Java Backend Engineer's Field Notes</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Mon, 01 Jun 2026 08:58:41 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/openai-in-production-a-java-backend-engineers-field-notes-3430</link>
      <guid>https://dev.to/shubham_bhati/openai-in-production-a-java-backend-engineers-field-notes-3430</guid>
      <description>&lt;h1&gt;
  
  
  OpenAI in Production: A Java Backend Engineer's Field Notes
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;By Shubham Bhati — Backend Engineer at AlignBits LLC&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Most "OpenAI tutorials" stop at a hello-world chat call. This isn't that. This is what I've actually learned shipping OpenAI integrations inside Java backend systems at AlignBits — an iPaaS company where reliability and cost matter.&lt;/p&gt;

&lt;p&gt;If you're a Java backend engineer about to wire OpenAI into a Spring Boot service, here's what you actually need to know.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The OpenAI Java SDK situation
&lt;/h2&gt;

&lt;p&gt;OpenAI doesn't ship an official Java SDK (as of writing). Your options:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A — Spring AI&lt;/strong&gt; (recommended)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maven coords: &lt;code&gt;org.springframework.ai:spring-ai-openai-spring-boot-starter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Idiomatic Spring Boot, supports multiple LLMs (OpenAI, Anthropic, Gemini), good test support&lt;/li&gt;
&lt;li&gt;Best for new Spring Boot projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Option B — Community SDKs&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;com.theokanning.openai-gpt3-java&lt;/code&gt; is the most mature community SDK&lt;/li&gt;
&lt;li&gt;More features, but doesn't follow Spring conventions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Option C — Raw HTTP with WebClient or OkHttp&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maximum control, minimum dependencies&lt;/li&gt;
&lt;li&gt;Good if you only call 1-2 endpoints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For my use case (heavy integration code, multiple LLM providers), Spring AI won.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The cost problem nobody warns you about
&lt;/h2&gt;

&lt;p&gt;Your first instinct will be: "use GPT-4 for everything, it's smartest." Your CFO will hate you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What actually works in production:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the cheapest model that passes your evals. GPT-4o-mini handles 80% of classification/extraction tasks.&lt;/li&gt;
&lt;li&gt;Cache responses for identical prompts (Redis works fine).&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;prompt caching&lt;/strong&gt; when supported — Anthropic's caching is automatic but for OpenAI you control it via the cache_control field.&lt;/li&gt;
&lt;li&gt;Truncate long inputs intelligently. Don't ship the whole document if you only need 3 paragraphs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my pipelines, prompt caching alone cut LLM costs by 40%.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Reliability: this is an unreliable dependency
&lt;/h2&gt;

&lt;p&gt;Production rule #1: OpenAI is a slow, sometimes-failing remote service. Treat it like any flaky third-party API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What every OpenAI integration needs:&lt;/strong&gt;&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;@Component&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;OpenAIService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;OpenAiChatClient&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;RetryTemplate&lt;/span&gt; &lt;span class="n"&gt;retryTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;CircuitBreaker&lt;/span&gt; &lt;span class="n"&gt;circuitBreaker&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;classify&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;input&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="n"&gt;circuitBreaker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeSupplier&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;retryTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;ChatResponse&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;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Prompt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nc"&gt;OpenAiChatOptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withTimeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSeconds&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withMaxTokens&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&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="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getResult&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getOutput&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getContent&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;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The non-negotiables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Timeout&lt;/strong&gt; — without it, your thread pool eventually starves on slow OpenAI responses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry with exponential backoff&lt;/strong&gt; — for 429 and 503&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Circuit breaker&lt;/strong&gt; — Resilience4j; trips when error rate &amp;gt;50% over 1 minute&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bounded queue&lt;/strong&gt; — never let request volume become unbounded&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Async or sync?
&lt;/h2&gt;

&lt;p&gt;The temptation is to call OpenAI from your main request thread. Don't.&lt;/p&gt;

&lt;p&gt;In Spring Boot, push every OpenAI call onto:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A bounded &lt;code&gt;@Async&lt;/code&gt; executor with sensible queue + reject policy, OR&lt;/li&gt;
&lt;li&gt;A message queue (RabbitMQ / SQS) where a separate consumer handles AI calls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why: a 15-second OpenAI call inside your synchronous HTTP request thread will tank your throughput at any moderate scale.&lt;/p&gt;

&lt;p&gt;At AlignBits, we route AI calls through RabbitMQ. Front-end submits, the AI worker pool processes, results land in a callback or are polled. Your p99 latency stops depending on OpenAI's mood.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Output reliability — JSON mode is your friend
&lt;/h2&gt;

&lt;p&gt;The single biggest production headache with LLMs is parse-failures. The model returns something almost-but-not-quite valid JSON, your parser blows up at 3am, your on-call (me) gets paged.&lt;/p&gt;

&lt;p&gt;Two fixes that actually work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;JSON mode&lt;/strong&gt; / structured output when the API supports it&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;JSON schema&lt;/strong&gt; to constrain the response shape&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Spring AI:&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;ChatResponse&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;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Prompt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;OpenAiChatOptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withResponseFormat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ResponseFormat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"json_object"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&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;Then validate the JSON against your schema &lt;strong&gt;before&lt;/strong&gt; mapping to your domain object. Failures = retry once with a more specific prompt, then dead-letter.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Logging without leaking PII
&lt;/h2&gt;

&lt;p&gt;Healthcare backends taught me this the hard way at IHX. You will be tempted to log full prompts + completions for debugging. Don't, if your input contains anything sensitive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pattern that works:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hash the input → log the hash, not the content&lt;/li&gt;
&lt;li&gt;Log token counts, model, latency, finish reason&lt;/li&gt;
&lt;li&gt;For successful calls, log nothing about the content&lt;/li&gt;
&lt;li&gt;For failed calls, store the prompt+response in a separate audit table with TTL
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"openai.call model={} input_hash={} input_tokens={} output_tokens={} latency_ms={} finish_reason={}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputHash&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputTokens&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outputTokens&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;latencyMs&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;finishReason&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Testing OpenAI-integrated code
&lt;/h2&gt;

&lt;p&gt;You can't hit the live API in CI. You'd burn money and tests would be flaky.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pattern I use:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wrap the LLM call in an interface &lt;code&gt;LLMClient&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Have &lt;code&gt;OpenAIClient&lt;/code&gt; (prod) and &lt;code&gt;MockLLMClient&lt;/code&gt; (test)&lt;/li&gt;
&lt;li&gt;Tests inject the mock; record realistic responses for golden-path tests&lt;/li&gt;
&lt;li&gt;Run a &lt;strong&gt;separate&lt;/strong&gt; "live integration" job nightly that hits OpenAI in a staging key and alerts on contract changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This catches prompt drift before customers do.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Prompts are code. Version them.
&lt;/h2&gt;

&lt;p&gt;A prompt change is a deploy. Treat it like code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prompts live in your repo, not in OpenAI's playground&lt;/li&gt;
&lt;li&gt;Each prompt has a version number&lt;/li&gt;
&lt;li&gt;Changes go through code review&lt;/li&gt;
&lt;li&gt;You can roll back&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I keep prompts in &lt;code&gt;src/main/resources/prompts/&lt;/code&gt; as &lt;code&gt;.txt&lt;/code&gt; files with a header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# id: classify-invoice-v3&lt;/span&gt;
&lt;span class="c1"&gt;# author: shubham.bhati&lt;/span&gt;
&lt;span class="c1"&gt;# changed: 2026-04-12&lt;/span&gt;
&lt;span class="c1"&gt;# purpose: extracts vendor + amount + due date from invoice text&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The bottom line
&lt;/h2&gt;

&lt;p&gt;OpenAI in production isn't &lt;code&gt;chatClient.call("hello")&lt;/code&gt;. It's:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A queue&lt;/li&gt;
&lt;li&gt;A circuit breaker&lt;/li&gt;
&lt;li&gt;A retry policy&lt;/li&gt;
&lt;li&gt;A cost model&lt;/li&gt;
&lt;li&gt;A version-controlled prompt library&lt;/li&gt;
&lt;li&gt;A redacted log pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've shipped any other third-party integration, you know this pattern. Don't let "AI" make you forget your engineering instincts.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Shubham Bhati is a Backend Engineer at AlignBits LLC building Java + Spring Boot integration pipelines with OpenAI in production. Based in Gurgaon, India. &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt; · &lt;a href="https://github.com/Shubh2-0" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://linkedin.com/in/bhatishubham" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Publishing checklist:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Cover image: a system architecture diagram (request → queue → AI worker → DB)&lt;/li&gt;
&lt;li&gt;[ ] Tags: &lt;code&gt;#java&lt;/code&gt; &lt;code&gt;#springboot&lt;/code&gt; &lt;code&gt;#openai&lt;/code&gt; &lt;code&gt;#ai&lt;/code&gt; &lt;code&gt;#backend&lt;/code&gt; &lt;code&gt;#microservices&lt;/code&gt; &lt;code&gt;#productionsoftware&lt;/code&gt; &lt;code&gt;#javadevelopment&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Cross-post to Dev.to + Hashnode after 24h (Medium first for canonical)&lt;/li&gt;
&lt;li&gt;[ ] Pin tweet linking to this post&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>openai</category>
      <category>springboot</category>
      <category>ai</category>
    </item>
    <item>
      <title>GraphQL with Spring Boot: A Hands-On Tutorial for REST Developers</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Thu, 28 May 2026 07:08:11 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/graphql-with-spring-boot-a-hands-on-tutorial-for-rest-developers-17d4</link>
      <guid>https://dev.to/shubham_bhati/graphql-with-spring-boot-a-hands-on-tutorial-for-rest-developers-17d4</guid>
      <description>&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%2Fsource.unsplash.com%2F1200x630%2F%3Fgraphql%2Capi%2Cweb%26sig%3D1" 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%2Fsource.unsplash.com%2F1200x630%2F%3Fgraphql%2Capi%2Cweb%26sig%3D1" alt="Graphql Spring Boot Tutorial" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Published 2026-05-28 by &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;Shubham Bhati&lt;/a&gt; — Backend Engineer (Java 17, Spring Boot, Microservices).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As backend engineers, we've all been there - stuck with a REST API that's becoming increasingly cumbersome to maintain. At our company, we recently faced a similar issue with our user management API, which was built using Spring Boot 2.7 and Java 17. The API had grown to over 50 endpoints, and every new feature addition was a nightmare. That's when we started exploring GraphQL as an alternative, and after a thorough evaluation, we decided to go with a &lt;strong&gt;graphql spring boot tutorial&lt;/strong&gt; to migrate our API. We chose Spring Boot 3.2 and Java 21 for the migration, and the results were astonishing - we reduced our p99 latency from 800ms to 120ms.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduction to GraphQL&lt;/li&gt;
&lt;li&gt;Setting up a GraphQL Project with Spring Boot&lt;/li&gt;
&lt;li&gt;Defining GraphQL Schemas&lt;/li&gt;
&lt;li&gt;Resolvers and Data Fetching&lt;/li&gt;
&lt;li&gt;Error Handling and Debugging&lt;/li&gt;
&lt;li&gt;Common Mistakes&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction to GraphQL
&lt;/h2&gt;

&lt;p&gt;GraphQL is a query language for APIs that allows clients to specify exactly what data they need, reducing the amount of data transferred over the network. This makes it an attractive alternative to traditional REST APIs, especially for complex, data-driven applications. In our case, we were using Spring Boot to build our REST API, so we decided to explore the &lt;a href="https://docs.spring.io/spring-graphql/docs/current/reference/html/" rel="noopener noreferrer"&gt;Spring GraphQL&lt;/a&gt; module to see how it could help us migrate to GraphQL. We started by reading the &lt;a href="https://docs.spring.io/spring-graphql/docs/current/reference/html/" rel="noopener noreferrer"&gt;official Spring GraphQL documentation&lt;/a&gt; and the &lt;a href="https://www.graphql-java.com/" rel="noopener noreferrer"&gt;GraphQL Java documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a GraphQL Project with Spring Boot
&lt;/h2&gt;

&lt;p&gt;To get started with GraphQL and Spring Boot, you'll need to add the following dependencies to your &lt;code&gt;pom.xml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-graphql&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.graphql-java&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;graphql-java&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We used Maven 3.8 to manage our dependencies. Once you've added the dependencies, you can create a new Spring Boot application and configure the GraphQL endpoint. We used the &lt;code&gt;@EnableGraphQL&lt;/code&gt; annotation to enable GraphQL support in our application:&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;@SpringBootApplication&lt;/span&gt;
&lt;span class="nd"&gt;@EnableGraphQL&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;GraphQLApplication&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;SpringApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GraphQLApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&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;We also used Java 21 to take advantage of its new features, such as &lt;a href="https://docs.oracle.com/javase/specs/jls/se21/preview/features.html#jep-409" rel="noopener noreferrer"&gt;sealed classes&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining GraphQL Schemas
&lt;/h2&gt;

&lt;p&gt;In GraphQL, schemas define the structure of your data and the available queries and mutations. We defined our schema using the GraphQL schema definition language (SDL):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&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;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&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;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Query&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;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!):&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&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;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mutation&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;span class="n"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!):&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&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;We used the &lt;code&gt;graphql-java&lt;/code&gt; library to parse and validate our schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resolvers and Data Fetching
&lt;/h2&gt;

&lt;p&gt;Resolvers are responsible for fetching data from your backend systems and returning it to the client. We used Spring Data JPA to interact with our database:&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;@Repository&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;JpaRepository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findById&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="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Service&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;UserService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getUsers&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="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&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="nc"&gt;User&lt;/span&gt; &lt;span class="nf"&gt;getUser&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="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&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;We used Spring Boot 3.2 to take advantage of its new features, such as &lt;a href="https://spring.io/blog/2022/11/24/spring-boot-3-0-0" rel="noopener noreferrer"&gt;native support for Java 21&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error Handling and Debugging
&lt;/h2&gt;

&lt;p&gt;Error handling and debugging are crucial aspects of building a GraphQL API. We used the &lt;code&gt;@ExceptionHandler&lt;/code&gt; annotation to handle exceptions and return error responses to the client:&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;@ExceptionHandler&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="nc"&gt;Exception&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&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;ErrorResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ErrorResponse&lt;/span&gt; &lt;span class="n"&gt;errorResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ErrorResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&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;INTERNAL_SERVER_ERROR&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;errorResponse&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;We also used the &lt;a href="https://www.graphql-java.com/tutorials/debugging/" rel="noopener noreferrer"&gt;GraphQL Java debugger&lt;/a&gt; to debug our API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;Here are some common mistakes to avoid when building a GraphQL API with Spring Boot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not validating user input&lt;/li&gt;
&lt;li&gt;Not handling exceptions properly&lt;/li&gt;
&lt;li&gt;Not using pagination and caching&lt;/li&gt;
&lt;li&gt;Not optimizing database queries&lt;/li&gt;
&lt;li&gt;Not using a consistent naming convention&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the difference between GraphQL and REST?
&lt;/h3&gt;

&lt;p&gt;GraphQL and REST are both API paradigms, but they differ in their approach to data retrieval. GraphQL allows clients to specify exactly what data they need, while REST returns a fixed set of data.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I handle authentication and authorization in GraphQL?
&lt;/h3&gt;

&lt;p&gt;You can handle authentication and authorization in GraphQL using middleware or resolvers. We used Spring Security to secure our API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use GraphQL with other frameworks besides Spring Boot?
&lt;/h3&gt;

&lt;p&gt;Yes, you can use GraphQL with other frameworks besides Spring Boot. We used the &lt;a href="https://www.graphql-java.com/" rel="noopener noreferrer"&gt;graphql-java&lt;/a&gt; library to build our API.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are some best practices for building a GraphQL API?
&lt;/h3&gt;

&lt;p&gt;Some best practices for building a GraphQL API include using a consistent naming convention, optimizing database queries, and using pagination and caching. You can find more information on the &lt;a href="https://graphql.org/learn/best-practices/" rel="noopener noreferrer"&gt;GraphQL best practices&lt;/a&gt; page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, building a GraphQL API with Spring Boot is a great way to improve the performance and flexibility of your API. By following the steps outlined in this tutorial, you can create a scalable and maintainable API that meets the needs of your clients. To get started, check out the &lt;a href="https://docs.spring.io/spring-graphql/docs/current/reference/html/" rel="noopener noreferrer"&gt;official Spring GraphQL documentation&lt;/a&gt; and the &lt;a href="https://www.graphql-java.com/" rel="noopener noreferrer"&gt;GraphQL Java documentation&lt;/a&gt;.&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%2Fsource.unsplash.com%2F1000x500%2F%3Fgraphql%2Capi%2Cweb%26sig%3D2" 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%2Fsource.unsplash.com%2F1000x500%2F%3Fgraphql%2Capi%2Cweb%26sig%3D2" alt="Graphql Spring Boot Tutorial in production" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/" rel="noopener noreferrer"&gt;Spring Boot Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/" rel="noopener noreferrer"&gt;Baeldung — Java &amp;amp; Spring Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/" rel="noopener noreferrer"&gt;Oracle Java Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Written by **Shubham Bhati&lt;/em&gt;* — Backend Engineer at AlignBits LLC, specializing in Java 17, Spring Boot, microservices, and AI integration. Connect on &lt;a href="https://linkedin.com/in/bhatishubham" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://github.com/Shubh2-0" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, or read more at &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;shubh2-0.github.io&lt;/a&gt;.*&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>springboot</category>
      <category>java</category>
      <category>api</category>
    </item>
    <item>
      <title>Solving the Hibernate N+1 Problem in Spring Data JPA</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Mon, 25 May 2026 08:03:29 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/solving-the-hibernate-n1-problem-in-spring-data-jpa-2p5g</link>
      <guid>https://dev.to/shubham_bhati/solving-the-hibernate-n1-problem-in-spring-data-jpa-2p5g</guid>
      <description>&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%2Fsource.unsplash.com%2F1200x630%2F%3Fdatabase%2Cperformance%2Cdebugging%26sig%3D1" 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%2Fsource.unsplash.com%2F1200x630%2F%3Fdatabase%2Cperformance%2Cdebugging%26sig%3D1" alt="Hibernate N+1 Problem" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Published 2026-05-25 by &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;Shubham Bhati&lt;/a&gt; — Backend Engineer (Java 17, Spring Boot, Microservices).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We've all been there - staring at a slow application, trying to figure out why our database queries are taking so long to execute. In our case, it was a Java-based e-commerce platform built using Spring Boot 3.2 and Spring Data JPA. After digging through the logs, we discovered that the &lt;strong&gt;hibernate n+1 problem&lt;/strong&gt; was the culprit behind the slow performance. This issue occurs when Hibernate executes multiple select queries to fetch related entities, resulting in a significant increase in database load and latency. In this article, we'll explore the causes of the hibernate n+1 problem and discuss various strategies to solve it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduction to the Hibernate N+1 Problem&lt;/li&gt;
&lt;li&gt;Understanding JPA Fetch Types&lt;/li&gt;
&lt;li&gt;Lazy Loading and Its Pitfalls&lt;/li&gt;
&lt;li&gt;Using Join Fetching to Solve the N+1 Problem&lt;/li&gt;
&lt;li&gt;Enabling Batch Fetching&lt;/li&gt;
&lt;li&gt;Common Mistakes&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction to the Hibernate N+1 Problem
&lt;/h2&gt;

&lt;p&gt;The hibernate n+1 problem is a common issue that arises when using Hibernate to fetch related entities. It occurs when Hibernate executes multiple select queries to fetch the related entities, instead of using a single query to fetch all the required data. For example, consider a simple &lt;code&gt;Order&lt;/code&gt; entity that has a one-to-many relationship with &lt;code&gt;OrderItem&lt;/code&gt;:&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;Order&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;customerName&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@OneToMany&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mappedBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"order"&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;orderItems&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// 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;When we try to fetch all the orders along with their order items, Hibernate will execute a separate query to fetch the order items for each order, resulting in the n+1 problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding JPA Fetch Types
&lt;/h2&gt;

&lt;p&gt;JPA provides two fetch types - &lt;code&gt;EAGER&lt;/code&gt; and &lt;code&gt;LAZY&lt;/code&gt;. The &lt;code&gt;EAGER&lt;/code&gt; fetch type fetches the related entities immediately when the parent entity is loaded, while the &lt;code&gt;LAZY&lt;/code&gt; fetch type fetches the related entities only when they are actually needed. By default, Hibernate uses the &lt;code&gt;LAZY&lt;/code&gt; fetch type for one-to-many and many-to-many relationships. However, this can lead to the n+1 problem if we're not careful. We can change the fetch type to &lt;code&gt;EAGER&lt;/code&gt; using the &lt;code&gt;fetch&lt;/code&gt; attribute:&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;@OneToMany&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mappedBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"order"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FetchType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;EAGER&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;orderItems&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, this can lead to performance issues if we're dealing with large amounts of data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lazy Loading and Its Pitfalls
&lt;/h2&gt;

&lt;p&gt;Lazy loading can be a powerful tool for improving performance, but it can also lead to the n+1 problem if we're not careful. Consider the following 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;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entityManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;find&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OrderItem&lt;/span&gt; &lt;span class="n"&gt;orderItem&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getOrderItems&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderItem&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, Hibernate will execute a separate query to fetch the order items for each order, resulting in the n+1 problem. To avoid this, we can use join fetching or batch fetching.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Join Fetching to Solve the N+1 Problem
&lt;/h2&gt;

&lt;p&gt;Join fetching involves using a single query to fetch all the required data. We can use the &lt;code&gt;JOIN FETCH&lt;/code&gt; keyword in our JPQL query to achieve 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="nc"&gt;Query&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entityManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createQuery&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT o FROM Order o JOIN FETCH o.orderItems WHERE o.id = :id"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSingleResult&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will fetch the order along with its order items in a single query, avoiding the n+1 problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enabling Batch Fetching
&lt;/h2&gt;

&lt;p&gt;Batch fetching involves fetching multiple related entities in a single query. We can enable batch fetching using the &lt;code&gt;@BatchSize&lt;/code&gt; annotation:&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;@OneToMany&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mappedBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"order"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@BatchSize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&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;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrderItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;orderItems&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will fetch the order items in batches of 10, reducing the number of queries executed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;Here are some common mistakes to avoid when dealing with the hibernate n+1 problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not using join fetching or batch fetching&lt;/li&gt;
&lt;li&gt;Using the &lt;code&gt;LAZY&lt;/code&gt; fetch type without considering the performance implications&lt;/li&gt;
&lt;li&gt;Not using the &lt;code&gt;@BatchSize&lt;/code&gt; annotation to enable batch fetching&lt;/li&gt;
&lt;li&gt;Not using the &lt;code&gt;JOIN FETCH&lt;/code&gt; keyword in JPQL queries&lt;/li&gt;
&lt;li&gt;Not optimizing database queries to reduce latency&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the hibernate n+1 problem?
&lt;/h3&gt;

&lt;p&gt;The hibernate n+1 problem is a common issue that arises when using Hibernate to fetch related entities. It occurs when Hibernate executes multiple select queries to fetch the related entities, instead of using a single query to fetch all the required data.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I solve the hibernate n+1 problem?
&lt;/h3&gt;

&lt;p&gt;You can solve the hibernate n+1 problem by using join fetching or batch fetching. Join fetching involves using a single query to fetch all the required data, while batch fetching involves fetching multiple related entities in a single query.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between EAGER and LAZY fetch types?
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;EAGER&lt;/code&gt; fetch type fetches the related entities immediately when the parent entity is loaded, while the &lt;code&gt;LAZY&lt;/code&gt; fetch type fetches the related entities only when they are actually needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I optimize database queries to reduce latency?
&lt;/h3&gt;

&lt;p&gt;You can optimize database queries by using indexes, reducing the amount of data fetched, and using efficient query algorithms. For more information, you can refer to the &lt;a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/tgsql/index.html" rel="noopener noreferrer"&gt;Oracle documentation&lt;/a&gt; or the &lt;a href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods" rel="noopener noreferrer"&gt;Spring documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, the hibernate n+1 problem is a common issue that can significantly impact the performance of your application. By using join fetching or batch fetching, you can avoid this problem and improve the performance of your database queries. For more information, you can refer to the &lt;a href="https://www.baeldung.com/hibernate-n1-problem" rel="noopener noreferrer"&gt;Baeldung tutorial&lt;/a&gt; or the &lt;a href="https://docs.oracle.com/javase/tutorial/jdbc/index.html" rel="noopener noreferrer"&gt;official Java tutorials&lt;/a&gt;. Remember to always consider the trade-offs between different approaches and optimize your database queries to reduce latency.&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%2Fsource.unsplash.com%2F1000x500%2F%3Fdatabase%2Cperformance%2Cdebugging%26sig%3D2" 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%2Fsource.unsplash.com%2F1000x500%2F%3Fdatabase%2Cperformance%2Cdebugging%26sig%3D2" alt="Hibernate N+1 Problem in production" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/" rel="noopener noreferrer"&gt;Spring Boot Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/" rel="noopener noreferrer"&gt;Baeldung — Java &amp;amp; Spring Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/" rel="noopener noreferrer"&gt;Oracle Java Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Written by **Shubham Bhati&lt;/em&gt;* — Backend Engineer at AlignBits LLC, specializing in Java 17, Spring Boot, microservices, and AI integration. Connect on &lt;a href="https://linkedin.com/in/bhatishubham" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://github.com/Shubh2-0" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, or read more at &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;shubh2-0.github.io&lt;/a&gt;.*&lt;/p&gt;

</description>
      <category>hibernate</category>
      <category>jpa</category>
      <category>performance</category>
      <category>mysql</category>
    </item>
    <item>
      <title>From B.Com to Backend Engineer: My Masai School Journey</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Mon, 25 May 2026 08:01:44 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/from-bcom-to-backend-engineer-my-masai-school-journey-6i9</link>
      <guid>https://dev.to/shubham_bhati/from-bcom-to-backend-engineer-my-masai-school-journey-6i9</guid>
      <description>&lt;h1&gt;
  
  
  From B.Com to Backend Engineer: My Masai School Journey
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;By Shubham Bhati — Backend Engineer at AlignBits LLC&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The unlikely path
&lt;/h2&gt;

&lt;p&gt;I have a Bachelor of Commerce degree from Devi Ahilya Vishwavidyalaya in Indore. Three years later, I'm a Software Engineer at an iPaaS company, shipping production Java microservices that integrate enterprise systems.&lt;/p&gt;

&lt;p&gt;In between those two facts is one institution that changed my trajectory: &lt;strong&gt;Masai School&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is the honest version of how I went from balance sheets to backend systems — what worked, what was hard, and what I'd do differently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why a B.Com grad picks up Java
&lt;/h2&gt;

&lt;p&gt;I didn't grow up writing code. My undergrad was accounting, taxation, business law. By the final year of B.Com (2022), I had a clear realization: the work I was being prepared for didn't excite me. The work that did — building software — required skills my degree never gave me.&lt;/p&gt;

&lt;p&gt;I had two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Spend ₹4–8 lakh on a Master's degree&lt;/li&gt;
&lt;li&gt;Find a focused, intensive program that taught backend engineering for software jobs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I picked option 2 and applied to &lt;strong&gt;Masai School&lt;/strong&gt; for their Software Engineering — Java Backend Specialization (then a 30+ week program in Bengaluru).&lt;/p&gt;




&lt;h2&gt;
  
  
  What Masai actually teaches
&lt;/h2&gt;

&lt;p&gt;Forget the marketing. What I actually learned, in order:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1 — Foundations (HTML/CSS/JS, DSA)&lt;/strong&gt;&lt;br&gt;
Surprisingly tough. As a non-engineering grad, the first month was just adapting to "thinking like a programmer" — abstraction, recursion, big-O.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 2 — Java + OOP&lt;/strong&gt;&lt;br&gt;
Where the Java backend specialization really started. Generic types, collections framework, exception handling, multithreading basics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 3 — Spring Boot + databases&lt;/strong&gt;&lt;br&gt;
The career-defining phase. REST APIs, Spring Data JPA, Hibernate, MySQL. By week 18, I was building functional CRUD APIs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 4 — Production-grade&lt;/strong&gt;&lt;br&gt;
Spring Security, JWT, OAuth 2.0, microservices patterns, message queues (RabbitMQ basics).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 5 — Capstone projects&lt;/strong&gt;&lt;br&gt;
Real, deployable projects. Mine included &lt;a href="https://github.com/Shubh2-0/Chatterbox" rel="noopener noreferrer"&gt;Chatterbox (Spring Boot WebSockets)&lt;/a&gt; and a &lt;a href="https://github.com/Shubh2-0/Shopzilla-Online-Shopping-Platform" rel="noopener noreferrer"&gt;Shopzilla e-commerce backend&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What worked
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Showing up every day&lt;/strong&gt;&lt;br&gt;
Masai is intense — 9–10 hours of focused work, six days a week. The students who showed up consistently are the ones who got hired. Talent matters less than this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Building things outside class&lt;/strong&gt;&lt;br&gt;
I built side projects on weekends. &lt;a href="https://github.com/Shubh2-0/SnapResize" rel="noopener noreferrer"&gt;SnapResize&lt;/a&gt;, &lt;a href="https://github.com/Shubh2-0/TIC_TAC_TOE_Game_With_JAVAFX" rel="noopener noreferrer"&gt;TIC_TAC_TOE with JavaFX&lt;/a&gt;, and &lt;a href="https://github.com/Shubh2-0/WorkFolio" rel="noopener noreferrer"&gt;WorkFolio&lt;/a&gt; — these became my real portfolio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Studying production code&lt;/strong&gt;&lt;br&gt;
Reading open-source Spring projects taught me more than tutorials ever did.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Practicing Java interview problems daily&lt;/strong&gt;&lt;br&gt;
HackerRank, LeetCode (easy/medium). I have an &lt;a href="https://www.hackerrank.com/profile/shubhambhati226" rel="noopener noreferrer"&gt;Intermediate badge for Java on HackerRank&lt;/a&gt; — earned by daily practice.&lt;/p&gt;




&lt;h2&gt;
  
  
  What didn't work (or what I'd change)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Spreading too thin&lt;/strong&gt;&lt;br&gt;
I tried to learn React + Java backend simultaneously in the first months. Mistake. Going deep on one stack beats being mediocre at two.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Skipping system design early&lt;/strong&gt;&lt;br&gt;
Masai covers basics, but interview-grade system design (LB, caching, partitioning, CAP, consistent hashing) — I learned that mostly on the job after joining IHX. Should have started earlier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Not building public presence&lt;/strong&gt;&lt;br&gt;
I waited until job-search stage to make a GitHub portfolio. Should have been pushing code from week 1. Recruiters search GitHub more than they admit.&lt;/p&gt;




&lt;h2&gt;
  
  
  What happened after Masai
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;IHX Private Limited (Jun 2023 – Aug 2024)&lt;/strong&gt; — Associate Software Engineer on healthcare backend systems. FHIR-standard integrations. This is where I learned production engineering: incidents, on-call, monitoring, SLOs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AlignBits LLC (Sep 2024 – present)&lt;/strong&gt; — Software Engineer on an iPaaS platform. Microservices at scale, message queues, AWS, cross-system integrations. Got promoted from Jr. in my first year.&lt;/p&gt;

&lt;p&gt;In two years from graduating Masai I've:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resolved 15+ production incidents&lt;/li&gt;
&lt;li&gt;Managed 10+ client integration pipelines&lt;/li&gt;
&lt;li&gt;Earned 25+ certifications (AI Engineer, Java, Prompt Engineering)&lt;/li&gt;
&lt;li&gt;Stayed at backend engineering — never had to pivot&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Is Masai worth it?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Honest answer: yes, conditionally.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's worth it if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're committed to backend engineering as a career&lt;/li&gt;
&lt;li&gt;You can dedicate 9+ hours/day for 30+ weeks&lt;/li&gt;
&lt;li&gt;You have no engineering background and need structured fundamentals&lt;/li&gt;
&lt;li&gt;You're OK with the pay-after-placement model (you don't pay until you're earning)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's NOT worth it if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're looking for a credential to put on a resume without doing the work&lt;/li&gt;
&lt;li&gt;You already know Java and Spring well — you'll be bored in the first half&lt;/li&gt;
&lt;li&gt;You can't commit full-time&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What I'd tell a B.Com student today
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pick one stack, go deep.&lt;/strong&gt; Don't be a full-stack jack-of-all-trades. Java + Spring Boot is a solid bet for India in 2026.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Push code to GitHub from day one.&lt;/strong&gt; Even bad code. Recruiters notice consistency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get a working website.&lt;/strong&gt; Mine is at &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;shubh2-0.github.io&lt;/a&gt;. It pulls more recruiter messages than my LinkedIn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solve 1 LeetCode problem a day.&lt;/strong&gt; Not 10. One, every day, for a year.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find a community.&lt;/strong&gt; I'd struggled alone for months before joining Masai. Don't.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;I'm currently exploring backend engineering roles — remote, hybrid, or relocation — with companies building products that scale. If you're hiring or know someone who is, my &lt;a href="https://linkedin.com/in/bhatishubham" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; is the fastest way to reach me.&lt;/p&gt;

&lt;p&gt;If you're a B.Com student staring at a coding bootcamp wondering if it's worth it: it is, if you do the work.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Shubham Bhati is a Backend Engineer at AlignBits LLC, working on iPaaS platform integrations with Java, Spring Boot, and AWS. Based in Gurgaon, India. &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt; · &lt;a href="https://github.com/Shubh2-0" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://linkedin.com/in/bhatishubham" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Publishing checklist:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Add 2-3 images (Masai campus photo, your code screenshot, a system diagram)&lt;/li&gt;
&lt;li&gt;[ ] Cover image: 1200x675 px (Canva)&lt;/li&gt;
&lt;li&gt;[ ] Tags: &lt;code&gt;#masaischool&lt;/code&gt; &lt;code&gt;#javadeveloper&lt;/code&gt; &lt;code&gt;#careerchange&lt;/code&gt; &lt;code&gt;#bcomtocoding&lt;/code&gt; &lt;code&gt;#backenddeveloper&lt;/code&gt; &lt;code&gt;#java&lt;/code&gt; &lt;code&gt;#springboot&lt;/code&gt; &lt;code&gt;#india&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Add canonical link back to your bio site&lt;/li&gt;
&lt;li&gt;[ ] Cross-post to Dev.to and Hashnode after 24h (Medium gets first crawl)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>career</category>
      <category>masaischool</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Spring Boot Dockerfile Best Practices: Smaller, Faster, Safer Images</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Thu, 21 May 2026 07:06:32 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/spring-boot-dockerfile-best-practices-smaller-faster-safer-images-3hbh</link>
      <guid>https://dev.to/shubham_bhati/spring-boot-dockerfile-best-practices-smaller-faster-safer-images-3hbh</guid>
      <description>&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%2Fsource.unsplash.com%2F1200x630%2F%3Fdocker%2Ccontainer%2Cdeployment%26sig%3D1" 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%2Fsource.unsplash.com%2F1200x630%2F%3Fdocker%2Ccontainer%2Cdeployment%26sig%3D1" alt="Spring Boot Dockerfile" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Published 2026-05-21 by &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;Shubham Bhati&lt;/a&gt; — Backend Engineer (Java 17, Spring Boot, Microservices).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We've all been there - stuck with a bloated Spring Boot Dockerfile that's slowing down our development cycle and increasing the risk of security vulnerabilities. A well-crafted &lt;code&gt;spring boot dockerfile&lt;/code&gt; is essential for ensuring our applications are efficient, scalable, and secure. In our production environment, we've seen firsthand the impact of poorly optimized Docker images, with deployment times increasing by up to 50% due to unnecessary layers and dependencies.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduction to Spring Boot Dockerfile Best Practices&lt;/li&gt;
&lt;li&gt;Understanding Docker Layers&lt;/li&gt;
&lt;li&gt;Multi-Stage Build for Smaller Images&lt;/li&gt;
&lt;li&gt;Optimizing Dependencies for Faster Builds&lt;/li&gt;
&lt;li&gt;Security Considerations for Spring Boot Docker Images&lt;/li&gt;
&lt;li&gt;Common Mistakes to Avoid&lt;/li&gt;
&lt;li&gt;Frequently Asked Questions&lt;/li&gt;
&lt;li&gt;Conclusion and Next Steps&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction to Spring Boot Dockerfile Best Practices
&lt;/h2&gt;

&lt;p&gt;When building a Spring Boot application, it's essential to follow best practices for creating efficient and secure Docker images. One of the key concepts to understand is the use of &lt;code&gt;docker layers&lt;/code&gt;, which allows us to break down our image into smaller, reusable components. By doing so, we can reduce the overall size of our image and improve build times. For example, we can use the following &lt;code&gt;Dockerfile&lt;/code&gt; to create a basic Spring Boot image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; openjdk:21-jdk-alpine&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; JAR_FILE=target/myapp.jar&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ${JAR_FILE} app.jar&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["java","-jar","/app.jar"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;Dockerfile&lt;/code&gt; uses the &lt;code&gt;openjdk:21-jdk-alpine&lt;/code&gt; base image and copies our Spring Boot application jar file into the container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Docker Layers
&lt;/h2&gt;

&lt;p&gt;Docker layers are a fundamental concept in Docker, allowing us to build images in a modular and efficient way. Each layer represents a set of changes to the previous layer, and by using &lt;code&gt;docker layers&lt;/code&gt;, we can avoid duplicating effort and reduce the overall size of our image. For example, if we have a &lt;code&gt;Dockerfile&lt;/code&gt; that installs dependencies, copies our application code, and sets environment variables, each of these steps will create a new layer. We can use the &lt;code&gt;docker history&lt;/code&gt; command to view the layers in our image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; myapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will show us the layers in our image, along with the size of each layer and the command that created it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Stage Build for Smaller Images
&lt;/h2&gt;

&lt;p&gt;One of the most effective ways to reduce the size of our Docker image is to use a &lt;code&gt;multi-stage build&lt;/code&gt;. This involves creating a separate stage for building our application, and then copying the resulting artifact into a smaller runtime stage. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage 1: Build&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;maven:3.8.6-jdk-21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; pom.xml .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mvn dependency:go-offline
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src src&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mvn package

&lt;span class="c"&gt;# Stage 2: Runtime&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; openjdk:21-jdk-alpine&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; JAR_FILE=target/myapp.jar&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build ${JAR_FILE} app.jar&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["java","-jar","/app.jar"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;Dockerfile&lt;/code&gt; uses two stages: one for building our application using Maven, and another for creating the runtime image. By doing so, we can avoid including unnecessary build dependencies in our runtime image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimizing Dependencies for Faster Builds
&lt;/h2&gt;

&lt;p&gt;When building a Spring Boot application, it's essential to optimize our dependencies to reduce build times. One way to do this is to use the &lt;code&gt;spring-boot-starter&lt;/code&gt; dependencies, which include only the necessary dependencies for our application. 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="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;springframework&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;boot&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;spring&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;boot&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;starter&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nl"&gt;web:&lt;/span&gt;&lt;span class="mf"&gt;3.2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="err"&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 will include only the necessary dependencies for a basic Spring Boot web application. We can also use tools like &lt;a href="https://www.baeldung.com/dependency-analyzer" rel="noopener noreferrer"&gt;Baeldung's Dependency Analyzer&lt;/a&gt; to identify and remove unnecessary dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Considerations for Spring Boot Docker Images
&lt;/h2&gt;

&lt;p&gt;When creating a Spring Boot Docker image, it's essential to consider security best practices. One way to do this is to use a non-root user to run our application, which can help prevent privilege escalation attacks. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;groupadd &lt;span class="nt"&gt;-r&lt;/span&gt; spring &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; useradd &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; spring spring
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; spring:spring&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a new user and group called &lt;code&gt;spring&lt;/code&gt;, and then switch to that user to run our application. We can also use tools like &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP's Docker Security Cheat Sheet&lt;/a&gt; to identify and mitigate security vulnerabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;Here are some common mistakes to avoid when creating a Spring Boot Dockerfile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using an unnecessary base image&lt;/li&gt;
&lt;li&gt;Including unnecessary dependencies&lt;/li&gt;
&lt;li&gt;Not using a non-root user to run the application&lt;/li&gt;
&lt;li&gt;Not optimizing Docker layers&lt;/li&gt;
&lt;li&gt;Not using a multi-stage build&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the best base image to use for a Spring Boot application?
&lt;/h3&gt;

&lt;p&gt;The best base image to use for a Spring Boot application is &lt;code&gt;openjdk:21-jdk-alpine&lt;/code&gt;, which includes the OpenJDK 21 runtime and the Alpine Linux distribution.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I optimize my Docker layers for better performance?
&lt;/h3&gt;

&lt;p&gt;To optimize your Docker layers, use the &lt;code&gt;docker history&lt;/code&gt; command to view the layers in your image, and then use the &lt;code&gt;--squash&lt;/code&gt; flag to combine unnecessary layers.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between a single-stage and multi-stage build?
&lt;/h3&gt;

&lt;p&gt;A single-stage build involves creating a single stage for building and running our application, while a multi-stage build involves creating separate stages for building and running our application.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I ensure my Spring Boot Docker image is secure?
&lt;/h3&gt;

&lt;p&gt;To ensure your Spring Boot Docker image is secure, use a non-root user to run your application, and follow security best practices like those outlined in the &lt;a href="https://docs.spring.io/spring-security/reference/index.html" rel="noopener noreferrer"&gt;Spring Security documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion and Next Steps
&lt;/h2&gt;

&lt;p&gt;In conclusion, creating an efficient and secure Spring Boot Dockerfile requires careful consideration of several factors, including Docker layers, dependencies, and security best practices. By following the tips and best practices outlined in this article, we can create smaller, faster, and safer images that improve our development cycle and reduce the risk of security vulnerabilities. To learn more about Spring Boot and Docker, check out the &lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/" rel="noopener noreferrer"&gt;official Spring Boot documentation&lt;/a&gt; and the &lt;a href="https://docs.docker.com/" rel="noopener noreferrer"&gt;Docker documentation&lt;/a&gt;.&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%2Fsource.unsplash.com%2F1000x500%2F%3Fdocker%2Ccontainer%2Cdeployment%26sig%3D2" 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%2Fsource.unsplash.com%2F1000x500%2F%3Fdocker%2Ccontainer%2Cdeployment%26sig%3D2" alt="Spring Boot Dockerfile in production" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/" rel="noopener noreferrer"&gt;Spring Boot Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/" rel="noopener noreferrer"&gt;Baeldung — Java &amp;amp; Spring Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/" rel="noopener noreferrer"&gt;Oracle Java Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Written by **Shubham Bhati&lt;/em&gt;* — Backend Engineer at AlignBits LLC, specializing in Java 17, Spring Boot, microservices, and AI integration. Connect on &lt;a href="https://linkedin.com/in/bhatishubham" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://github.com/Shubh2-0" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, or read more at &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;shubh2-0.github.io&lt;/a&gt;.*&lt;/p&gt;

</description>
      <category>docker</category>
      <category>springboot</category>
      <category>devops</category>
      <category>java</category>
    </item>
    <item>
      <title>Calling OpenAI from Spring Boot: A Production-Ready Integration</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Mon, 18 May 2026 07:09:47 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/calling-openai-from-spring-boot-a-production-ready-integration-13c4</link>
      <guid>https://dev.to/shubham_bhati/calling-openai-from-spring-boot-a-production-ready-integration-13c4</guid>
      <description>&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%2Fsource.unsplash.com%2F1200x630%2F%3Fai%2Copenai%2Capi%26sig%3D1" 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%2Fsource.unsplash.com%2F1200x630%2F%3Fai%2Copenai%2Capi%26sig%3D1" alt="Spring Boot Openai Integration" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Published 2026-05-18 by &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;Shubham Bhati&lt;/a&gt; — Backend Engineer (Java 17, Spring Boot, Microservices).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We've all been there - trying to integrate a third-party API into our Spring Boot application, only to hit a roadblock. Recently, we encountered this issue while trying to integrate OpenAI into our Java backend using Spring Boot. The primary goal was to create a seamless Spring Boot OpenAI integration, enabling our application to tap into the power of AI. After overcoming several hurdles, we successfully implemented the integration, and our application is now capable of utilizing OpenAI's features.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduction to OpenAI API&lt;/li&gt;
&lt;li&gt;Setting up OpenAI with Spring Boot&lt;/li&gt;
&lt;li&gt;Creating a Service to Handle OpenAI Requests&lt;/li&gt;
&lt;li&gt;Error Handling and Logging&lt;/li&gt;
&lt;li&gt;Performance Optimization&lt;/li&gt;
&lt;li&gt;Common Mistakes&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction to OpenAI API
&lt;/h2&gt;

&lt;p&gt;The OpenAI API provides a wide range of features, including text completion, language translation, and text classification. To use the OpenAI API, you need to create an account on their website and obtain an API key. We're using Java 21 and Spring Boot 3.2 for our application, which provides a solid foundation for building a production-ready integration. The OpenAI API uses a RESTful architecture, making it easy to integrate with our Spring Boot application. We can use the &lt;a href="https://docs.spring.io/spring-boot/docs/3.2.0/reference/htmlsingle/#web" rel="noopener noreferrer"&gt;Spring Web&lt;/a&gt; module to make HTTP requests to the OpenAI API.&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="c1"&gt;// Import necessary dependencies&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.beans.factory.annotation.Value&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;org.springframework.http.HttpEntity&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;org.springframework.http.HttpHeaders&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;org.springframework.http.HttpMethod&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;org.springframework.http.ResponseEntity&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;org.springframework.web.client.RestTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create a RestTemplate instance&lt;/span&gt;
&lt;span class="nc"&gt;RestTemplate&lt;/span&gt; &lt;span class="n"&gt;restTemplate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RestTemplate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Set API key and base URL&lt;/span&gt;
&lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${openai.api.key}"&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;apiKey&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${openai.base.url}"&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;baseUrl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create a method to make requests to the OpenAI API&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;makeRequest&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;prompt&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Set headers and entity&lt;/span&gt;
    &lt;span class="nc"&gt;HttpHeaders&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpHeaders&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;HttpEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Make the request&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;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;restTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;baseUrl&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/completions"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HttpMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;POST&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Return the response&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBody&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;h2&gt;
  
  
  Setting up OpenAI with Spring Boot
&lt;/h2&gt;

&lt;p&gt;To set up OpenAI with Spring Boot, you need to add the necessary dependencies to your &lt;code&gt;pom.xml&lt;/code&gt; file (if you're using Maven) or your &lt;code&gt;build.gradle&lt;/code&gt; file (if you're using Gradle). We're using the &lt;a href="https://docs.spring.io/spring-boot/docs/3.2.0/reference/htmlsingle/#boot-features-developing-web-applications" rel="noopener noreferrer"&gt;Spring Boot Starter Web&lt;/a&gt; module, which provides a convenient way to build web applications. You also need to configure the OpenAI API key and base URL in your application properties file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# application.properties
&lt;/span&gt;&lt;span class="py"&gt;openai.api.key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;YOUR_API_KEY&lt;/span&gt;
&lt;span class="py"&gt;openai.base.url&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;https://api.openai.com/v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating a Service to Handle OpenAI Requests
&lt;/h2&gt;

&lt;p&gt;To handle OpenAI requests, we created a service that encapsulates the logic for making requests to the OpenAI API. This service uses the &lt;code&gt;RestTemplate&lt;/code&gt; instance to make HTTP requests to the OpenAI API. We're using the &lt;a href="https://docs.spring.io/spring-framework/docs/5.3.23/reference/html/core.html#beans" rel="noopener noreferrer"&gt;Spring Framework's dependency injection&lt;/a&gt; feature to inject the &lt;code&gt;RestTemplate&lt;/code&gt; instance into our service.&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="c1"&gt;// OpenAI Service&lt;/span&gt;
&lt;span class="nd"&gt;@Service&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;OpenAIService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;RestTemplate&lt;/span&gt; &lt;span class="n"&gt;restTemplate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;makeRequest&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;prompt&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Make the request using the RestTemplate instance&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;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;restTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.openai.com/v1/completions"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HttpMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;POST&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HttpEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Return the response&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBody&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;h2&gt;
  
  
  Error Handling and Logging
&lt;/h2&gt;

&lt;p&gt;Error handling and logging are crucial aspects of building a production-ready integration. We're using the &lt;a href="https://docs.spring.io/spring-framework/docs/5.3.23/reference/html/core.html#core-exception" rel="noopener noreferrer"&gt;Spring Framework's exception handling&lt;/a&gt; feature to handle exceptions that occur during the execution of our application. We're also using the &lt;a href="https://logback.qos.ch/" rel="noopener noreferrer"&gt;Logback&lt;/a&gt; logging framework to log important events in our application.&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="c1"&gt;// Error handling example&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Make the request&lt;/span&gt;
    &lt;span class="nc"&gt;String&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;openAIService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;makeRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Log the exception&lt;/span&gt;
    &lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OpenAIService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&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="na"&gt;log&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Level&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SEVERE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&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;h2&gt;
  
  
  Performance Optimization
&lt;/h2&gt;

&lt;p&gt;Performance optimization is critical to ensuring that our application can handle a large volume of requests. We're using the &lt;a href="https://docs.oracle.com/javase/tutorial/essential/concurrency/" rel="noopener noreferrer"&gt;Java 21's built-in support for concurrent programming&lt;/a&gt; to optimize the performance of our application. We're also using the &lt;a href="https://docs.spring.io/spring-boot/docs/3.2.0/reference/htmlsingle/#boot-features-caching" rel="noopener noreferrer"&gt;Spring Boot's support for caching&lt;/a&gt; to cache frequently accessed data.&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="c1"&gt;// Performance optimization example&lt;/span&gt;
&lt;span class="c1"&gt;// Use Java 21's concurrent programming features to optimize performance&lt;/span&gt;
&lt;span class="nc"&gt;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newFixedThreadPool&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;future&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;openAIService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;makeRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;Here are some common mistakes to avoid when integrating OpenAI with Spring Boot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not handling exceptions properly&lt;/li&gt;
&lt;li&gt;Not logging important events&lt;/li&gt;
&lt;li&gt;Not optimizing performance&lt;/li&gt;
&lt;li&gt;Not configuring the OpenAI API key and base URL correctly&lt;/li&gt;
&lt;li&gt;Not using the correct dependencies in your &lt;code&gt;pom.xml&lt;/code&gt; or &lt;code&gt;build.gradle&lt;/code&gt; file&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the OpenAI API?
&lt;/h3&gt;

&lt;p&gt;The OpenAI API provides a wide range of features, including text completion, language translation, and text classification. You can use the OpenAI API to build applications that utilize the power of AI.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I integrate OpenAI with Spring Boot?
&lt;/h3&gt;

&lt;p&gt;To integrate OpenAI with Spring Boot, you need to add the necessary dependencies to your &lt;code&gt;pom.xml&lt;/code&gt; file (if you're using Maven) or your &lt;code&gt;build.gradle&lt;/code&gt; file (if you're using Gradle). You also need to configure the OpenAI API key and base URL in your application properties file.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between Spring AI and OpenAI?
&lt;/h3&gt;

&lt;p&gt;Spring AI is a framework for building AI-powered applications, while OpenAI is a platform that provides a wide range of AI features, including text completion, language translation, and text classification.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use OpenAI with Java?
&lt;/h3&gt;

&lt;p&gt;Yes, you can use OpenAI with Java. OpenAI provides a RESTful API that can be accessed using Java's built-in support for HTTP requests. You can use the &lt;a href="https://docs.spring.io/spring-boot/docs/3.2.0/reference/htmlsingle/#web" rel="noopener noreferrer"&gt;Spring Web&lt;/a&gt; module to make HTTP requests to the OpenAI API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we've discussed how to integrate OpenAI with Spring Boot. We've covered the basics of the OpenAI API, how to set up OpenAI with Spring Boot, and how to create a service to handle OpenAI requests. We've also discussed error handling and logging, performance optimization, and common mistakes to avoid. To learn more about Spring Boot and OpenAI, you can visit the &lt;a href="https://docs.spring.io/spring-boot/docs/3.2.0/reference/htmlsingle/" rel="noopener noreferrer"&gt;Spring Boot documentation&lt;/a&gt; and the &lt;a href="https://beta.openai.com/docs/" rel="noopener noreferrer"&gt;OpenAI documentation&lt;/a&gt;.&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%2Fsource.unsplash.com%2F1000x500%2F%3Fai%2Copenai%2Capi%26sig%3D2" 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%2Fsource.unsplash.com%2F1000x500%2F%3Fai%2Copenai%2Capi%26sig%3D2" alt="Spring Boot Openai Integration in production" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/" rel="noopener noreferrer"&gt;Spring Boot Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/" rel="noopener noreferrer"&gt;Baeldung — Java &amp;amp; Spring Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/" rel="noopener noreferrer"&gt;Oracle Java Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Written by **Shubham Bhati&lt;/em&gt;* — Backend Engineer at AlignBits LLC, specializing in Java 17, Spring Boot, microservices, and AI integration. Connect on &lt;a href="https://linkedin.com/in/bhatishubham" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://github.com/Shubh2-0" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, or read more at &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;shubh2-0.github.io&lt;/a&gt;.*&lt;/p&gt;

</description>
      <category>openai</category>
      <category>ai</category>
      <category>springboot</category>
      <category>java</category>
    </item>
    <item>
      <title>15 Production Incidents in a Healthcare Backend: FHIR Lessons</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Mon, 18 May 2026 07:08:58 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/15-production-incidents-in-a-healthcare-backend-fhir-lessons-3p7b</link>
      <guid>https://dev.to/shubham_bhati/15-production-incidents-in-a-healthcare-backend-fhir-lessons-3p7b</guid>
      <description>&lt;h1&gt;
  
  
  15 Production Incidents in a Healthcare Backend: What FHIR Taught Me About Reliability
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;By Shubham Bhati — Backend Engineer at AlignBits LLC&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;When I joined IHX Private Limited in June 2023 as an Associate Software Engineer, I had Masai's certificate and a few personal Java projects. By the time I left in August 2024, I'd resolved 15+ production incidents on FHIR-standard healthcare backend systems.&lt;/p&gt;

&lt;p&gt;That number sounds bad. It isn't. Production engineering is where you actually learn to build software. Here's what FHIR healthcare backends taught me — beyond what any Spring Boot tutorial covers.&lt;/p&gt;




&lt;h2&gt;
  
  
  What FHIR is (in 60 seconds)
&lt;/h2&gt;

&lt;p&gt;FHIR — &lt;strong&gt;Fast Healthcare Interoperability Resources&lt;/strong&gt; — is a standard for exchanging healthcare data. Think of it as REST + JSON for hospitals, labs, insurers, and EHR systems.&lt;/p&gt;

&lt;p&gt;Every domain object is a "Resource": &lt;code&gt;Patient&lt;/code&gt;, &lt;code&gt;Practitioner&lt;/code&gt;, &lt;code&gt;Encounter&lt;/code&gt;, &lt;code&gt;Observation&lt;/code&gt;, &lt;code&gt;Coverage&lt;/code&gt;, &lt;code&gt;Claim&lt;/code&gt;. Each has a well-defined JSON schema with strict validation rules.&lt;/p&gt;

&lt;p&gt;In Java, the standard library is &lt;a href="https://hapifhir.io/" rel="noopener noreferrer"&gt;HAPI FHIR&lt;/a&gt;. It's huge, opinionated, and 95% of what you need.&lt;/p&gt;




&lt;h2&gt;
  
  
  What "production" means in healthcare
&lt;/h2&gt;

&lt;p&gt;In a typical SaaS, an outage costs revenue. In healthcare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A patient might not get their meds approved.&lt;/li&gt;
&lt;li&gt;A claim might be misrouted.&lt;/li&gt;
&lt;li&gt;A practitioner might see wrong data.&lt;/li&gt;
&lt;li&gt;Regulators audit your logs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't fear-mongering. It's why FHIR healthcare backends force you to learn engineering disciplines that consumer apps let you skip.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 1: Schema validation is not optional
&lt;/h2&gt;

&lt;p&gt;Patient records flow in from ~20 different EHR vendors. Each interprets FHIR slightly differently. Some send dates as &lt;code&gt;YYYY-MM-DD&lt;/code&gt;, others as full timestamps, some omit required fields, some send extension data your parser doesn't recognize.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we learned:&lt;/strong&gt; validate at the boundary, log the failures, never crash the pipeline.&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;@Component&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;FhirValidator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;FhirValidator&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ValidationResult&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IBaseResource&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;ValidationResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validateWithResult&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isSuccessful&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;warn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fhir.validation.failed resource={} errors={}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fhirType&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessages&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="c1"&gt;// do NOT throw — route to dead-letter for human review&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&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;Bad validation handling caused 4 of our 15 incidents. Fixed it once, gone forever.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 2: Idempotency or death
&lt;/h2&gt;

&lt;p&gt;Healthcare integrations retry. A lot. Network blips, gateway timeouts, scheduler restarts — every one triggers a retry. If your handler isn't idempotent, you create duplicate &lt;code&gt;Observation&lt;/code&gt; records for one blood test. Patients now appear to have run a CBC twice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; every inbound FHIR message has a deterministic ID. Use it.&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="nc"&gt;Observation&lt;/span&gt; &lt;span class="nf"&gt;upsert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Observation&lt;/span&gt; &lt;span class="n"&gt;obs&lt;/span&gt;&lt;span class="o"&gt;)&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;idempotencyKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getIdentifierFirstRep&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;observationRepo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByIdempotencyKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idempotencyKey&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElseGet&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;observationRepo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idempotencyKey&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;We turned every write into an upsert keyed on a stable business key. Duplicate-record bugs dropped to zero.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 3: The clock is not your friend
&lt;/h2&gt;

&lt;p&gt;Different sources stamp their FHIR resources with different time zones. UTC, IST, sometimes naïve local time with no zone. Sometimes the clock is wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rules I now follow:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parse everything to &lt;code&gt;Instant&lt;/code&gt; at ingress — never &lt;code&gt;LocalDateTime&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Store as UTC in the database.&lt;/li&gt;
&lt;li&gt;Format to user's locale only at the edge (controller / response mapper).&lt;/li&gt;
&lt;li&gt;If a timestamp has no zone, treat it as suspect and log it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Caused 3 of our incidents. Twice the bug was "patient timeline shows future appointment" because someone stored IST as UTC.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 4: Don't trust the network — design for partial failure
&lt;/h2&gt;

&lt;p&gt;FHIR integrations are a graph of remote calls: ingress webhook → validation → transform → enrichment from EHR → push to insurer. Anywhere in the chain can fail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Patterns that work:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every step is independently retryable&lt;/li&gt;
&lt;li&gt;Every step writes to a durable store (DB or queue) before moving on&lt;/li&gt;
&lt;li&gt;A failed step doesn't block other patients' messages&lt;/li&gt;
&lt;li&gt;A circuit breaker protects you from a slow downstream&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We standardized on this pattern after an incident where one slow insurer API caused a thread pool to fill and blocked all unrelated patient traffic. Resilience4j circuit breaker fixed it permanently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 5: Logging structure matters more than log volume
&lt;/h2&gt;

&lt;p&gt;When you're paged at 2am, you don't want to grep 10GB of unstructured logs. You want one query.&lt;/p&gt;

&lt;p&gt;We moved every log line to structured JSON with these fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;correlation_id&lt;/code&gt; — uniquely identifies a patient message across all services&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tenant_id&lt;/code&gt; — which hospital/clinic&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;resource_type&lt;/code&gt; — Patient, Observation, etc.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;event&lt;/code&gt; — what just happened&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;duration_ms&lt;/code&gt; — how long it took&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;outcome&lt;/code&gt; — success / failure / partial&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One query against our log store told us which tenant, which resource, which step, what went wrong. MTTR (mean time to recovery) for incidents dropped from ~40 minutes to ~8.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 6: PII logging will get you in trouble
&lt;/h2&gt;

&lt;p&gt;You will not log patient names. You will not log SSNs / Aadhaar numbers. You will not log diagnoses. Period.&lt;/p&gt;

&lt;p&gt;What you can log:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resource type, resource ID hash, tenant ID&lt;/li&gt;
&lt;li&gt;Timestamps, durations, outcomes&lt;/li&gt;
&lt;li&gt;Sanitized field-presence (e.g., "had_address=true", not the address)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We added a pre-commit hook that scanned every PR for "obvious PII leak" patterns. Caught 2 leaks before they shipped.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 7: The on-call rotation is the best teacher
&lt;/h2&gt;

&lt;p&gt;Six months into my role, my manager added me to on-call rotation. I was nervous. It was the single best decision for my engineering growth.&lt;/p&gt;

&lt;p&gt;You learn things on-call you cannot learn anywhere else:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What your system actually does at 3am&lt;/li&gt;
&lt;li&gt;Which logs are useful and which are noise&lt;/li&gt;
&lt;li&gt;Which alerts are signal and which are noise&lt;/li&gt;
&lt;li&gt;How a small bug in deployment becomes a customer-impacting incident in 12 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your role lets you opt into on-call, do it. It's the fastest engineering compounding you can get.&lt;/p&gt;




&lt;h2&gt;
  
  
  The compounding effect
&lt;/h2&gt;

&lt;p&gt;After 15 months at IHX, I wasn't just "the Spring Boot guy from Masai." I was someone who'd debugged production at 2am, understood SLOs, had a feel for trade-offs between consistency and availability. That changed everything about how I approached engineering interviews afterwards.&lt;/p&gt;

&lt;p&gt;It's also why I now work on integration platforms at AlignBits — the patterns are the same. Different domain, same engineering rules.&lt;/p&gt;




&lt;h2&gt;
  
  
  If you're starting in healthcare backend
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read the HAPI FHIR docs&lt;/strong&gt;. The 80% you need fits in a weekend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get familiar with one EHR's API&lt;/strong&gt; (Epic FHIR sandbox is free).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick a real test fixture set&lt;/strong&gt;. Synthea generates realistic FHIR data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get on a real on-call rotation as soon as you can&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find a senior engineer who'll review your code line-by-line&lt;/strong&gt;. Mine made me 3x as good in 6 months.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Shubham Bhati is a Backend Engineer at AlignBits LLC. Previously Associate Software Engineer at IHX Private Limited working on FHIR-standard healthcare backend systems. Based in Gurgaon, India. &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt; · &lt;a href="https://github.com/Shubh2-0" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://linkedin.com/in/bhatishubham" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Publishing checklist:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Cover image: abstract flow diagram or HL7 FHIR logo&lt;/li&gt;
&lt;li&gt;[ ] Tags: &lt;code&gt;#java&lt;/code&gt; &lt;code&gt;#springboot&lt;/code&gt; &lt;code&gt;#healthcare&lt;/code&gt; &lt;code&gt;#fhir&lt;/code&gt; &lt;code&gt;#hapifhir&lt;/code&gt; &lt;code&gt;#backend&lt;/code&gt; &lt;code&gt;#productionengineering&lt;/code&gt; &lt;code&gt;#microservices&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Add a "FHIR resources" link section at the bottom for SEO&lt;/li&gt;
&lt;li&gt;[ ] Cross-post to Dev.to and Hashnode after 24h&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>healthcare</category>
      <category>productivity</category>
      <category>backend</category>
    </item>
    <item>
      <title>Spring Boot REST API Best Practices in 2026: A Production Guide</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Sat, 16 May 2026 20:36:08 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/spring-boot-rest-api-best-practices-in-2026-a-production-guide-267f</link>
      <guid>https://dev.to/shubham_bhati/spring-boot-rest-api-best-practices-in-2026-a-production-guide-267f</guid>
      <description>&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%2Fsource.unsplash.com%2F1200x630%2F%3Fjava%2Cprogramming%2Ccode%26sig%3D1" 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%2Fsource.unsplash.com%2F1200x630%2F%3Fjava%2Cprogramming%2Ccode%26sig%3D1" alt="Spring Boot Rest Api Best Practices" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Published 2026-05-17 by &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;Shubham Bhati&lt;/a&gt; — Backend Engineer (Java 17, Spring Boot, Microservices).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We've all been there - stuck with a slow and unresponsive Spring Boot REST API in production, wondering where it all went wrong. Recently, we encountered a similar issue with one of our APIs, where the average response time was over 500ms. After digging into the code, we realized that we weren't following some of the essential Spring Boot REST API best practices. In this article, we'll share our experience and provide a comprehensive guide on how to build production-grade REST APIs using Spring Boot.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduction to REST API Design&lt;/li&gt;
&lt;li&gt;Choosing the Right HTTP Methods&lt;/li&gt;
&lt;li&gt;Error Handling and Logging&lt;/li&gt;
&lt;li&gt;Database Schema Design&lt;/li&gt;
&lt;li&gt;Common Mistakes&lt;/li&gt;
&lt;li&gt;Security Considerations&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction to REST API Design
&lt;/h2&gt;

&lt;p&gt;When designing a REST API, it's essential to keep in mind the principles of RESTful architecture. This includes using HTTP methods (GET, POST, PUT, DELETE) to interact with resources, using meaningful resource names, and handling errors properly. We've found that using a tool like &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt; can be incredibly helpful in testing and debugging our APIs. For example, let's consider a simple API that returns a list of users:&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;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users"&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;UserController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getUsers&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="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&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;In this example, we're using the &lt;code&gt;@GetMapping&lt;/code&gt; annotation to map the &lt;code&gt;/users&lt;/code&gt; endpoint to the &lt;code&gt;getUsers()&lt;/code&gt; method, which returns a list of users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Right HTTP Methods
&lt;/h2&gt;

&lt;p&gt;Choosing the right HTTP method for your API endpoint is crucial. For instance, if you're creating a new resource, you should use the POST method. If you're updating an existing resource, you should use the PUT method. We've seen cases where using the wrong HTTP method can lead to unexpected behavior and errors. For example, let's consider an API that creates a new user:&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;User&lt;/span&gt; &lt;span class="nf"&gt;createUser&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;User&lt;/span&gt; &lt;span class="n"&gt;user&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="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&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;In this example, we're using the &lt;code&gt;@PostMapping&lt;/code&gt; annotation to map the &lt;code&gt;/users&lt;/code&gt; endpoint to the &lt;code&gt;createUser()&lt;/code&gt; method, which creates a new user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error Handling and Logging
&lt;/h2&gt;

&lt;p&gt;Error handling and logging are critical components of a production-grade REST API. We've found that using a combination of try-catch blocks and logging frameworks like &lt;a href="https://logback.qos.ch/" rel="noopener noreferrer"&gt;Logback&lt;/a&gt; can be incredibly effective in handling errors and logging important information. For example, let's consider an API that handles errors:&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;@GetMapping&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error fetching users"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&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;In this example, we're using a try-catch block to catch any exceptions that occur when fetching users, and logging the error using Logback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database Schema Design
&lt;/h2&gt;

&lt;p&gt;Database schema design is another critical aspect of building a production-grade REST API. We've found that using a tool like &lt;a href="https://hibernate.org/" rel="noopener noreferrer"&gt;Hibernate&lt;/a&gt; can be incredibly helpful in designing and managing our database schema. For example, let's consider a simple database schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we're creating a simple table called &lt;code&gt;users&lt;/code&gt; with three columns: &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;email&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes
&lt;/h2&gt;

&lt;p&gt;Here are some common mistakes to avoid when building a Spring Boot REST API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not using meaningful resource names&lt;/li&gt;
&lt;li&gt;Not handling errors properly&lt;/li&gt;
&lt;li&gt;Not using the right HTTP methods&lt;/li&gt;
&lt;li&gt;Not logging important information&lt;/li&gt;
&lt;li&gt;Not securing your API properly&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Security Considerations
&lt;/h2&gt;

&lt;p&gt;Security is a critical aspect of building a production-grade REST API. We've found that using a combination of authentication and authorization mechanisms, such as &lt;a href="https://oauth.net/2/" rel="noopener noreferrer"&gt;OAuth&lt;/a&gt; and &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;JWT&lt;/a&gt;, can be incredibly effective in securing our APIs. For example, let's consider an API that uses JWT to authenticate users:&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;@GetMapping&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestHeader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&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;token&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Verify the token and authenticate the user&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&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;In this example, we're using the &lt;code&gt;@RequestHeader&lt;/code&gt; annotation to get the &lt;code&gt;Authorization&lt;/code&gt; header, which contains the JWT token.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the best way to handle errors in a Spring Boot REST API?
&lt;/h3&gt;

&lt;p&gt;We've found that using a combination of try-catch blocks and logging frameworks like Logback can be incredibly effective in handling errors and logging important information. For more information, check out the &lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-error-handling" rel="noopener noreferrer"&gt;Spring documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I secure my Spring Boot REST API?
&lt;/h3&gt;

&lt;p&gt;We've found that using a combination of authentication and authorization mechanisms, such as OAuth and JWT, can be incredibly effective in securing our APIs. For more information, check out the &lt;a href="https://oauth.net/2/" rel="noopener noreferrer"&gt;OAuth documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the best way to design a database schema for a Spring Boot REST API?
&lt;/h3&gt;

&lt;p&gt;We've found that using a tool like Hibernate can be incredibly helpful in designing and managing our database schema. For more information, check out the &lt;a href="https://hibernate.org/" rel="noopener noreferrer"&gt;Hibernate documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I choose the right HTTP methods for my Spring Boot REST API?
&lt;/h3&gt;

&lt;p&gt;We've found that choosing the right HTTP method depends on the specific use case and the resources being interacted with. For more information, check out the &lt;a href="https://tools.ietf.org/html/rfc7231" rel="noopener noreferrer"&gt;RFC documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In conclusion, building a production-grade Spring Boot REST API requires careful consideration of several factors, including REST API design, error handling and logging, database schema design, security considerations, and more. By following the best practices outlined in this article, we can build fast, scalable, and secure APIs that meet the needs of our users. For more information, check out the &lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/" rel="noopener noreferrer"&gt;Spring Boot documentation&lt;/a&gt;.&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%2Fsource.unsplash.com%2F1000x500%2F%3Fjava%2Cprogramming%2Ccode%26sig%3D2" 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%2Fsource.unsplash.com%2F1000x500%2F%3Fjava%2Cprogramming%2Ccode%26sig%3D2" alt="Spring Boot Rest Api Best Practices in production" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/" rel="noopener noreferrer"&gt;Spring Boot Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/" rel="noopener noreferrer"&gt;Baeldung — Java &amp;amp; Spring Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/" rel="noopener noreferrer"&gt;Oracle Java Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Written by **Shubham Bhati&lt;/em&gt;* — Backend Engineer at AlignBits LLC, specializing in Java 17, Spring Boot, microservices, and AI integration. Connect on &lt;a href="https://linkedin.com/in/bhatishubham" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://github.com/Shubh2-0" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, or read more at &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;shubh2-0.github.io&lt;/a&gt;.*&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>restapi</category>
      <category>backend</category>
    </item>
    <item>
      <title>From B.Com to Backend Engineer: My Masai School Journey</title>
      <dc:creator>Shubham Bhati</dc:creator>
      <pubDate>Sat, 16 May 2026 17:58:53 +0000</pubDate>
      <link>https://dev.to/shubham_bhati/from-bcom-to-backend-engineer-my-masai-school-journey-1053</link>
      <guid>https://dev.to/shubham_bhati/from-bcom-to-backend-engineer-my-masai-school-journey-1053</guid>
      <description>&lt;h1&gt;
  
  
  From B.Com to Backend Engineer: My Masai School Journey
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;By Shubham Bhati — Backend Engineer at AlignBits LLC&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The unlikely path
&lt;/h2&gt;

&lt;p&gt;I have a Bachelor of Commerce degree from Devi Ahilya Vishwavidyalaya in Indore. Three years later, I'm a Software Engineer at an iPaaS company, shipping production Java microservices that integrate enterprise systems.&lt;/p&gt;

&lt;p&gt;In between those two facts is one institution that changed my trajectory: &lt;strong&gt;Masai School&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is the honest version of how I went from balance sheets to backend systems — what worked, what was hard, and what I'd do differently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why a B.Com grad picks up Java
&lt;/h2&gt;

&lt;p&gt;I didn't grow up writing code. My undergrad was accounting, taxation, business law. By the final year of B.Com (2022), I had a clear realization: the work I was being prepared for didn't excite me. The work that did — building software — required skills my degree never gave me.&lt;/p&gt;

&lt;p&gt;I had two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Spend ₹4–8 lakh on a Master's degree&lt;/li&gt;
&lt;li&gt;Find a focused, intensive program that taught backend engineering for software jobs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I picked option 2 and applied to &lt;strong&gt;Masai School&lt;/strong&gt; for their Software Engineering — Java Backend Specialization (then a 30+ week program in Bengaluru).&lt;/p&gt;




&lt;h2&gt;
  
  
  What Masai actually teaches
&lt;/h2&gt;

&lt;p&gt;Forget the marketing. What I actually learned, in order:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1 — Foundations (HTML/CSS/JS, DSA)&lt;/strong&gt;&lt;br&gt;
Surprisingly tough. As a non-engineering grad, the first month was just adapting to "thinking like a programmer" — abstraction, recursion, big-O.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 2 — Java + OOP&lt;/strong&gt;&lt;br&gt;
Where the Java backend specialization really started. Generic types, collections framework, exception handling, multithreading basics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 3 — Spring Boot + databases&lt;/strong&gt;&lt;br&gt;
The career-defining phase. REST APIs, Spring Data JPA, Hibernate, MySQL. By week 18, I was building functional CRUD APIs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 4 — Production-grade&lt;/strong&gt;&lt;br&gt;
Spring Security, JWT, OAuth 2.0, microservices patterns, message queues (RabbitMQ basics).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 5 — Capstone projects&lt;/strong&gt;&lt;br&gt;
Real, deployable projects. Mine included &lt;a href="https://github.com/Shubh2-0/Chatterbox" rel="noopener noreferrer"&gt;Chatterbox (Spring Boot WebSockets)&lt;/a&gt; and a &lt;a href="https://github.com/Shubh2-0/Shopzilla-Online-Shopping-Platform" rel="noopener noreferrer"&gt;Shopzilla e-commerce backend&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What worked
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Showing up every day&lt;/strong&gt;&lt;br&gt;
Masai is intense — 9–10 hours of focused work, six days a week. The students who showed up consistently are the ones who got hired. Talent matters less than this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Building things outside class&lt;/strong&gt;&lt;br&gt;
I built side projects on weekends. &lt;a href="https://github.com/Shubh2-0/SnapResize" rel="noopener noreferrer"&gt;SnapResize&lt;/a&gt;, &lt;a href="https://github.com/Shubh2-0/TIC_TAC_TOE_Game_With_JAVAFX" rel="noopener noreferrer"&gt;TIC_TAC_TOE with JavaFX&lt;/a&gt;, and &lt;a href="https://github.com/Shubh2-0/WorkFolio" rel="noopener noreferrer"&gt;WorkFolio&lt;/a&gt; — these became my real portfolio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Studying production code&lt;/strong&gt;&lt;br&gt;
Reading open-source Spring projects taught me more than tutorials ever did.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Practicing Java interview problems daily&lt;/strong&gt;&lt;br&gt;
HackerRank, LeetCode (easy/medium). I have an &lt;a href="https://www.hackerrank.com/profile/shubhambhati226" rel="noopener noreferrer"&gt;Intermediate badge for Java on HackerRank&lt;/a&gt; — earned by daily practice.&lt;/p&gt;




&lt;h2&gt;
  
  
  What didn't work (or what I'd change)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Spreading too thin&lt;/strong&gt;&lt;br&gt;
I tried to learn React + Java backend simultaneously in the first months. Mistake. Going deep on one stack beats being mediocre at two.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Skipping system design early&lt;/strong&gt;&lt;br&gt;
Masai covers basics, but interview-grade system design (LB, caching, partitioning, CAP, consistent hashing) — I learned that mostly on the job after joining IHX. Should have started earlier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Not building public presence&lt;/strong&gt;&lt;br&gt;
I waited until job-search stage to make a GitHub portfolio. Should have been pushing code from week 1. Recruiters search GitHub more than they admit.&lt;/p&gt;




&lt;h2&gt;
  
  
  What happened after Masai
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;IHX Private Limited (Jun 2023 – Aug 2024)&lt;/strong&gt; — Associate Software Engineer on healthcare backend systems. FHIR-standard integrations. This is where I learned production engineering: incidents, on-call, monitoring, SLOs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AlignBits LLC (Sep 2024 – present)&lt;/strong&gt; — Software Engineer on an iPaaS platform. Microservices at scale, message queues, AWS, cross-system integrations. Got promoted from Jr. in my first year.&lt;/p&gt;

&lt;p&gt;In two years from graduating Masai I've:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resolved 15+ production incidents&lt;/li&gt;
&lt;li&gt;Managed 10+ client integration pipelines&lt;/li&gt;
&lt;li&gt;Earned 25+ certifications (AI Engineer, Java, Prompt Engineering)&lt;/li&gt;
&lt;li&gt;Stayed at backend engineering — never had to pivot&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Is Masai worth it?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Honest answer: yes, conditionally.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's worth it if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're committed to backend engineering as a career&lt;/li&gt;
&lt;li&gt;You can dedicate 9+ hours/day for 30+ weeks&lt;/li&gt;
&lt;li&gt;You have no engineering background and need structured fundamentals&lt;/li&gt;
&lt;li&gt;You're OK with the pay-after-placement model (you don't pay until you're earning)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's NOT worth it if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're looking for a credential to put on a resume without doing the work&lt;/li&gt;
&lt;li&gt;You already know Java and Spring well — you'll be bored in the first half&lt;/li&gt;
&lt;li&gt;You can't commit full-time&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What I'd tell a B.Com student today
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pick one stack, go deep.&lt;/strong&gt; Don't be a full-stack jack-of-all-trades. Java + Spring Boot is a solid bet for India in 2026.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Push code to GitHub from day one.&lt;/strong&gt; Even bad code. Recruiters notice consistency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get a working website.&lt;/strong&gt; Mine is at &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;shubh2-0.github.io&lt;/a&gt;. It pulls more recruiter messages than my LinkedIn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solve 1 LeetCode problem a day.&lt;/strong&gt; Not 10. One, every day, for a year.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find a community.&lt;/strong&gt; I'd struggled alone for months before joining Masai. Don't.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;I'm currently exploring backend engineering roles — remote, hybrid, or relocation — with companies building products that scale. If you're hiring or know someone who is, my &lt;a href="https://linkedin.com/in/bhatishubham" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; is the fastest way to reach me.&lt;/p&gt;

&lt;p&gt;If you're a B.Com student staring at a coding bootcamp wondering if it's worth it: it is, if you do the work.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Shubham Bhati is a Backend Engineer at AlignBits LLC, working on iPaaS platform integrations with Java, Spring Boot, and AWS. Based in Gurgaon, India. &lt;a href="https://shubh2-0.github.io" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt; · &lt;a href="https://github.com/Shubh2-0" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://linkedin.com/in/bhatishubham" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Publishing checklist:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Add 2-3 images (Masai campus photo, your code screenshot, a system diagram)&lt;/li&gt;
&lt;li&gt;[ ] Cover image: 1200x675 px (Canva)&lt;/li&gt;
&lt;li&gt;[ ] Tags: &lt;code&gt;#masaischool&lt;/code&gt; &lt;code&gt;#javadeveloper&lt;/code&gt; &lt;code&gt;#careerchange&lt;/code&gt; &lt;code&gt;#bcomtocoding&lt;/code&gt; &lt;code&gt;#backenddeveloper&lt;/code&gt; &lt;code&gt;#java&lt;/code&gt; &lt;code&gt;#springboot&lt;/code&gt; &lt;code&gt;#india&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Add canonical link back to your bio site&lt;/li&gt;
&lt;li&gt;[ ] Cross-post to Dev.to and Hashnode after 24h (Medium gets first crawl)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>career</category>
      <category>masaischool</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
