diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index f7f2d6d..0df2d3d 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -63,9 +63,6 @@ jobs:
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_ACCESS_SECRET }}
- TF_VAR_db_user: ${{ secrets.DB_USER }}
- TF_VAR_db_password: ${{ secrets.DB_PASSWORD }}
- TF_VAR_jwt_secret: ${{ secrets.JWT_SECRET_KEY }}
aws-region: us-east-1
TF_VAR_lambda_jar_path: app/target/lambda-identification-client.jar
@@ -76,8 +73,5 @@ jobs:
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_ACCESS_SECRET }}
- TF_VAR_db_user: ${{ secrets.DB_USER }}
- TF_VAR_db_password: ${{ secrets.DB_PASSWORD }}
- TF_VAR_jwt_secret: ${{ secrets.JWT_SECRET_KEY }}
aws-region: us-east-1
TF_VAR_lambda_jar_path: app/target/lambda-identification-client.jar
diff --git a/app/pom.xml b/app/pom.xml
index fc1df82..c305023 100644
--- a/app/pom.xml
+++ b/app/pom.xml
@@ -65,6 +65,11 @@
0.12.3
runtime
+
+ software.amazon.awssdk
+ dynamodb
+ 2.25.10
+
diff --git a/app/src/main/java/tech/buildrun/lambda/HandlerClient.java b/app/src/main/java/tech/buildrun/lambda/HandlerClient.java
index 0fb9695..0875f25 100644
--- a/app/src/main/java/tech/buildrun/lambda/HandlerClient.java
+++ b/app/src/main/java/tech/buildrun/lambda/HandlerClient.java
@@ -5,17 +5,18 @@
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import com.fasterxml.jackson.databind.ObjectMapper;
+import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
+import software.amazon.awssdk.services.dynamodb.model.*;
-import java.sql.*;
-import java.util.Map;
+import java.util.*;
-public class HandlerClient implements RequestHandler {
+public class HandlerClient implements
+ RequestHandler {
- private static final String DB_URL = System.getenv("DB_URL");
- private static final String DB_USER = System.getenv("DB_USER");
- private static final String DB_PASSWORD = System.getenv("DB_PASSWORD");
+ private static final String TABLE_NAME = "tc-identification-table";
private final ObjectMapper mapper = new ObjectMapper();
+ private final DynamoDbClient dynamo = DynamoDbClient.create();
@Override
public APIGatewayProxyResponseEvent handleRequest(
@@ -29,24 +30,18 @@ public APIGatewayProxyResponseEvent handleRequest(
context.getLogger().log("METHOD=" + method);
context.getLogger().log("PATH=" + path);
- Class.forName("org.postgresql.Driver");
-
- try (Connection conn =
- DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD)) {
-
- // POST /clientes
- if ("POST".equals(method) && "/clientes".equals(path)) {
- return criarCliente(request, conn);
- }
-
- // GET /clientes/{document}
- if ("GET".equals(method) && path.startsWith("/clientes/")) {
- return consultarCliente(path, conn);
- }
+ // POST /clientes
+ if ("POST".equals(method) && "/clientes".equals(path)) {
+ return criarCliente(request);
+ }
- return response(404, Map.of("message", "Endpoint não encontrado"));
+ // GET /clientes/{document}
+ if ("GET".equals(method) && path.startsWith("/clientes/")) {
+ return consultarCliente(path);
}
+ return response(404, Map.of("message", "Endpoint não encontrado"));
+
} catch (Exception e) {
e.printStackTrace();
return response(500, Map.of("message", "Erro interno"));
@@ -56,14 +51,14 @@ public APIGatewayProxyResponseEvent handleRequest(
// ===================== CRIAR CLIENTE =====================
private APIGatewayProxyResponseEvent criarCliente(
- APIGatewayProxyRequestEvent request,
- Connection conn) throws Exception {
+ APIGatewayProxyRequestEvent request) throws Exception {
if (request.getBody() == null || request.getBody().isBlank()) {
return response(400, Map.of("message", "Body obrigatório"));
}
- Map body = mapper.readValue(request.getBody(), Map.class);
+ Map body =
+ mapper.readValue(request.getBody(), Map.class);
String document = body.get("document");
String name = body.get("name");
@@ -75,63 +70,78 @@ private APIGatewayProxyResponseEvent criarCliente(
));
}
- String sql = """
- INSERT INTO tb_cliente (nr_documento, nm_cliente, ds_email)
- VALUES (?, ?, ?)
- """;
-
- try (PreparedStatement ps = conn.prepareStatement(sql)) {
- ps.setString(1, document);
- ps.setString(2, name);
- ps.setString(3, email);
- ps.executeUpdate();
-
- return response(201, Map.of(
- "message", "Cliente criado com sucesso",
- "document", document
- ));
-
- } catch (SQLException e) {
- if ("23505".equals(e.getSQLState())) {
- return response(409, Map.of("message", "Cliente já existe"));
- }
- throw e;
+ // 🔍 Verifica se já existe (regra do SQL 23505)
+ if (clienteExistePorDocumento(document)) {
+ return response(409, Map.of("message", "Cliente já existe"));
}
+
+ Map item = new HashMap<>();
+ item.put("id", AttributeValue.builder()
+ .s(UUID.randomUUID().toString()).build());
+ item.put("nr_documento", AttributeValue.builder().s(document).build());
+ item.put("nm_cliente", AttributeValue.builder().s(name).build());
+ item.put("ds_email", AttributeValue.builder().s(email).build());
+
+ dynamo.putItem(PutItemRequest.builder()
+ .tableName(TABLE_NAME)
+ .item(item)
+ .build());
+
+ return response(201, Map.of(
+ "message", "Cliente criado com sucesso",
+ "document", document
+ ));
}
// ===================== CONSULTAR CLIENTE =====================
- private APIGatewayProxyResponseEvent consultarCliente(
- String path,
- Connection conn) throws Exception {
+ private APIGatewayProxyResponseEvent consultarCliente(String path)
+ throws Exception {
- // /clientes/123456
String document = path.substring("/clientes/".length());
- String sql = """
- SELECT id, nr_documento, nm_cliente, ds_email
- FROM tb_cliente
- WHERE nr_documento = ?
- """;
-
- try (PreparedStatement ps = conn.prepareStatement(sql)) {
- ps.setString(1, document);
- ResultSet rs = ps.executeQuery();
-
- if (rs.next()) {
- return response(200, Map.of(
- "id", rs.getLong("id"),
- "document", rs.getString("nr_documento"),
- "name", rs.getString("nm_cliente"),
- "email", rs.getString("ds_email")
- ));
- }
+ QueryRequest query = QueryRequest.builder()
+ .tableName(TABLE_NAME)
+ .indexName("DocumentoIndex")
+ .keyConditionExpression("nr_documento = :doc")
+ .expressionAttributeValues(Map.of(
+ ":doc", AttributeValue.builder().s(document).build()
+ ))
+ .limit(1)
+ .build();
+ QueryResponse response = dynamo.query(query);
+
+ if (response.count() == 0) {
return response(404, Map.of("message", "Cliente não encontrado"));
}
+
+ Map item = response.items().get(0);
+
+ return response(200, Map.of(
+ "id", item.get("id").s(),
+ "document", item.get("nr_documento").s(),
+ "name", item.get("nm_cliente").s(),
+ "email", item.get("ds_email").s()
+ ));
}
- // ===================== RESPONSE =====================
+ // ===================== UTIL =====================
+
+ private boolean clienteExistePorDocumento(String document) {
+
+ QueryRequest query = QueryRequest.builder()
+ .tableName(TABLE_NAME)
+ .indexName("DocumentoIndex")
+ .keyConditionExpression("nr_documento = :doc")
+ .expressionAttributeValues(Map.of(
+ ":doc", AttributeValue.builder().s(document).build()
+ ))
+ .limit(1)
+ .build();
+
+ return dynamo.query(query).count() > 0;
+ }
private APIGatewayProxyResponseEvent response(int status, Object body) {
try {
@@ -140,8 +150,10 @@ private APIGatewayProxyResponseEvent response(int status, Object body) {
.withHeaders(Map.of(
"Content-Type", "application/json",
"Access-Control-Allow-Origin", "*",
- "Access-Control-Allow-Headers", "Content-Type,Authorization",
- "Access-Control-Allow-Methods", "GET,POST,OPTIONS"
+ "Access-Control-Allow-Headers",
+ "Content-Type,Authorization",
+ "Access-Control-Allow-Methods",
+ "GET,POST,OPTIONS"
))
.withBody(mapper.writeValueAsString(body));
} catch (Exception e) {
@@ -150,4 +162,4 @@ private APIGatewayProxyResponseEvent response(int status, Object body) {
.withBody("{\"message\":\"Erro ao serializar resposta\"}");
}
}
-}
\ No newline at end of file
+}
diff --git a/lambda.tf b/lambda.tf
index 129eabc..69579d6 100644
--- a/lambda.tf
+++ b/lambda.tf
@@ -2,6 +2,36 @@ data "aws_iam_role" "lambda_exec_role" {
name = "tc-infra-id-lambda-exec-role"
}
+
+data "aws_dynamodb_table" "identification_table" {
+ name = "tc-identification-table"
+}
+
+resource "aws_iam_role_policy" "lambda_dynamodb_policy" {
+ role = data.aws_iam_role.lambda_exec_role.id
+
+ policy = jsonencode({
+ Version = "2012-10-17"
+ Statement = [{
+ Effect = "Allow"
+ Action = [
+ "dynamodb:PutItem",
+ "dynamodb:Query",
+ "dynamodb:GetItem"
+ ]
+ Resource = [
+ data.aws_dynamodb_table.identification_table.arn,
+ "${data.aws_dynamodb_table.identification_table.arn}/index/*"
+ ]
+ }]
+ })
+}
+
+resource "aws_iam_role_policy_attachment" "lambda_logs" {
+ role = data.aws_iam_role.lambda_exec_role.name
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
+}
+
data "aws_security_group" "id_lambda" {
name = "tc-id-lambda-sg"
vpc_id = data.aws_vpc.tc_lambda_vpc.id
@@ -9,25 +39,21 @@ data "aws_security_group" "id_lambda" {
resource "aws_lambda_function" "id_lambda" {
function_name = "lambda-identification-client"
- depends_on = []
- role = data.aws_iam_role.lambda_exec_role.arn
- handler = "tech.buildrun.lambda.HandlerClient::handleRequest"
- runtime = "java17"
- timeout = 10
+ role = data.aws_iam_role.lambda_exec_role.arn
+ handler = "tech.buildrun.lambda.HandlerClient::handleRequest"
+ runtime = "java17"
+ timeout = 30
- # Usa o caminho passado via variável
filename = var.lambda_jar_path
source_code_hash = filebase64sha256(var.lambda_jar_path)
environment {
variables = {
- DB_URL = local.jdbc_url
- DB_USER = var.db_user
- DB_PASSWORD = var.db_password
- JWT_SECRET = var.jwt_secret
+ TABLE_NAME = "tc-identification-table"
}
}
+
vpc_config {
subnet_ids = data.aws_subnets.tc_lambda_subnets.ids
security_group_ids = [data.aws_security_group.id_lambda.id]
diff --git a/locals.tf b/locals.tf
deleted file mode 100644
index f271e51..0000000
--- a/locals.tf
+++ /dev/null
@@ -1,3 +0,0 @@
-locals {
- jdbc_url = "jdbc:postgresql://${data.aws_db_instance.db_instance.address}:${data.aws_db_instance.db_instance.port}/${data.aws_db_instance.db_instance.db_name}"
-}
diff --git a/vars.tf b/vars.tf
index 285199c..306b400 100644
--- a/vars.tf
+++ b/vars.tf
@@ -11,23 +11,6 @@ variable "tags" {
}
}
-# Banco de dados
-variable "db_user" {
- description = "Usuário do banco de dados"
- sensitive = true
-}
-
-variable "db_password" {
- description = "Senha do banco de dados"
- sensitive = true
-}
-
-variable "jwt_secret" {
- description = "Chave secreta para geração de tokens JWT"
- type = string
- sensitive = true
-}
-
variable "lambda_jar_path" {
description = "Caminho do fat JAR da Lambda"
type = string