Skip to content

Yape Challenge - Sergio Siccha #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

.idea/
7 changes: 7 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ services:
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
redis:
image: "redis:latest"
ports:
- "6379:6379"
environment:
- ALLOW_EMPTY_PASSWORD=yes
- REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
zookeeper:
image: confluentinc/cp-zookeeper:5.5.3
environment:
Expand Down
38 changes: 38 additions & 0 deletions microservices/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/

### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr

### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/

### VS Code ###
.vscode/

### Mac OS ###
.DS_Store
37 changes: 37 additions & 0 deletions microservices/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## Composición del proyecto
El presente proyecto esta conformado por tres módulos

```
1. transaction-gateway
2. transaction-management
3. fraud-evaluation
```

## Detalle de Módulos

* transaction-gateway: Es el orquestador de las funcionalidades hacia el cliente. Utiliza GraphQL
* transaction-management: Microservicio dedicado para el mantenimiento de las transacciones en la BD.
* fraud-evaluation: Microservicio dedicado a la evaluación de fraudes de las transacciones registradas.

## Pasos a seguir para compilar la aplicación

1. Ejecutar el comando `docker-compose up -d` en la carpeta raiz del proyecto
2. Crear base de datos **bd_challenge**
3. Ejecutar script **01_init_query.sql** de la carpeta _/script_
4. Compilar cada uno de los módulos listados previamente



## Detalle de Funcionalidades

El microservicio transaction-gateway expone las siguientes funcionalidades:

1. Query
- getAllTransactions(limit, offset)
- getTransactionByCode(transactionCode)


2. Mutation
- createTransaction(transactionBody)


38 changes: 38 additions & 0 deletions microservices/fraud-evaluation/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/

### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr

### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/

### VS Code ###
.vscode/

### Mac OS ###
.DS_Store
51 changes: 51 additions & 0 deletions microservices/fraud-evaluation/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.yape</groupId>
<artifactId>microservices</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>fraud-evaluation</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>fraud-evaluation</name>
<description>Fraud Evaluation Service</description>

<dependencies>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

<!-- KAFKA LIBRARY -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<!-- KAFKA LIBRARY -->

<!-- REACTOR LIBRARY -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- REACTOR LIBRARY -->

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.yape.fraudevaluation;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class FraudEvaluationApplication {

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

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.yape.fraudevaluation.config;

import com.yape.fraudevaluation.model.dto.TransactionDTO;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
import org.springframework.kafka.core.*;
import org.springframework.kafka.support.serializer.ErrorHandlingDeserializer;
import org.springframework.kafka.support.serializer.JsonDeserializer;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class KafkaConfig {

@Value("${spring.kafka.bootstrap-servers}")
private String serverUrl;

@Value("${spring.kafka.consumer.group-id}")
private String groupId;

@Value("${spring.kafka.consumer.offset-mode}")
private String offsetMode;

@Bean
public ConsumerFactory<String, TransactionDTO> consumerFactory() {
Map<String, Object> configProps = new HashMap<>();

configProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, serverUrl);
configProps.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
configProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ErrorHandlingDeserializer.class);
configProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, ErrorHandlingDeserializer.class);
configProps.put(ErrorHandlingDeserializer.KEY_DESERIALIZER_CLASS, StringDeserializer.class);
configProps.put(ErrorHandlingDeserializer.VALUE_DESERIALIZER_CLASS, StringDeserializer.class);
configProps.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, offsetMode);

return new DefaultKafkaConsumerFactory<>(configProps, new ErrorHandlingDeserializer<>(), new ErrorHandlingDeserializer<>(new JsonDeserializer<>(TransactionDTO.class)));
}

@Bean
public ConcurrentKafkaListenerContainerFactory<String, TransactionDTO> kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, TransactionDTO> factory = new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());

return factory;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.yape.fraudevaluation.error;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class ErrorResponse {

private Integer errorCode;
private String description;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.yape.fraudevaluation.error;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(Throwable.class)
public ResponseEntity<ErrorResponse> handle(Throwable ex) {
log.error("Ocurrió un error en la aplicación {}", ex.toString());
ex.printStackTrace();
return new ResponseEntity<>(ErrorResponse.builder()
.errorCode(HttpStatus.INTERNAL_SERVER_ERROR.value())
.description(ex.getMessage())
.build(), HttpStatus.INTERNAL_SERVER_ERROR);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.yape.fraudevaluation.kafka.consumer;

import com.yape.fraudevaluation.model.dto.TransactionDTO;

public interface FraudMessageConsumer {

void retrieveMessage(TransactionDTO object);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.yape.fraudevaluation.kafka.consumer.impl;

import com.yape.fraudevaluation.kafka.consumer.FraudMessageConsumer;
import com.yape.fraudevaluation.model.dto.TransactionDTO;
import com.yape.fraudevaluation.service.FraudEvaluationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@RequiredArgsConstructor
public class FraudMessageConsumerImpl implements FraudMessageConsumer {

@Value("${fraud-evaluation.kafka-topics.transaction}")
private String transactionTopic;

private final FraudEvaluationService fraudEvaluationService;

@KafkaListener(
topics = "${fraud-evaluation.kafka-topics.transaction}",
groupId = "${spring.kafka.consumer.group-id}"
)
@Override
public void retrieveMessage(TransactionDTO object) {
try {
log.info("Retreived message from Topic {}. Message {}", transactionTopic, object.toString());

fraudEvaluationService.evaluateTransaction(object)
.subscribe();
} catch (Exception e) {
log.error("Exception on message send {}", e.toString());
throw new RuntimeException("Error occurs message retrieve");
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.yape.fraudevaluation.kafka.producer;

import com.yape.fraudevaluation.model.dto.TransactionDTO;

public interface FraudMessageProducer {

boolean sendMessage(TransactionDTO transactionDTO);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.yape.fraudevaluation.kafka.producer.impl;

import com.yape.fraudevaluation.kafka.producer.FraudMessageProducer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.yape.fraudevaluation.model.dto.TransactionDTO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@RequiredArgsConstructor
public class FraudMessageProducerImpl implements FraudMessageProducer {

private final KafkaTemplate<String, TransactionDTO> kafkaTemplate;

@Value("${fraud-evaluation.kafka-topics.fraud-evaluation}")
private String fraudTopic;

@Override
public boolean sendMessage(TransactionDTO transactionDTO) {
try {
log.info("Sending message {} to Topic {}", transactionDTO.toString(), fraudTopic);

kafkaTemplate.send(fraudTopic, transactionDTO);

return true;
} catch (Exception e) {
log.error("Exception on message send {}", e.toString());
throw new RuntimeException("Error occurs on message send");
}
}

}
Loading