com.google.apis
google-api-services-gmail
diff --git a/infrastructure/src/main/java/com/pablotj/restemailbridge/infrastructure/config/OpenApiConfig.java b/infrastructure/src/main/java/com/pablotj/restemailbridge/infrastructure/config/OpenApiConfig.java
new file mode 100644
index 0000000..a500f5b
--- /dev/null
+++ b/infrastructure/src/main/java/com/pablotj/restemailbridge/infrastructure/config/OpenApiConfig.java
@@ -0,0 +1,46 @@
+package com.pablotj.restemailbridge.infrastructure.config;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Contact;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.info.License;
+import io.swagger.v3.oas.models.parameters.Parameter;
+import io.swagger.v3.oas.models.media.StringSchema;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springdoc.core.customizers.OpenApiCustomizer;
+@Configuration
+public class OpenApiConfig {
+
+ @Bean
+ public OpenAPI customOpenAPI() {
+ return new OpenAPI()
+ .info(new Info()
+ .title("Rest Email Bridge API")
+ .version("v1")
+ .description("API for sending and managing emails")
+ .license(new License().name("Apache 2.0").url("https://www.apache.org/licenses/LICENSE-2.0"))
+ );
+ }
+
+
+ @Bean
+ public OpenApiCustomizer globalHeaderCustomizer() {
+ return openApi -> openApi.getPaths().values().forEach(pathItem ->
+ pathItem.readOperations().forEach(operation ->
+ operation.addParametersItem(
+ new Parameter()
+ .in("header")
+ .name("Accept-Language")
+ .description("Language for messages (en, es, gl)")
+ .required(false)
+ .schema(new StringSchema()
+ ._default("en")
+ .addEnumItem("en")
+ .addEnumItem("es")
+ .addEnumItem("gl"))
+ )
+ )
+ );
+ }
+}
\ No newline at end of file
diff --git a/infrastructure/src/main/java/com/pablotj/restemailbridge/infrastructure/rest/MailController.java b/infrastructure/src/main/java/com/pablotj/restemailbridge/infrastructure/rest/MailController.java
index 5d7340a..5983ed7 100644
--- a/infrastructure/src/main/java/com/pablotj/restemailbridge/infrastructure/rest/MailController.java
+++ b/infrastructure/src/main/java/com/pablotj/restemailbridge/infrastructure/rest/MailController.java
@@ -3,6 +3,13 @@ package com.pablotj.restemailbridge.infrastructure.rest;
import com.pablotj.restemailbridge.application.dto.EmailDTO;
import com.pablotj.restemailbridge.application.usecase.SendEmailUseCase;
import com.pablotj.restemailbridge.infrastructure.rest.dto.SendMailRequest;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
@@ -10,18 +17,76 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
+/**
+ * REST controller responsible for handling email-related requests.
+ *
+ * Exposes endpoints under {@code /v1/mail} to send emails through the system.
+ * Delegates business logic to the {@link SendEmailUseCase}.
+ */
@RestController
@RequestMapping("/v1/mail")
+@Tag(name = "Mail API", description = "Endpoints for sending emails")
public class MailController {
private final SendEmailUseCase sendEmailUseCase;
+ /**
+ * Creates a new {@link MailController} instance.
+ *
+ * @param sendEmailUseCase the use case responsible for sending emails
+ */
public MailController(SendEmailUseCase sendEmailUseCase) {
this.sendEmailUseCase = sendEmailUseCase;
}
-
+ /**
+ * Sends a new email using the provided request data.
+ *
+ * The request payload is validated using {@link jakarta.validation.Valid}.
+ *
+ * @param request the email request containing sender, subject and body
+ * @return {@link ResponseEntity} with HTTP 200 (OK) if the email is sent successfully
+ */
@PostMapping
+ @Operation(
+ summary = "Send an email",
+ description = "Sends an email using the provided sender, subject, and body.",
+ requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
+ required = true,
+ content = @Content(
+ mediaType = "application/json",
+ examples = @ExampleObject(
+ name = "Basic email",
+ value = "{ \"from\": \"user@example.com\", \"subject\": \"Hello\", \"body\": \"Hi there!\" }"
+ )
+ )
+ )
+ )
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "Email sent successfully"),
+ @ApiResponse(responseCode = "400", description = "Invalid request payload"),
+ @ApiResponse(
+ responseCode = "401",
+ description = "Unauthorized – missing or invalid authentication token",
+ content = @Content(schema = @Schema(hidden = true))
+ ),
+ @ApiResponse(
+ responseCode = "403",
+ description = "Forbidden – the authenticated user cannot send to the specified recipient",
+ content = @Content(schema = @Schema(hidden = true))
+ ),
+ @ApiResponse(
+ responseCode = "422",
+ description = "Unprocessable Entity – domain validation failed (e.g. invalid email address, business rule violation)",
+ content = @Content(
+ mediaType = "application/json",
+ schema = @Schema(
+ example = "{ \"error\": \"Invalid recipient domain\" }"
+ )
+ )
+ ),
+ @ApiResponse(responseCode = "500", description = "Unexpected server error")
+ })
public ResponseEntity send(@Valid @RequestBody SendMailRequest request) {
sendEmailUseCase.handle(new EmailDTO(request.from(), request.subject(), request.body()));
return ResponseEntity.ok().build();
diff --git a/infrastructure/src/main/java/com/pablotj/restemailbridge/infrastructure/rest/dto/SendMailRequest.java b/infrastructure/src/main/java/com/pablotj/restemailbridge/infrastructure/rest/dto/SendMailRequest.java
index 11c752d..c9143ec 100644
--- a/infrastructure/src/main/java/com/pablotj/restemailbridge/infrastructure/rest/dto/SendMailRequest.java
+++ b/infrastructure/src/main/java/com/pablotj/restemailbridge/infrastructure/rest/dto/SendMailRequest.java
@@ -1,12 +1,26 @@
package com.pablotj.restemailbridge.infrastructure.rest.dto;
+import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import org.hibernate.validator.constraints.Length;
+@Schema(description = "Request payload to send an email")
public record SendMailRequest(
- @NotBlank @Email @Length(min = 4, max = 100) String from,
- @NotBlank @Length(min=1, max = 30) String subject,
- @NotBlank @Length(min=1, max = 4000) String body
+ @NotBlank(message = "{email.from.blank}")
+ @Email(message = "{email.from.invalid}")
+ @Length(min = 4, max = 100, message = "email.from.length}")
+ @Schema(description = "Sender email address", example = "user@example.com")
+ String from,
+
+ @NotBlank(message = "{email.subject.blank}")
+ @Length(min=1, max = 30, message = "{email.subject.length}")
+ @Schema(description = "Email subject", example = "Welcome to RestEmailBridge")
+ String subject,
+
+ @NotBlank(message = "{email.body.blank}")
+ @Length(min=1, max = 4000, message = "{email.body.length}")
+ @Schema(description = "Email body content", example = "Hello, thanks for signing up!")
+ String body
) {
}
\ No newline at end of file