Building My First RESTful API: Backend Wizards Stage 0 Journey πŸš€



This content originally appeared on DEV Community and was authored by Luvie

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."
}

🤔 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)    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

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>

Step 2: Building the Main Application

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

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);
        }
    }
}

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();
    }
}

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


This content originally appeared on DEV Community and was authored by Luvie