1. Framework
  2. Why Contract is so important no only inner but also external

Basic

Why contract is so import in internal or external communication?

Basically what ApiHug try to solve is API, which is a specification use to communication between different layers or systems.

In other words, it is a contract:

  1. internal an application, it used to communicate between the backend and front-end
  2. external, between different applications(microservices) or 3rd-party system

ApiHug

  1. ApiHug implements API design strictly according to Swagger standards;
  2. ApiHug use DSL to define the contract supplier, which will leverage the most compile time static check avoid human mistake and readability
  3. For 3rd party system dependencies also use DSL definition
  4. ApiHug test Kola strictly according to the api design proto
  5. ApiHug MCP expose the MCP endpoints

All those build base on ApiHug’s Api design meta language: protobuf

During the compile and runtime you can customize this behaviour easily with hope.common.service.contract.ContractAdapter

ApiHug uses the Service Locator pattern to load your custom ContractAdapter at both runtime and compile time.

What you need to do:

  1. Keep your custom ContractAdapter stateless and provide a default constructor.
  2. Create a file named hope.common.service.contract.ContractAdapter under {APP-MODULE}/src/main/resources/META-INF, and register your ContractAdapter in it:
#PKG-NAME#.infra.contract.MyContractAdapter

it will supply those extension for customized:

functionRemarks
moduleClassNameclass name of this application’s proto module.
contractControl the api context from the given 3rd-party module(microservice api dependencies).
mcpControl the expose of MCP service base on API.

How to use DSL to control your ApiContext in API contracts between different applications or MCP exposures:

  1. Cast the module to your target module using instance of
  2. Use DSL to enable or disable specific services or APIs
  //if module instanceof MyModule myModule: 
  return myModule.service()
          .apiContext()
          .orderService(
              svc -> {
                // Keep all the methods of this service
                svc.keepAll();
                // All the method start with, feel free try other shortcut
                svc.startsWith("add");
                // Pick method one by one
                svc.methods(
                    methods -> {
                      // Include this method
                      methods.PlaceOrder();
                      // Exclude this method, start with `_`
                      methods._DeleteOrder();
                    });
              })
          .build();

Refer

  1. Introducing Spring Cloud Contract
  2. Consumer-Driven Contracts: A Service Evolution Pattern