<?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>Forem: Luvie</title>
    <description>The latest articles on Forem by Luvie (@luvie).</description>
    <link>https://forem.com/luvie</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%2F1768039%2F1074ff5a-405d-46ba-b0b6-cbfcfa827166.png</url>
      <title>Forem: Luvie</title>
      <link>https://forem.com/luvie</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/luvie"/>
    <language>en</language>
    <item>
      <title>Building a Production-Ready AI Agent</title>
      <dc:creator>Luvie</dc:creator>
      <pubDate>Mon, 03 Nov 2025 21:01:45 +0000</pubDate>
      <link>https://forem.com/luvie/building-a-production-ready-ai-agent-28o5</link>
      <guid>https://forem.com/luvie/building-a-production-ready-ai-agent-28o5</guid>
      <description>&lt;p&gt;Building a Production-Ready AI Agent in Pure Java: The License Compatibility Checker for Telex.imIntroduction: From Idea to Integration 🚀As part of the HNG Stage 3 Backend task, I designed and built a specialized AI agent for the Telex.im platform. My goal was to create something genuinely useful for developers: a License Compatibility Checker Agent. This agent goes beyond simple Q&amp;amp;A, offering on-demand license compatibility checks, detailed information, and proactive educational content—all built from scratch in Java 17+ without relying on external frameworks like Spring.This post walks through the architectural choices, the core logic (including the "clock system"), and the successful integration with the Telex A2A (Agent-to-Agent) protocol.🏗️ Architectural Design: Layered JavaTo meet the requirements for clean, maintainable, and testable code, I chose a simple Layered Architecture inspired by the classic Model-View-Controller (MVC) pattern, substituting the "View" with a dedicated formatting layer.LayerFilesPurposeMainLicenseCompatibilityAgent.javaServer setup, thread pooling, and endpoint registration (using com.sun.net.httpserver).Controllers*Controller.javaHandles HTTP requests (e.g., /v1/message, /health). Translates HTTP into service calls.Services*Service.javaContains all business logic (caching, API calls, scheduling, compatibility matrix).Utilities*Utils.java, LicenseExtractor.javaShared helpers: HTTP client, JSON parsing, NLP for query extraction, and Markdown formatting.Models*Info.javaSimple POJOs for data transfer (e.g., LicenseInfo, CompatibilityResult).Key Design Principle: Separation of ConcernsThe use of distinct classes like MessageProcessor and LicenseExtractor ensured that the agent could handle incoming JSON-RPC messages, extract complex natural language queries, fetch data from the LicenseService, and format the final Markdown response without any single class becoming bloated.💡 Core Functionality &amp;amp; Logic1. Data Source and Caching StrategyThe agent uses the GitHub Licenses API (&lt;a href="https://api.github.com/licenses" rel="noopener noreferrer"&gt;https://api.github.com/licenses&lt;/a&gt;) as its primary, free data source.Caching: To adhere to best practices and conserve API bandwidth, the LicenseService implements an in-memory HashMap cache. When a license detail is requested (e.g., for MIT), it is fetched once from GitHub and stored. All subsequent requests for MIT are served instantly from the cache.2. The "Clock System" (Daily Posts) ⏰A core requirement was creating an agent that is both reactive (responds to users) and proactive (posts automatically).SchedulerService.java: This service uses a standard Java ScheduledExecutorService to execute a task every 24 hours.Proactive Content: The scheduled task calls the LicenseService to determine the "License of the Day" based on the day of the year (ensuring a different license is selected daily) and posts the result to a specified channel via an internal messaging mechanism.3. Compatibility LogicThe heart of the agent is in the LicenseService, which defines a pre-computed compatibility matrix based on established open-source license guidelines (e.g., GPL's Copyleft requirements). This simple logic ensures accurate and fast results for queries like: "Can I use MIT with GPL-3.0?"🔗 Integration with Telex.im (A2A Protocol)Integration was handled via three main public HTTP endpoints, ensuring full compliance with the Agent-to-Agent (A2A) JSON-RPC 2.0 standard.1. Agent Card Discovery (/.well-known/agent-card)This is the handshake for Telex. The AgentCardController serves a static agent-card.json file that clearly lists the agent's capabilities (license-compatibility-check, daily-license-insights) and skills.2. Message Handling (/v1/message)This is the main interaction point. The MessageController is responsible for:Receiving the JSON-RPC request.Extracting the user's plain text message.Calling the MessageProcessor to determine the intent (compatibility check, info request, or list request).Returning a valid JSON-RPC result object with the final Markdown-formatted response.3. Health Check (/health)A simple endpoint used by the platform for monitoring, ensuring the server is up and responsive.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>architecture</category>
      <category>ai</category>
      <category>java</category>
    </item>
    <item>
      <title>Building My First RESTful API: Backend Wizards Stage 0 Journey 🚀</title>
      <dc:creator>Luvie</dc:creator>
      <pubDate>Sun, 19 Oct 2025 08:47:47 +0000</pubDate>
      <link>https://forem.com/luvie/building-my-first-restful-api-backend-wizards-stage-0-journey-2n51</link>
      <guid>https://forem.com/luvie/building-my-first-restful-api-backend-wizards-stage-0-journey-2n51</guid>
      <description>&lt;h1&gt;
  
  
  Building My First RESTful API: Backend Wizards Stage 0 Journey 🚀
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;A complete walkthrough of building a dynamic profile endpoint with Java and Spring Boot&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  📋 Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The Challenge&lt;/li&gt;
&lt;li&gt;Why Java and Spring Boot?&lt;/li&gt;
&lt;li&gt;Architecture Overview&lt;/li&gt;
&lt;li&gt;Implementation Journey&lt;/li&gt;
&lt;li&gt;Key Learnings&lt;/li&gt;
&lt;li&gt;Challenges Faced&lt;/li&gt;
&lt;li&gt;Testing &amp;amp; Deployment&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🎯 The Challenge {#the-challenge}
&lt;/h2&gt;

&lt;p&gt;Backend Wizards Stage 0 presented an interesting task: build a RESTful API endpoint that combines static user profile data with dynamic external API integration. The requirements were clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Endpoint&lt;/strong&gt;: &lt;code&gt;GET /me&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response&lt;/strong&gt;: JSON with user info, timestamp, and cat fact&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;External API&lt;/strong&gt;: Fetch fresh cat facts from catfact.ninja&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Data&lt;/strong&gt;: New timestamp and cat fact on every request&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling&lt;/strong&gt;: Graceful fallbacks for API failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's what the response should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user"&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="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"developer@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Developer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"stack"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Java/Spring Boot"&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="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2025-10-18T12:34:56.789Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fact"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cats can rotate their ears 180 degrees."&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;h2&gt;
  
  
  🤔 Why Java and Spring Boot? {#tech-stack}
&lt;/h2&gt;

&lt;p&gt;While I could have chosen any language, I opted for &lt;strong&gt;Java with Spring Boot&lt;/strong&gt; for several reasons:&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages:
&lt;/h3&gt;

&lt;p&gt;✅ &lt;strong&gt;Industry Standard&lt;/strong&gt; - Widely used in enterprise applications&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Spring Boot Magic&lt;/strong&gt; - Auto-configuration saves tons of boilerplate&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Strong Typing&lt;/strong&gt; - Catches errors at compile time&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Excellent Ecosystem&lt;/strong&gt; - Mature libraries and tools&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;RestTemplate&lt;/strong&gt; - Built-in HTTP client with timeout support&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Easy Deployment&lt;/strong&gt; - Single JAR file, runs anywhere  &lt;/p&gt;
&lt;h3&gt;
  
  
  Tech Stack:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Java 17&lt;/strong&gt; - Latest LTS version&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spring Boot 3.2.0&lt;/strong&gt; - Web framework&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maven&lt;/strong&gt; - Dependency management&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RestTemplate&lt;/strong&gt; - HTTP client&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jackson&lt;/strong&gt; - JSON serialization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLF4J&lt;/strong&gt; - Logging&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  🏗️ Architecture Overview {#architecture}
&lt;/h2&gt;

&lt;p&gt;I followed a clean &lt;strong&gt;MVC architecture&lt;/strong&gt; with clear separation of concerns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────┐
│     ProfileController               │  ← HTTP Layer
│  (Handles REST requests/responses)  │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│       ProfileService                │  ← Business Logic
│  (Fetches cat facts, builds model)  │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│      External Cat Facts API         │  ← External Integration
│     (https://catfact.ninja/fact)    │
└─────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Layer Breakdown:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Controller Layer&lt;/strong&gt; (&lt;code&gt;ProfileController.java&lt;/code&gt;)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handles HTTP requests&lt;/li&gt;
&lt;li&gt;Returns proper status codes&lt;/li&gt;
&lt;li&gt;Manages error responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Service Layer&lt;/strong&gt; (&lt;code&gt;ProfileService.java&lt;/code&gt;)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Business logic&lt;/li&gt;
&lt;li&gt;External API calls&lt;/li&gt;
&lt;li&gt;Data transformation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. DTO Layer&lt;/strong&gt; (Data Transfer Objects)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ProfileResponse&lt;/code&gt; - Main response structure&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UserInfo&lt;/code&gt; - User profile data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CatFactResponse&lt;/code&gt; - External API response&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💻 Implementation Journey {#implementation}
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Setting Up the Project
&lt;/h3&gt;

&lt;p&gt;Created a Spring Boot project with Maven:&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;parent&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-parent&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.2.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/parent&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Building the Main Application
&lt;/h3&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="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProfileApplication&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;ProfileApplication&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;Simple and clean! Spring Boot handles all the heavy lifting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Creating the REST Controller
&lt;/h3&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="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProfileController&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;ProfileService&lt;/span&gt; &lt;span class="n"&gt;profileService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&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="s"&gt;"/me"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;produces&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON_VALUE&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;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getProfile&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="nc"&gt;ProfileResponse&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;profileService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProfileWithCatFact&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;ok&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;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;// Error handling&lt;/span&gt;
            &lt;span class="nc"&gt;Map&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;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
            &lt;span class="n"&gt;errorResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"error"&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="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"timestamp"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Instant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&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="mi"&gt;503&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;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Points:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@RestController&lt;/code&gt; - Combines &lt;code&gt;@Controller&lt;/code&gt; and &lt;code&gt;@ResponseBody&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@GetMapping&lt;/code&gt; - Maps HTTP GET requests&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ResponseEntity&lt;/code&gt; - Full control over HTTP response&lt;/li&gt;
&lt;li&gt;Error handling with proper status codes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4: Implementing the Service Layer
&lt;/h3&gt;

&lt;p&gt;The most interesting part - integrating with the external 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="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;ProfileService&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;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="nf"&gt;ProfileService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RestTemplateBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;restTemplate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setConnectTimeout&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;5&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setReadTimeout&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;5&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="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ProfileResponse&lt;/span&gt; &lt;span class="nf"&gt;getProfileWithCatFact&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;catFact&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetchCatFact&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;UserInfo&lt;/span&gt; &lt;span class="n"&gt;userInfo&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;UserInfo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stack&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;ProfileResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"success"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;userInfo&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;Instant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;  &lt;span class="c1"&gt;// ISO 8601 timestamp&lt;/span&gt;
            &lt;span class="n"&gt;catFact&lt;/span&gt;
        &lt;span class="o"&gt;);&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="nf"&gt;fetchCatFact&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;CatFactResponse&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;getForObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"https://catfact.ninja/fact"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;CatFactResponse&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="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;getFact&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;&lt;strong&gt;Critical Implementation Details:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Timeout Configuration&lt;/strong&gt;: 5-second timeout prevents hanging&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ISO 8601 Timestamps&lt;/strong&gt;: &lt;code&gt;Instant.now().toString()&lt;/code&gt; automatically formats&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RestTemplate&lt;/strong&gt;: Spring's HTTP client with automatic JSON mapping&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constructor Injection&lt;/strong&gt;: Best practice for dependency injection&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 5: Creating DTOs
&lt;/h3&gt;

&lt;p&gt;Clean data transfer objects for type safety:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
java
public class ProfileResponse {
    @JsonProperty("status")
    private String status;

    @JsonProperty("user")
    private UserInfo user;

    @JsonProperty("timestamp")
    private String timestamp;

    @JsonProperty("fact")
    private String fact;

    // Constructors, getters
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>springboot</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>java</category>
    </item>
  </channel>
</rss>
