. . .

Development Basics

This page is an introduction to the basics of developing services with ApiOmat. It consists of a simple introduction to the development workflow and a brief overview of the relevant service assets. Links to further topics will help you dive deeper into service development.

Contents :


Workflow

In a nutshell, you can create a new service in the following steps:

  1. Model your service via the ApiOmat Dashboard.

  2. Download your service and retrieve project assets.

  3. Develop your service and deploy the newly created sources to a repository.

  4. Start your service.

  5. Retrieve existing logic & code-first approach.

These steps are described in detail in the Development cycle guide.

About the service assets

As the list above guides you to a working service, there are some further technical aspects you should know about.

Package structure

A generated service will have the following architecture (example service "MyService"):

images/download/thumbnails/95834661/Screen-Shot-2020-02-21-at-10.56.25.png

The generated base package is "com.apiomat.microservice.{serviceName}", it contains:

  • The Spring Boot application main class, named after the service with "Application" appended (e.g. MyServiceApplication.java). It contains annotations to start the Spring Boot application and enable Feign:

    MyServiceApplication.java
    @SpringBootApplication
    @EnableFeignClients
    public class MyServiceApplication extends SpringBootServletInitializer
  • The main Spring-related configuration, "{serviceName}Configuration.java", that contains the configuration and initialization of all the beans required for your service logic.

  • The "config" package which contains:

    • A SwaggerDocumentationConfig.java class, which contains specific configuration to generate an OpenAPI specification. This is done for all REST endpoints annotated with the @ApiXXX swagger annotations from the springfox-swagger2 library. The OpenAPI specification is available by default at http://localhost:8090/{lowerCaseServiceName}/v2/api-docs and is accessed by the Explorer service to display the API documentation UI.

    • A "{serviceName}ConfigDefinition.java" class that contains the specific ApiOmat application configuration definition of your service. See Configuration Parameters.

    • A "{serviceName}CorsConfiguration.java" class that contains the CORS configuration for your service. See CORS configuration.

  • The "controller" package which contains the following for each class:

    • An API interface "I{className}Api.java" that describes API endpoints.

    • An API implementation "{className}ApiController.java" to call internal service logic.

  • The "model" package which contains the following for each class:

    • A POJO "{className}.java" that holds the class's attributes.

    • An enum list of reference attributes "{className}RefAttributes.java", used when querying the data model's reference endpoints.

    • An enum list of static data attributes name "{className}StaticDataAttributes.java", used when querying the data model's static data endpoints.

  • The "service" package which contains the following for each class :

    • A Feign client "{className}ApiClient.java" that calls the corresponding Yambas endpoints when a data model's CRUD operations are executed.

    • An API abstract service "Abstract{className}ApiService.java" that provides default implementations of service methods.

    • An API service implementation "{className}ApiServiceImpl.java" that extends the abstract implementation, where the developer can make their own implementations of service methods by overriding the default abstract provided ones.

The resources folder contains:

  • The "application.yml" Spring configuration file, with specific values described below in the Service Configuration - Spring related configuration section.

  • A "logback.xml" logging configuration file, see Logging and Debugging for details on this

  • You can place your own logo for the service here. For details see section Add logo for marketplace


This was only a quick overview of the classes that are generated within your Spring Boot service project. Please go to the Service architecture guide for more details on the global logic and architecture.

Versioning

ApiOmat 21.03 gives you the possibility to version your service projects independently from the "API" version (the version of your service in Yambas). That way, your service project may have a version that reflects the version of your project or business logic, while the API version stays same. This means, that you may have a project/artifact version "1.1.15", while your "API" or service version that is shown in the dashboard and attached to the is still "1.1.0"
To achieve that, there's a new property in the application.yml with the key apiomat.service.version. By default, this property has a placeholder as value. The placeholder comes from the pom.xml's property section with the key apiomat.service.version which is replaced during the maven build. Therefore, we recommend changing the property within the pom.xml, as the placeholder may be contained in the application.yml several times. Services that are generated with an ApiOmat 21.03 version automatically contain this structure.

During the artifact processing, Yambas scans at first for the property in the application.yml. If it isn't present or contains the placeholder, it will try to find the respective value in the properties section of the pom.xml. If the property doesn't exist as well, it will fall back to the version that is specified in the pom.xml. This value is used as service version in Yambas (and it's respective API endpoints).

The "used service" dependency libraries will use the service version and not the project version as well, as these libraries contain the clients and models that are bound to the API version. The same applies for the executor endpoints.

Maven dependencies

In this section, we'll list the dependencies that are defined in the pom.xml of your generated service and explain what each of them is for. Links to related documentation will be provided when relevant.

Parent

Each generated service is a child of our spring-microservice-base parent project . It provides the general dependencies and global dependency management used by every ApiOmat service. The goal of this parent project is to manage the versions used in the ApiOmat ecosystem for compliance purposes.

Spring related

Most of the dependencies in your generated service are Spring related. Some of them rely on the auto-configuration behavior of Spring Boot, which means that some of these dependencies automatically add features by e.g. auto-registering endpoints or adding beans to your Spring context. Be aware that the policy of Spring Boot is to provide features along with properties to disable them. To read more about Spring Boot auto-configuration, please refer to the Spring Boot documentation .

Name

Description

spring-boot-starter-web

Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container.

spring-boot-starter-tomcat

Provides auto-configuration to embed a Spring Boot application within a Tomcat web server.

spring-boot-starter-actuator

Provides multiple utility features for your application, including an auto-registered health endpoint. See Spring Boot actuator documentation .

spring-cloud-starter-consul-discovery

Provides auto-registration to a Consul discovery client via property configuration, along with Spring components to support Consul as the implementation of the abstract Spring Cloud discovery client.

spring-boot-devtools

Provides additional development-time features, such as auto-restart when a file changes. See Spring DevTools documentation .

spring-cloud-starter-openfeign

Provides OpenFeign integrations for Spring Boot apps via auto-configuration and binding to the Spring Environment and other Spring programming model idioms. See Spring Cloud OpenFeign documentation.

feign-form-spring

Implementation to support multipart form data in Feign clients.

spring-cloud-starter-sleuth

Spring Boot support for Sleuth. Required for Zipkin (see below row).

spring-cloud-sleuth-zipkin

Spring Boot support for Zipkin. Provides auto-registration and features related to Zipkin by simply setting the Zipkin properties in your service's application.yml. For more information about Zipkin, see our Zipkin installation documentation .

springfox-swagger2

Provides classes and annotations to generate an Open API specification for your service. See the Introduction to Swagger documentation for details, and the API documentation section of the service tutorial for a concrete example.

spring-boot-starter-test

Starter for testing Spring Boot applications with libraries such as JUnit, Hamcrest and Mockito.

ApiOmat libraries

Some dependencies are custom artifacts we provide to make it easier to integrate services within the ApiOmat ecosystem:

Name

Description

brewer-base

Contains the basic POJOs and interfaces used in all ApiOmat microservices, and provides the global logic applied to your microservice's service classes. This library is the service equivalent of the nativemodule-base library, which you may be familiar with if you have worked with native modules. Most of the features provided by the brewer-base library are described in the service architecture documentation .

apiomat-service-config-starter

Provides features to enhance the usage of ApiOmat configuration parameters in Spring Boot microservices. Features provided by this library, and the apiomat-service-config library, are described in the Configuration Parameters documentation .

Others

Name

Description

logback-gelf

Provides a log appender implementation for Graylog. The appender is defined in your logback.xml file. More information about Graylog can be found in our Graylog documentation.

Maven plugins

The pom.xml of your generated service will have the following Maven plugins:

Name

Description

spring-boot-maven-plugin

Provides several Maven goals to work with a Spring Boot application. See usage documentation.

dockerfile-maven-plugin

Provides features to create a docker image of your service. See the plugin's GitHub page.

license-maven-plugin

Generate license information about used dependencies.

maven-war-plugin

Plugin to package your service as a Web Application Resource (WAR).

maven-source-plugin

Plugin to package the sources of your application. The sources are deployed to Innkeeper so files can be merged. Also used in code-first approach to update your service's metadata.

brewer-maven-plugin

Our custom maven plugin to support service development. See the plugin's public documentation.

Application main class

The entry point of your service is its application class {ServiceName}Application.java. It contains a main method and is annotated with @SpringBootApplication which is explained in more detail in the Spring Boot documentation .

An important feature to be aware of when using @SpringBootAnnotation is the @ComponentScan annotation. By default, a bean will be created and added to your service's application context for all classes annotated with @Component (or its child annotations such as @Service or @Controller) from the package where your @SpringBootAnnotation annotated class is located, and from all sub package s.

With the default behaviour of @ComponentScan , putting a class annotated with @SpringBootApplication in a top level package may result in a lot of unwanted components being added to your application context. For example, an annotation on the "com" package level will add all components from "com.*" to your application context, including dependency classes that are annotated with @Component and located in the "com.*" package of their dependency, which is definitely not wanted behavior. Try to keep your package names as specific to your application as possible.

Service Configuration

Configuration via properties is a key part of Spring. Typically, you can define your application configuration in a YAML or properties file (e.g. in your generated service, there will be an application.yml file) .

Spring related configuration

Configuration can be used to enable or disable features in Spring Boot by setting specific property values . For an in-depth guide to configuration in Spring, check out the Spring Boot documentation .
Here is the commented configuration that will be generated for your service
:

application.yml
# Your service's context-path and static port
server:
  servlet:
        context-path: /{YOUR_SERVICE_NAME_LOWERCASE}/v/@project.version@
  port: 8090


spring:
  # Application name and version are placeholders, the values are taken from your service's pom.xml
  application:
        name: '@name@'
        version: '@project.version@'
  jmx:
      default-domain: '@name@'
  cloud:
      # Configuration for Consul
      consul:
		  # The host and port of your Consul installation
          host: localhost
          port: 8500
		  # Service discovery properties
          discovery:
			  # Specific meta data of your service instance in Consul
			  # Services must provide a context path and version so they can be queried through the Dispatcher gateway
			  # "registerAsYambasContextPath" is also used in the Gateway context to proxy requests over YAMBAS to your service
              tags: contextPath=${server.servlet.context-path}, version='@project.version@', registerAsYambasContextPath
              enabled: true
			  # Path used by Consul to assert your service's healthiness, the Spring Actuator endpoint is used there
              health-check-path: ${server.servlet.context-path}/actuator/health
			  health-check-critical-timeout

  # Object mapping configuration for timestamps
  jackson:
      deserialization:
          read-date-timestamps-as-nanoseconds: false
      serialization:
          write-date-timestamps-as-nanoseconds: false
          write-dates-as-timestamps: true

  # If you want to enable zipkin tracing, you have to add at least the commented-out values and set sleuth and zipkin to enabled
  # A probability of 1.0 will trace ALL requests.
  # Note that this may consume more memory, so you may have to increase the Xmx value of the JVM
  zipkin:
    enabled: false
  #  baseUrl: localhost:9411
  sleuth:
    enabled: false
  #  sampler:
  #    probability: 1.0

# Path where your service will expose the OpenAPI specification generated by SpringFox annotations on your API methods
# This is the default one, used by the API Docs service Explorer
springfox:
  documentation:
    swagger:
      v2:
        path: /v2/api-docs


# Specific configuration for Feign client communicating with YAMBAS
feign:
  client:
    config:
      YAMBAS:
		# Set the connection and read timeout to 5 seconds
        connectTimeout: 5000
        readTimeout: 5000
		# A specific request interceptor implementation, for Feign clients communicating with YAMBAS, that copies the incoming request's headers to the outgoing request
        requestInterceptors:
          - com.apiomat.service.base.feign.RequestHeaderRequestInterceptor


# Service ID, allowed version(s) and path prefix of YAMBAS, used to configure Feign clients
{YOUR_SERVICE_NAME_LOWERCASE}:
  coreservice:
    name: YAMBAS
	version: "[3.3,)"
    pathprefix: /yambas/rest
# CORS configuration for your service:
# You can set allowlists of origins (URIs) and HTTP methods for CORS requests.
# E.g.:
# cors-configuration:
#   allowedOrigins:
#     - "http://127.0.0.1:9081"
#     - "https://other.secure.domain"
#   allowedMethods:
#     - GET
#     - HEAD
# For both properties:
# - "*" allows all origins/methods as long as they are valid URIs/HTTP methods, respectively.
# - "none" or an empty value allows NO CORS requests at all.
# - The default is "*".
# cors-configuration:
#   allowedOrigins:
#   allowedMethods:

ApiOmat application configuration

It is possible to define ApiOmat application- and system-related configurations for your service, where values can be dynamically accessed and changed within your service logic at runtime. To dive deeper into this topic, please refer to Configuration Parameters .

Service discovery, health checks and load balancing

In a Cloud context, services need to communicate with each other, so they need to be able to find each other. The principle of service discovery is that a single discovery client holds information about all services in the cloud. When a service starts up, it registers itself to the discovery client, with some additional configuration if necessary. When a service wants to communicate with another service, it can retrieve the address from the discovery client.

For service discovery, we are using the Consul discovery client from HashiCorp. An additional useful feature of Consul is health checking: Each service registers itself with an endpoint for health checks, which is queried by Consul to assert the service's healthiness. Please refer to Service health checks for further information.
The picture below describes our discovery use case with the different features provided by Consul:

images/download/attachments/95834661/advanced-spring-boot-with-consul.png

Another useful principle when working with services is load balancing. Imagine that you start two or more instances of the same services in order to scale your application - how can you make sure that the workload is efficiently distributed between all instances?
Load balancing will solve this for you. We use the default implementation from Spring Cloud, which is also supported by Feign.

The Spring Cloud load balancer includes several implementations to distribute the workload over multiple instances. For more information, you can have a look at the Spring Cloud documentation .

Logging and Debugging

To learn about the logging and debugging features, please refer to Service Logging and Debugging .

Data model classes

When you generate your service, a corresponding Java class will be created for each of your service's classes. This class will contain any attributes that you defined in the Dashboard. As mentioned above, these data model classes will be placed in the package com.apiomat.microservice.<servicename>.model.

Attribute Annotations

There are several attribute annotations for various attribute-specific information. They are applied automatically during service generation, and can be added manually when creating new attributes by editing the source code.

EmbeddedObject

References can be annotated with EmbeddedObject to mark them as embedded objects .
For example:

@com.apiomat.service.base.model.EmbeddedObject
private Address address = null;


Mandatory

Attributes can be annotated with Mandatory to mark them as mandatory attributes.
For example:

@com.apiomat.service.base.model.Mandatory
private String mandatoryStr = null;

Next steps

  • If you are now familiar with the different concepts of Service development in ApiOmat, but you want to practice before creating your own, please follow our Introduction tutorial .

  • You now feel ready to create your own service? Please have a look at the services we provide in the ApiOmat cloud, as they may be helpful for your future development.