. . .

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/81682890/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.

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.

Note that the current version of spring-microservice-base contains dependencies as well as dependency management. Future versions of spring-microservice-base will correct this behavior and only provide dependency management.

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 auto-configuration 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-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/81682890/advanced-spring-boot-with-consul.png

Another useful principle when working with services is load balancing. Imagine that you start two instances of the same services in order to scale your application - how can you make sure that the workload is efficiently distributed between both instances?
Load balancing will solve this for you. We use the client side load balancer Ribbon, with a default implementation from Spring Cloud. By default, Feign also supports load balancing using Ribbon.

Each Ribbon client can be configured to include a list of service instances that could be retrieved from the discovery client. The Ribbon implementation includes some rules which are applied in order to distribute the workload over multiple instances. For more information on load balancing with Ribbon, 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.