DEV Community

Luvie
Luvie

Posted on

Building My First RESTful API: Backend Wizards Stage 0 Journey 🚀

Building My First RESTful API: Backend Wizards Stage 0 Journey 🚀

A complete walkthrough of building a dynamic profile endpoint with Java and Spring Boot


📋 Table of Contents

  1. The Challenge
  2. Why Java and Spring Boot?
  3. Architecture Overview
  4. Implementation Journey
  5. Key Learnings
  6. Challenges Faced
  7. Testing & Deployment
  8. Conclusion

🎯 The Challenge {#the-challenge}

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:

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

Here's what the response should look like:

{
  "status": "success",
  "user": {
    "email": "developer@example.com",
    "name": "John Developer",
    "stack": "Java/Spring Boot"
  },
  "timestamp": "2025-10-18T12:34:56.789Z",
  "fact": "Cats can rotate their ears 180 degrees."
}
Enter fullscreen mode Exit fullscreen mode

🤔 Why Java and Spring Boot? {#tech-stack}

While I could have chosen any language, I opted for Java with Spring Boot for several reasons:

Advantages:

Industry Standard - Widely used in enterprise applications

Spring Boot Magic - Auto-configuration saves tons of boilerplate

Strong Typing - Catches errors at compile time

Excellent Ecosystem - Mature libraries and tools

RestTemplate - Built-in HTTP client with timeout support

Easy Deployment - Single JAR file, runs anywhere

Tech Stack:

  • Java 17 - Latest LTS version
  • Spring Boot 3.2.0 - Web framework
  • Maven - Dependency management
  • RestTemplate - HTTP client
  • Jackson - JSON serialization
  • SLF4J - Logging

🏗️ Architecture Overview {#architecture}

I followed a clean MVC architecture with clear separation of concerns:

┌─────────────────────────────────────┐
│     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)    │
└─────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Layer Breakdown:

1. Controller Layer (ProfileController.java)

  • Handles HTTP requests
  • Returns proper status codes
  • Manages error responses

2. Service Layer (ProfileService.java)

  • Business logic
  • External API calls
  • Data transformation

3. DTO Layer (Data Transfer Objects)

  • ProfileResponse - Main response structure
  • UserInfo - User profile data
  • CatFactResponse - External API response

💻 Implementation Journey {#implementation}

Step 1: Setting Up the Project

Created a Spring Boot project with Maven:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.0</version>
</parent>
Enter fullscreen mode Exit fullscreen mode

Step 2: Building the Main Application

@SpringBootApplication
public class ProfileApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProfileApplication.class, args);
    }
}
Enter fullscreen mode Exit fullscreen mode

Simple and clean! Spring Boot handles all the heavy lifting.

Step 3: Creating the REST Controller

@RestController
public class ProfileController {

    @Autowired
    private ProfileService profileService;

    @GetMapping(value = "/me", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> getProfile() {
        try {
            ProfileResponse response = profileService.getProfileWithCatFact();
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            // Error handling
            Map<String, Object> errorResponse = new HashMap<>();
            errorResponse.put("status", "error");
            errorResponse.put("timestamp", Instant.now().toString());
            return ResponseEntity.status(503).body(errorResponse);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • @RestController - Combines @Controller and @ResponseBody
  • @GetMapping - Maps HTTP GET requests
  • ResponseEntity - Full control over HTTP response
  • Error handling with proper status codes

Step 4: Implementing the Service Layer

The most interesting part - integrating with the external API:

@Service
public class ProfileService {

    private final RestTemplate restTemplate;

    public ProfileService(RestTemplateBuilder builder) {
        this.restTemplate = builder
            .setConnectTimeout(Duration.ofSeconds(5))
            .setReadTimeout(Duration.ofSeconds(5))
            .build();
    }

    public ProfileResponse getProfileWithCatFact() {
        String catFact = fetchCatFact();
        UserInfo userInfo = new UserInfo(email, name, stack);

        return new ProfileResponse(
            "success",
            userInfo,
            Instant.now().toString(),  // ISO 8601 timestamp
            catFact
        );
    }

    private String fetchCatFact() {
        CatFactResponse response = restTemplate.getForObject(
            "https://catfact.ninja/fact",
            CatFactResponse.class
        );
        return response.getFact();
    }
}
Enter fullscreen mode Exit fullscreen mode

Critical Implementation Details:

  1. Timeout Configuration: 5-second timeout prevents hanging
  2. ISO 8601 Timestamps: Instant.now().toString() automatically formats
  3. RestTemplate: Spring's HTTP client with automatic JSON mapping
  4. Constructor Injection: Best practice for dependency injection

Step 5: Creating DTOs

Clean data transfer objects for type safety:


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
Enter fullscreen mode Exit fullscreen mode

Top comments (0)