Giter VIP home page Giter VIP logo

paymentapi's Introduction

Architecture

For the design of PaymentAPI I used DDD + CQRS + Event Sourcing, I will explain a little bit why the use of these three architectures patters.

DDD

Domain Driven Design it's a design pattern for dealing with highly complex domains that is based on making the domain itself the main focus of the project.

Also it helps to decouple the different layers of your program(Application, Domain, Infrastructure) making it more extensible and easy to port each of the layers into another program if it's needed.

In PaymentAPI I implemented three modules described like:

  • Application: Layer which normally is the entry point of your app. It has dependency with domain and infrastructure modules.
  • Domain: Layer where you implement the business logic of your application. It does not have any dependency.
  • Infrastructure: Layer where you implement the communication with the backends (Database, services, Brokers). It has dependency with domain.

My image

CQRS

Command Query Responsibility Segregation it's another Design pattern, mostly divulged by Greg Young which segregate the model of Commands and Queries in your architecture to do Writes and Reads separated. It can give you the chance to make the Queries more efficient since normally in a Cluster the 90% of the traffic is for Queries.

In PaymentAPI I implemented Handler for Commands and Service to deal with Queries.

  • Handler: Receives commands and transforms the Command into Domain model, to pass the responsibility to the domain, and finally into the infrastructure.
  • Service: Receives Queries and invokes directly to the DAO in the infrastructure layer.

Event Sourcing

Event sourcing is a design pattern where you work with Events. The main idea of Event sourcing is to keep and persist the state of your program, without mutating previous states.

That means that with Event sourcing I'm not deleting any data in the system, giving us the possibility to have an historical about the different state of one Payment.

In PaymentAPI, Event sourcing together with CQRS, allow us persist events in order to keep state and have historical data.

  • PaymentAdded: Event that keep the state of the creation of a payment.
  • PaymentUpdated: Event that keep the state of the change of a payment.
  • PaymentDeleted: Event that keep the state of the deletion of a payment.

API

The design of the API is based on Restful design, so for Queries I used GET, for create POST, update PUT and delete DELETE

Since the root of the endpoints is /v1/payment many of the endpoints do not require any extra word, only arguments as Query param

@Path("/v1/payment")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class PaymentResource {

    @GET
    @Path("/all")
    public CompletionStage<PaymentResponse<?>> fetchAllPayment() 
    
    @GET
    @Path("/{paymentId}")
    public CompletionStage<PaymentResponse<?>> fetchPaymentById(@PathParam("paymentId") String id)
    
    @POST
    @Path("/")
    public CompletionStage<PaymentResponse<String>> addPayment(AddPaymentCommand addPaymentCommand)   
    
    @PUT
    @Path("/{paymentId}")
    public CompletionStage<PaymentResponse<String>> updatePayment(@PathParam("paymentId") String paymentId,
                                                                  UpdatePaymentCommand updatePaymentCommand)
    @DELETE
    @Path("/{paymentId}")
    public CompletionStage<PaymentResponse<String>> deletePayment(@PathParam("paymentId") String paymentId)                                                                        
}

The request body for Create and Update Payment it has this json format

{
  "amount": "amount",
  "currency": "currency",
  "paymentId": "paymentId",
  "debtorParty": {
    "accountName": "accountName",
    "accountNumber": "accountNumber",
    "accountType": 0.0,
    "address": "address",
    "bankId": "bankId",
    "name": "name"
  },
  "sponsorParty": {
    "accountNumber": "accountName",
    "bankId": "bankId",
    "bankIdCode": "bankCode"
  },
  "beneficiaryParty": {
    "accountName": "accountName",
    "accountNumber": "accountNumber",
    "accountType": 0.0,
    "address": "address",
    "bankId": "bankId",
    "name": "name"
  },
  "paymentPurpose": "paymentPurpose",
  "paymentType": "paymentType",
  "processingDate": "processingDate",
  "reference": "reference",
  "schemePaymentSubType": "schemePaymentSubType",
  "schemePaymentType": "schemePaymentType"
}

And the json response format for fetch payment has this one.

{
  "id": "id",
  "type": "created",
  "version": 1.0,
  "paymentInfo": {
    "amount": "amount",
    "currency": "currency",
    "paymentId": "paymentId",
    "paymentPurpose": "paymentPurpose",
    "paymentType": "paymentType",
    "processingDate": "processingDate",
    "reference": "reference",
    "schemePaymentSubType": "schemePaymentSubType",
    "schemePaymentType": "schemePaymentType",
    "debtorParty": {
      "accountName": "accountName",
      "accountNumber": "accountNumber",
      "accountType": 0.0,
      "address": "address",
      "bankId": "bankId",
      "name": "name"
    },
    "sponsorParty": {
      "accountNumber": "accountName",
      "bankId": "bankId",
      "bankIdCode": "bankCode"
    },
    "beneficiaryParty": {
      "accountName": "accountName",
      "accountNumber": "accountNumber",
      "accountType": 0.0,
      "address": "address",
      "bankId": "bankId",
      "name": "name"
    }
  }
}

Testing

My image

To go fast you have to go well this quote of Robert C. Martin express perfectly what TDD and BDD is. You should think first in all corner cases of your program, and then implement one by one committing every scenario to have a quick feedback about your program.

In our application I invested around 70% of the time implementing the test framework, the type of testing implemented are described below.

  • Unit: I used JUnit5 together with Mockito to Mock external resources of your class.
  • Integration: I used Quarkus server, which include a very nice Test framework to do BDD and run the application and test all layers of your application. Just to be clear, the IT test are just a proof that our Unit test are well designed and the Mock behaves as I expect. None IT test should ever fail. And if it does, you have to reproduce it in Unit test.
  • Performance: Performance/Stress test are meant to be used to detect possible concurrency issue in your application, and also to have a control of the latency of your endpoints. Quarkus seems like it does not work with Gatling so I just use @RepeatedTest of JUnit5. So, no control of latency of endpoints available.
  • Volume: Volume test are meant to be used to have a load of traffic for a long period of time, to detect some possible memory leaks in your application that it might provoke that your application get out of memory and die. Quarkus seems like it does not work with Gatling so I just use @RepeatedTest of JUnit5.

Technology Stack

As Http Server I used Quarkus, a new Serverless framework implemented by RedHat team, as a new Power Vertx framework. Indeed a good choice to create Reactive systems.

For the API I used JAX-RS standard.

In order to have a reactive system, functional programing it's a powerful tool. Although Java is functional since Java 8 it's not Scala. Vavr is good library for functional programing that makes you feel like you're in Scala realm again.

To make transformation of models between layer doing DDD, I used Orika.

Finally as Connector and Database I chose Cassandra since it's a good choice for Event sourcing.

  • Application: Quarkus, JAX-RS, Vavr, Mockito

  • Domain: Vavr, Orika

  • Infrastructure: Orika, Vavr, Orika, Cassandra, Mockito.

Use

To run the Unit and Integration test, just go into the root program and run the command:

mvn clean install

Once that you have your project tested, you just need to run the application. Go to the application module and run the command:

./mvnw compile quarkus:dev

Then you will have to run the Cassandra embedded that the project provide.

CassandraConnector.start()

Health check

PaymentAPI provide a health check endpoint to know the state of the service and backends.

http://localhost:8080/health
Response
{
    "outcome": "UP",
    "checks": [
        {
            "name": "Payment API health check",
            "state": "UP",
            "data": {
                "Cassandra database": "running"
            }
        }
    ]
}

paymentapi's People

Contributors

politrons avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.