Skip to content

Microservices

Within our system, five main types of operations occur:

  • Getting data by ID: This operation involves retrieving specific data entries from the microservice based on their unique identifier (ID). This allows for the retrieval of individual records as needed.

  • Getting all data: This operation involves retrieving all available data from the microservice.

  • Deletion: Deleting existing records. This typically involves interacting with the microservice to remove specific records.

  • Update of existing entries: This refers to making changes by sending data to the microservice for processing and storage.

  • Creation: This involves creating new records by sending data to the microservice for processing and storage.

Basics

Live Sample · GitHub

When creating entities for microservices, the process is largely similar to creating entities for database access, with a few notable exceptions.

1) Instead of creating an entity, we establish a mapping entity through which data will be sent to the microservice.

2) Instead of using FieldMetaBuilder, we utilize AnySourceFieldMetaBuilder._

3) Instead of using VersionAwareResponseService, we utilize AnySourceVersionAwareResponseService.

4) Create extends AbstractAnySourceBaseDAO implements AnySourceBaseDAO service

Example
  • Step1.1 Create mapping entity through which data will be sent to the microservice
    @Getter
    @Setter
    @NoArgsConstructor
    public class MyEntityOutServiceDTO implements Serializable {
    
        private String id;
        private String customField;
        private String customField;
    }
    
  • Step1.2 Create DAO extends AbstractAnySourceBaseDAO implements AnySourceBaseDAO Override methods:

    @Service
    @RequiredArgsConstructor
    public class MyEntityDao extends AbstractAnySourceBaseDAO<MyEntityOutServiceDTO> implements AnySourceBaseDAO<MyEntityOutServiceDTO> {
    
        private final IntegrationConfiguration integrationConfig;
    
        private final RestTemplate restTemplate;
    
        @Override
        public String getId(final MyEntityOutServiceDTO entity) {
            return entity.getId();
        }
    
        @Override
        public void setId(final String id, final MyEntityOutServiceDTO entity) {
            entity.setId(id);
        }
    
    
        // --8<-- [start:getByIdIgnoringFirstLevelCache]
        @Override
        public MyEntityOutServiceDTO getByIdIgnoringFirstLevelCache(final BusinessComponent bc) {
            return restTemplate.exchange(
                    fromUriString(integrationConfig.getExistingMicroservicesDataServerUrl() + "/{id}").build()
                            .expand(bc.getIdAsLong()).normalize().encode()
                            .toUriString(),
                    GET, null, MyEntityOutServiceDTO.class
            ).getBody();
        }
    
        // --8<-- [end:getByIdIgnoringFirstLevelCache]
    
        // --8<-- [start:getList]
        @Override
        public Page<MyEntityOutServiceDTO> getList(final BusinessComponent bc, final QueryParameters queryParameters) {
    
            //Page size
            String page = bc.getParameters().getParameter("_page");
    
            //Limit
            String limit = bc.getParameters().getParameter("_limit");
    
            //Filter
            List<String> filterCustomField = getFilterFieldName(queryParameters, "customField", "contains");
            Optional<String> filter = filterCustomField.isEmpty() ? Optional.empty() : Optional.of(filterCustomField.get(0));
    
            //Sorting
            List<String> sortCustomField = getSortFieldName(queryParameters, "customField");
            Optional<String> sort = sortCustomField.isEmpty() ? Optional.empty() : Optional.of(sortCustomField.get(0));
    
            String urlTemplate = UriComponentsBuilder.fromHttpUrl(integrationConfig.getExistingMicroservicesDataServerUrl())
                    .queryParam("number", page)
                    .queryParam("size", limit)
                    .queryParamIfPresent("filterCustomField", filter)
                    .queryParamIfPresent("sortCustomField", sort)
                    .encode()
                    .toUriString();
    
            ResponseEntity<RestResponsePage<MyEntityOutServiceDTO>> responseEntity = restTemplate.exchange(
                    urlTemplate,
                    HttpMethod.GET,
                    null,
                    new ParameterizedTypeReference<>() {
                    },
                    filter
            );
    
    
            return responseEntity.getBody();
        }
    
    
        private List<String> getSortFieldName(QueryParameters queryParameters, String fieldName) {
            return queryParameters.getParameters().entrySet().stream()
                    .filter(f -> f.getKey().contains("_sort"))
                    .filter(f -> f.getValue().contains(fieldName))
                    .map(m -> {
                                String[] splitOperation = m.getKey().split("\\.");
                                return splitOperation[splitOperation.length - 1];
                            }
                    ).toList();
        }
    
        private List<String> getFilterFieldName(QueryParameters queryParameters, String fieldName, String searchSpec) {
            return queryParameters.getParameters().entrySet().stream()
                    .filter(f -> f.getKey().contains(fieldName + "." + searchSpec))
                    .map(Map.Entry::getValue)
                    .toList();
        }
    
        // --8<-- [end:getList]
    
        @Override
        // --8<-- [start:delete]
        public void delete(BusinessComponent bc) {
            restTemplate.exchange(
                    fromUriString(integrationConfig.getExistingMicroservicesDataServerUrl() + "/{id}").build().expand(bc.getIdAsLong()).normalize().encode()
                            .toUriString(),
                    DELETE, null, Void.class
            );
        }
        // --8<-- [end:delete]
    
    
        @Override
        // --8<-- [start:create]
        public MyEntityOutServiceDTO create(BusinessComponent bc, MyEntityOutServiceDTO entity) {
            entity.setId(null);
            return restTemplate.exchange(
                    fromUriString(integrationConfig.getExistingMicroservicesDataServerUrl()).build().normalize().encode().toUriString(),
                    POST, new HttpEntity<>(entity), MyEntityOutServiceDTO.class
            ).getBody();
        }
        // --8<-- [end:create]
    
        @Override
        // --8<-- [start:update]
        public MyEntityOutServiceDTO update(BusinessComponent bc, MyEntityOutServiceDTO entity) {
            return restTemplate.exchange(
                    fromUriString(integrationConfig.getExistingMicroservicesDataServerUrl()).build().normalize().encode().toUriString(),
                    PUT, new HttpEntity<>(entity), MyEntityOutServiceDTO.class
            ).getBody();
        }
        // --8<-- [end:update]
    }
    
  • Step1.3 Create DTO extends DataResponseDTO Creating fields in DTO with the necessary properties, such as, for example,filtering is described in the article field types

    @Getter
    @Setter
    @NoArgsConstructor
    public class MyExampleDTO extends DataResponseDTO {
    
        @SearchParameter(name = "customField", provider = StringValueProvider.class)
        private String customField;
    
        public MyExampleDTO(MyEntityOutServiceDTO entity) {
            this.id = entity.getId();
            this.customField = entity.getCustomField();
        }
    }
    
  • Step1.4 Create MetaBuilder extends AnySourceFieldMetaBuilder

    see more Meta builder

    @Service
    public class MyExampleMeta extends AnySourceFieldMetaBuilder<MyExampleDTO> {
    // --8<-- [start:buildRowDependentMeta]
        @Override
        public void buildRowDependentMeta(RowDependentFieldsMeta<MyExampleDTO> fields, BcDescription bc,
                                          String id, String parentId) {
            fields.setEnabled(MyExampleDTO_.customField);
        }
       // --8<-- [end:buildRowDependentMeta]
    
       // --8<-- [start:buildIndependentMeta]
      @Override
        public void buildIndependentMeta(FieldsMeta<MyExampleDTO> fields, BcDescription bcDescription,
                                         String parentId) {
            fields.enableFilter(MyExampleDTO_.customField);
          fields.enableSort(MyExampleDTO_.customField);
        }
       // --8<-- [end:buildIndependentMeta]
    }
    
  • Step1.5 Create Service extends AnySourceVersionAwareResponseService

    @Service
    public class MyExampleService extends AnySourceVersionAwareResponseService<MyExampleDTO, MyEntityOutServiceDTO> {
    
        public MyExampleService() {
            super(MyExampleDTO.class, MyEntityOutServiceDTO.class, MyExampleMeta.class, MyEntityDao.class);
        }
    
        @Override
        protected CreateResult<MyExampleDTO> doCreateEntity(MyEntityOutServiceDTO entity, BusinessComponent bc) {
    
            return new CreateResult<>(entityToDto(bc, entity));
        }
    
        @Override
        protected ActionResultDTO<MyExampleDTO> doUpdateEntity(MyEntityOutServiceDTO entity, MyExampleDTO data, BusinessComponent bc) {
            if (data.isFieldChanged(MyExampleDTO_.customField)) {
                entity.setCustomField(data.getCustomField());
            }
            return new ActionResultDTO<>(entityToDto(bc, entity));
        }
    
         // --8<-- [start:getActions]
        @Override
        public Actions<MyExampleDTO> getActions() {
            return Actions.<MyExampleDTO>builder()
                    .create(crt -> crt.text("Add"))
                    .addGroup(
                            "actions",
                            "Actions",
                            0,
                            Actions.<MyExampleDTO>builder()
                                    .action(act -> act
                                            .action("delete", "delete")
                                    )
                                    .action(act -> act
                                            .action("save", "save")
                                    )
                                    .build()).
                    build();
        }
    
    }
    
  • Step1.6 Create PlatformController implements EnumBcIdentifier

    @Getter
    public enum PlatformMyExampleController implements EnumBcIdentifier {
    
    
        myExampleBc(MyExampleService.class);
    
    
    
        public static final EnumBcIdentifier.Holder<PlatformMyExampleController> Holder = new Holder<>(
                PlatformMyExampleController.class);
    
        private final BcDescription bcDescription;
    
        PlatformMyExampleController(String parentName, Class<?> serviceClass, boolean refresh) {
            this.bcDescription = buildDescription(parentName, serviceClass, refresh);
        }
    
        PlatformMyExampleController(Class<?> serviceClass) {
            this((String) null, serviceClass, false);
        }
    
        @Component
        public static class BcSupplier extends AbstractEnumBcSupplier<PlatformMyExampleController> {
    
            public BcSupplier() {
                super(PlatformMyExampleController.Holder);
            }
    
        }
    
    }
    

Methods

Getting data by ID (getByIdIgnoringFirstLevelCache)

Tips

In this example, we're addressing the scenario where the service obtaining data only by ID. If your service relies solely on natural keys for data retrieval, you may find the following article helpful.

Example

Step1 Method getByIdIgnoringFirstLevelCache takes a BusinessComponent as input.

When calling the service, it's essential to provide the Id record as a parameter for which data will be returned.

Long Id  = bc.getIdAsLong().

Example of fetching data using REST:

    @Override
    public MyEntityOutServiceDTO getByIdIgnoringFirstLevelCache(final BusinessComponent bc) {
        return restTemplate.exchange(
                fromUriString(integrationConfig.getExistingMicroservicesDataServerUrl() + "/{id}").build()
                        .expand(bc.getIdAsLong()).normalize().encode()
                        .toUriString(),
                GET, null, MyEntityOutServiceDTO.class
        ).getBody();
    }

Getting data all (getList)

This method incorporates additional peculiaritys such as filtering, sorting, record limits, and page numbers.

  • Page size: This parameter refers to the number of items or records displayed on a single page of a user interface or returned in a single response from an API. It's used in pagination systems to control how much data is fetched or displayed at once.

  • Limit: This parameter sets a maximum limit on the number of items or records that can be returned or processed by the service. It's a way to prevent overloading the system with too much data at once.

  • Filter: This parameter allows users to specify criteria for filtering the data they want to retrieve or process. Filters could be based on various attributes or properties of the data, allowing users to narrow down their results to only the items that meet specific conditions.

  • Sorting: This parameter would involve specifying the order in which the results are presented. Might want to sort data based on certain attributes, such as alphabetical order, numerical order, date, etc. Sorting can typically be done in ascending or descending order.

Combining these parameters allows users to control and customize the behavior of the service according to their needs, enabling efficient data retrieval and processing.

Example

Method getList takes a BusinessComponent as input.

Step1 Page size.

String page = bc.getParameters().getParameter("_page");

Step2 Limit.

String limit = bc.getParameters().getParameter("_limit");

Step3 Sorting.

If the application lacks a sorting feature, it implies that the parameter associated with sorting would be absent.

queryParameters.getParameters().entrySet().stream().filter(f->f.getKey().contains("sort")).toList();

In the map key, receive the sorting direction: 'desc' for descending or 'asc' for ascending

For example, map key = _sort.0.desc

In the map value, obtain the name of the filtered field specified in to corresponding field "key" to corresponding file widget.json

For example, map value = customField

Step4 Filter.

If the application lacks a filtration feature, it implies that the parameter associated with filtration would be absent.

This example demonstrates how to select filtering conditions for a field with the String type. For comprehensive information on all fields available for filtering, please refer to the article

queryParameters.getParameters().entrySet().stream().filter(f->f.getKey().contains("contains")).toList();

In the map key, receive the filtration type. Can observe the relationship between standard filtering and standard field types here .

For example, map key = customField.contains

In the map value, obtain the filtering criteria for selecting specific data.

For example, map value = Test data

    @Override
    public Page<MyEntityOutServiceDTO> getList(final BusinessComponent bc, final QueryParameters queryParameters) {

        //Page size
        String page = bc.getParameters().getParameter("_page");

        //Limit
        String limit = bc.getParameters().getParameter("_limit");

        //Filter
        List<String> filterCustomField = getFilterFieldName(queryParameters, "customField", "contains");
        Optional<String> filter = filterCustomField.isEmpty() ? Optional.empty() : Optional.of(filterCustomField.get(0));

        //Sorting
        List<String> sortCustomField = getSortFieldName(queryParameters, "customField");
        Optional<String> sort = sortCustomField.isEmpty() ? Optional.empty() : Optional.of(sortCustomField.get(0));

        String urlTemplate = UriComponentsBuilder.fromHttpUrl(integrationConfig.getExistingMicroservicesDataServerUrl())
                .queryParam("number", page)
                .queryParam("size", limit)
                .queryParamIfPresent("filterCustomField", filter)
                .queryParamIfPresent("sortCustomField", sort)
                .encode()
                .toUriString();

        ResponseEntity<RestResponsePage<MyEntityOutServiceDTO>> responseEntity = restTemplate.exchange(
                urlTemplate,
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<>() {
                },
                filter
        );


        return responseEntity.getBody();
    }


    private List<String> getSortFieldName(QueryParameters queryParameters, String fieldName) {
        return queryParameters.getParameters().entrySet().stream()
                .filter(f -> f.getKey().contains("_sort"))
                .filter(f -> f.getValue().contains(fieldName))
                .map(m -> {
                            String[] splitOperation = m.getKey().split("\\.");
                            return splitOperation[splitOperation.length - 1];
                        }
                ).toList();
    }

    private List<String> getFilterFieldName(QueryParameters queryParameters, String fieldName, String searchSpec) {
        return queryParameters.getParameters().entrySet().stream()
                .filter(f -> f.getKey().contains(fieldName + "." + searchSpec))
                .map(Map.Entry::getValue)
                .toList();
    }

Delete

Tips

In this example, we're addressing the scenario where the service obtaining data only by ID. If your service relies solely on natural keys for data retrieval, you may find the following article helpful.

Example

Step1 Method delete takes a BusinessComponent as input.

When calling the service, it's essential to provide the Id record as a parameter for which data will be returned.

Long Id  = bc.getIdAsLong().

Example of fetching data using REST:

    public void delete(BusinessComponent bc) {
        restTemplate.exchange(
                fromUriString(integrationConfig.getExistingMicroservicesDataServerUrl() + "/{id}").build().expand(bc.getIdAsLong()).normalize().encode()
                        .toUriString(),
                DELETE, null, Void.class
        );
    }

Update

Tips

In this example, we're addressing the scenario where the service obtaining data only by ID. If your service relies solely on natural keys for data retrieval, you may find the following article helpful.

Example

Step1 Method update takes a BusinessComponent as input.

When calling the service, it's essential to provide theId record as a parameter for which data will be returned.

Long Id  = bc.getIdAsLong().

Example of fetching data using REST:

    public MyEntityOutServiceDTO update(BusinessComponent bc, MyEntityOutServiceDTO entity) {
        return restTemplate.exchange(
                fromUriString(integrationConfig.getExistingMicroservicesDataServerUrl()).build().normalize().encode().toUriString(),
                PUT, new HttpEntity<>(entity), MyEntityOutServiceDTO.class
        ).getBody();
    }

Create

Tips

In this example, we're addressing the scenario where the service obtaining data only by ID. If your service relies solely on natural keys for data retrieval, you may find the following article helpful.

Example

Step1 Method create takes a BusinessComponent as input.

When calling the service, it's essential to provide the Id record as a parameter for which data will be returned.

Long Id  = bc.getIdAsLong().

Example of fetching data using REST:

    public MyEntityOutServiceDTO create(BusinessComponent bc, MyEntityOutServiceDTO entity) {
        entity.setId(null);
        return restTemplate.exchange(
                fromUriString(integrationConfig.getExistingMicroservicesDataServerUrl()).build().normalize().encode().toUriString(),
                POST, new HttpEntity<>(entity), MyEntityOutServiceDTO.class
        ).getBody();
    }