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)