Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,38 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
* Main entry point for the API Gateway microservice.
*
* <p>This class bootstraps the Spring Boot application and registers it as a Eureka client
* for service discovery. The API Gateway serves as the single entry point for all client
* requests, routing them to the appropriate microservices.</p>
*
* <p>Key responsibilities:</p>
* <ul>
* <li>Centralized routing of API requests to backend microservices</li>
* <li>Authentication and authorization via OAuth2/JWT</li>
* <li>Service discovery integration with Eureka</li>
* <li>Load balancing across service instances</li>
* </ul>
*
* @author Training Team
* @version 1.0
* @see org.training.api.gateway.config.SecurityConfig
*/
@SpringBootApplication
@EnableEurekaClient
public class ApiGatewayApplication {

/**
* Main method that starts the API Gateway application.
*
* <p>This method initializes the Spring application context and starts the embedded
* web server. The gateway will automatically register with the Eureka service registry
* upon startup.</p>
*
* @param args command-line arguments passed to the application (typically empty)
*/
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,65 @@
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;

/**
* Security configuration class for the API Gateway.
*
* <p>This class configures Spring Security for the reactive web application,
* implementing OAuth2 authentication and JWT token validation. It defines
* which endpoints are publicly accessible and which require authentication.</p>
*
* <p>Security features configured:</p>
* <ul>
* <li>OAuth2 login support for user authentication</li>
* <li>JWT token validation for API requests</li>
* <li>Public access to registration endpoint</li>
* <li>CSRF protection disabled for stateless API</li>
* </ul>
*
* @author Training Team
* @version 1.0
* @see org.springframework.security.config.web.server.ServerHttpSecurity
*/
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

/**
* Configures the security filter chain for the API Gateway.
*
* <p>This method sets up the security rules for incoming HTTP requests:</p>
* <ul>
* <li>The user registration endpoint (/api/users/register) is publicly accessible
* to allow new users to create accounts without authentication</li>
* <li>All other endpoints require authentication via OAuth2/JWT</li>
* <li>CSRF protection is disabled since this is a stateless REST API</li>
* <li>OAuth2 login is enabled for interactive authentication flows</li>
* <li>JWT validation is configured for the OAuth2 resource server</li>
* </ul>
*
* @param http the {@link ServerHttpSecurity} object used to configure security
* @return the configured {@link SecurityWebFilterChain} bean
*/
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
// Configure authorization rules for different endpoints
http
.authorizeExchange()
//ALLOWING REGISTER API FOR DIRECT ACCESS
// Allow unauthenticated access to the registration endpoint
// so new users can create accounts
.pathMatchers("/api/users/register").permitAll()
//ALL OTHER APIS ARE AUTHENTICATED
// Require authentication for all other API endpoints
.anyExchange().authenticated()
.and()
// Disable CSRF protection for stateless REST API
// (tokens are used instead of session cookies)
.csrf().disable()
// Enable OAuth2 login for interactive authentication
.oauth2Login()
.and()
// Configure JWT validation for API requests
.oauth2ResourceServer()
.jwt();
return http.build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,25 @@

import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* Integration tests for the API Gateway application.
*
* <p>This test class verifies that the Spring application context
* loads correctly with all required beans and configurations.</p>
*
* @author Training Team
* @version 1.0
*/
@SpringBootTest
class ApiGatewayApplicationTests {

/**
* Verifies that the Spring application context loads successfully.
*
* <p>This test ensures that all Spring beans are properly configured
* and the application can start without errors. A failure in this test
* typically indicates configuration issues or missing dependencies.</p>
*/
@Test
void contextLoads() {
assertTrue(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,40 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
* Main entry point for the Account Service microservice.
*
* <p>This microservice manages bank account operations including account creation,
* status updates, balance inquiries, and account closure. It communicates with
* other microservices (User Service, Transaction Service, Sequence Generator)
* via Feign clients for inter-service communication.</p>
*
* <p>Key responsibilities:</p>
* <ul>
* <li>Creating and managing bank accounts</li>
* <li>Updating account status (PENDING, ACTIVE, BLOCKED, CLOSED)</li>
* <li>Retrieving account balances and transaction histories</li>
* <li>Processing account closure requests</li>
* <li>Validating user existence before account creation</li>
* </ul>
*
* @author Training Team
* @version 1.0
* @see org.training.account.service.service.AccountService
* @see org.training.account.service.controller.AccountController
*/
@SpringBootApplication
@EnableFeignClients
public class AccountServiceApplication {

/**
* Main method that starts the Account Service application.
*
* <p>This method initializes the Spring application context, enables Feign
* clients for inter-service communication, and starts the embedded web server.</p>
*
* @param args command-line arguments passed to the application (typically empty)
*/
public static void main(String[] args) {
SpringApplication.run(AccountServiceApplication.class, args);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
* Custom error decoder for Feign client responses.
*
* <p>This class implements the Feign {@link ErrorDecoder} interface to provide
* custom error handling for HTTP responses from external services. It extracts
* error information from the response body and converts it into appropriate
* exception types.</p>
*
* <p>The decoder handles:</p>
* <ul>
* <li>400 Bad Request errors - converted to {@link GlobalException}</li>
* <li>Other errors - wrapped in a generic Exception</li>
* </ul>
*
* @author Training Team
* @version 1.0
* @see feign.codec.ErrorDecoder
*/
@Slf4j
public class FeignClientErrorDecoder implements ErrorDecoder {

Expand Down Expand Up @@ -69,4 +87,4 @@ private GlobalException extractGlobalException(Response response) {
}
return globalException;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* Configuration class for Feign clients in the Account Service.
*
* <p>This configuration extends the default Feign client configuration and provides
* custom error handling for inter-service communication. It registers a custom
* error decoder to properly handle and translate errors from external services.</p>
*
* @author Training Team
* @version 1.0
* @see org.training.account.service.configuration.FeignClientErrorDecoder
*/
@Configuration
public class FeignConfiguration extends FeignClientProperties.FeignClientConfiguration {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,40 @@

import java.util.List;

/**
* REST controller for managing bank account operations.
*
* <p>This controller exposes endpoints for creating, reading, updating, and closing
* bank accounts. It handles all account-related HTTP requests and delegates business
* logic to the {@link AccountService}.</p>
*
* <p>Base URL: /accounts</p>
*
* <p>Available endpoints:</p>
* <ul>
* <li>POST /accounts - Create a new account</li>
* <li>GET /accounts - Get account by account number</li>
* <li>PUT /accounts - Update account details</li>
* <li>PATCH /accounts - Update account status</li>
* <li>GET /accounts/balance - Get account balance</li>
* <li>GET /accounts/{accountId}/transactions - Get account transactions</li>
* <li>PUT /accounts/closure - Close an account</li>
* <li>GET /accounts/{userId} - Get account by user ID</li>
* </ul>
*
* @author Training Team
* @version 1.0
* @see org.training.account.service.service.AccountService
*/
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/accounts")
public class AccountController {

/**
* Service for handling account business logic.
*/
private final AccountService accountService;

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
package org.training.account.service.exception;

/**
* Exception thrown when an account cannot be closed.
*
* <p>This exception is thrown when an account closure operation fails due to
* business rule violations. For example, attempting to close an account that
* still has a non-zero balance. It results in an HTTP 400 Bad Request response.</p>
*
* @author Training Team
* @version 1.0
* @see org.training.account.service.exception.GlobalException
*/
public class AccountClosingException extends GlobalException{

/**
* Constructs an AccountClosingException with the specified error message.
*
* @param errorMessage the detailed error message describing why the account cannot be closed
*/
public AccountClosingException(String errorMessage) {
super(GlobalErrorCode.BAD_REQUEST, errorMessage);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
package org.training.account.service.exception;

/**
* Exception thrown when an account status prevents an operation.
*
* <p>This exception is thrown when an operation cannot be performed due to
* the current status of an account. For example, attempting to perform
* transactions on an inactive or closed account. It results in an HTTP 400
* Bad Request response.</p>
*
* @author Training Team
* @version 1.0
* @see org.training.account.service.exception.GlobalException
*/
public class AccountStatusException extends GlobalException {

/**
* Constructs an AccountStatusException with the specified error message.
*
* @param errorMessage the detailed error message describing the status issue
*/
public AccountStatusException(String errorMessage) {
super(errorMessage, GlobalErrorCode.BAD_REQUEST);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,29 @@
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* Data Transfer Object for error responses.
*
* <p>This class represents the structure of error responses returned by the API
* when an exception occurs. It provides a consistent format for error information
* that clients can parse and handle appropriately.</p>
*
* @author Training Team
* @version 1.0
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ErrorResponse {

/**
* The error code (e.g., "400", "404", "409").
*/
private String errorCode;

/**
* A human-readable error message describing what went wrong.
*/
private String message;
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
package org.training.account.service.exception;

/**
* Constants class containing standard HTTP error codes used throughout the application.
*
* <p>This utility class provides centralized error code constants that are used
* when creating exception responses. Using constants ensures consistency across
* all error handling in the service.</p>
*
* @author Training Team
* @version 1.0
*/
public class GlobalErrorCode {

/**
* Private constructor to prevent instantiation of this utility class.
*/
private GlobalErrorCode() {}

/** HTTP 404 Not Found - Resource does not exist. */
public static final String NOT_FOUND = "404";

/** HTTP 409 Conflict - Resource already exists or state conflict. */
public static final String CONFLICT = "409";

/** HTTP 400 Bad Request - Invalid request parameters or state. */
public static final String BAD_REQUEST = "400";
}
Loading