KivaKit Microservices – Java Code Geeks


KivaKit Microservices

KivaKit is designed to make coding microservices faster and easier. In this blog post, we’ll take a look at the kivakit-microservice module. As of this date, this module is only available in early access via the SNAPSHOT builds and by build KivaKit. The final version of KivaKit 1.1 will include this add-on and is expected to arrive in late October 2021 or earlier.

What does it do?

The kivakit-microservice mini-framework facilitates the implementation of REST-ful GET, POST and DELETE handlers, and ascend these handlers on specific paths. Most of the typical plumbing for a REST microservice is taken care of, including:

  • Configuring and starting the Jetty web server
  • Management of GET, POST and DELETE requests
  • Serializing JSON objects with Json
  • Error handling with KivaKit Messaging
  • Generate an OpenAPI specification
  • Viewing the OpenAPI specification with Swagger
  • Starting an Apache Wicket web application

Microservices

The DivisionMicroservice the class below is a Microservice which performs the arithmetic division (in the slowest and most expensive way imaginable). The Microservice superclass provides automatic configuration and startup of the Jetty server:

public class DivisionMicroservice extends Microservice
{
    public static void main(final String[] arguments)
    {
        new DivisionMicroservice().run(arguments);
    }

    @Override
    public MicroserviceMetadata metadata()
    {
        return new MicroserviceMetadata()
                .withName("divide-microservice")
                .withDescription("Example microservice for division")
                .withVersion(Version.parse("1.0"));
    }

    @Override
    public void onInitialize()
    {
        // Register components here 
    } 
        
    public DivideRestApplication restApplication()
    {
        return new DivideRestApplication(this);
    }
}

Here the main (String[] arguments) The method creates an instance of DivisionMicroservice and starts its execution with a call to execute (string[]) (the same as for any KivaKit application). The metadata () The method returns information about the service included in the OpenAPI REST specification (mounted on /open-api/swagger.json). The restApplication () the factory method creates a REST application for the microservice, and the method Web application() The factory method optionally creates an Apache Wicket web application to configure the service and display its status. Any initialization of the microservice must take place in the onInitialize () method. It is the best place for register components used throughout the application.

When the execute (string[] arguments) method is called, the Jetty web server is started on the port specified by the Microservice settings object loaded by the -deployment switch. The -Harbor The command line switch can be used to override this value.

When the microservice starts, the following resources are available:

Resource path The description
/ Apache One-Stop Web Application
/ KivaKit microservlet REST application
/assets Static resources
/ docs Swagger OpenAPI Documentation
/ open-api / assets OpenAPI resources (.yaml files)
/open-api/swagger.json OpenAPI specification
/ swagger / webapp Swagger web application
/ swagger / webjar Swagger Design Resources

REST applications

A REST application is created by extending the MicroserviceRestApplication to classify:

public class DivideRestApplication extends MicroserviceRestApplication
{
	public DivideRestApplication(Microservice microservice)
	{
		super(microservice);
	}
	
	@Override
	public void onInitialize()
	{
		mount("divide", DivideRequest.class);
	}
}

Request handlers must be mounted on specific paths inside the onInitialize () method (or an error is reported). If the mount path (in this case “divide”) does not start with a forward slash (“/”), the path “/ api /[major-version].[minor-version]/ “is added automatically at the beginning. So,” divide “becomes” /api/1.0/divide “in the code above, where the version 1.0 comes from the metadata returned by DivideMicroservice. The same way can be used to mount a single request handler for each HTTP method (GET, POST, DELETE). However, trying to mount two handlers for the same HTTP method on the same path will result in an error.

The gsonFactory () the factory method (not shown above) can potentially provide a factory that creates Gson objects. The Gson the factory should extend the class MicroserviceGsonFactory. KivaKit will use this factory when serializing and deserializing JSON objects.

For anyone interested in the gory details, the exact flow of control that occurs when a request is made to a KivaKit microservice is detailed in the Javadoc for MicroserviceRestApplication.

Microservlets

Microservlets handle GET, POST and DELETE requests. They are mounted on paths the same way query handlers are mounted. But unlike a request handler, a microservlet can handle one or all of the HTTP request methods at the same time. Request handlers are more flexible and generally more useful than microservlets, so this information is primarily here for completeness. The key use case (the only one so far) for microservlets is that they are used to implement request handlers. You can see the internal microservlet for this in MicroserviceRestApplication in the method mount (chainpath, class requestType).

Request managers

Query handlers are mounted on a MicroserviceRestApplication with calls to mount (chainpath, class requestType). They come in three flavors, each a subclass of MicroserviceRequest:

  • MicroservletGetRequest
  • MicroservletPostRequest
  • MicroservletDeleteRequest

Below we see a POST request handler, Divide Request, which divides two numbers. The answer is formulated by the nested class Divide Response. An OpenAPI specification is generated using information from the @OpenApi annotations. Finally, the request performs a self-validation by implementing the Validable interface required by MicroservletPostRequest:

@OpenApiIncludeType(description = "Request for divisive action")
public class DivideRequest extends MicroservletPostRequest
{
    @OpenApiIncludeType(description = "Response to a divide request")
    public class DivideResponse extends MicroservletResponse
    {
        @Expose
        @OpenApiIncludeMember(description = "The result of dividing",
                              example = "42")
        int quotient;

        public DivideResponse()
        {
            this.quotient = dividend / divisor;
        }

        public String toString()
        {
            return Integer.toString(quotient);
        }
    }

    @Expose
    @OpenApiIncludeMember(description = "The number to be divided",
                          example = "84")
    private int dividend;

    @Expose
    @OpenApiIncludeMember(description = "The number to divide the dividend by",
                          example = "2")
    private int divisor;

    public DivideRequest(int dividend, int divisor)
    {
        this.dividend = dividend;
        this.divisor = divisor;
    }

    public DivideRequest()
    {
    }

    @Override
    @OpenApiRequestHandler(summary = "Divides two numbers")
    public DivideResponse onPost()
    {
        return listenTo(new DivideResponse());
    }

    @Override
    public Class<DivideResponse> responseType()
    {
        return DivideResponse.class;
    }

    @Override
    public Validator validator(ValidationType type)
    {
        return new BaseValidator()
        {
            @Override
            protected void onValidate()
            {
                problemIf(divisor == 0, "Cannot divide by zero");
            }
        };
    }
}

Note that the nested response class uses the outer class to access the fields in the request. This makes getters and setters useless. When onPost () is called by KivaKit, the response object is created (and any messages it produces are repeated due to the call to To listen()), and the constructor of the Divide Response The object performs the division operation. This makes the onPost () manage a one-liner:

public DivideResponse onPost()
	{
	    return listenTo(new DivideResponse());
	}

Notice how OO design principles have improved encapsulation, eliminated the master key, and increased readability.

Accessing KivaKit microservices in Java

The kivakit-microservice the module includes MicroserviceClient, which provides easy access to KivaKit microservices in Java. The client can be used like this:

public class DivisionClient extends Application
{
    public static void main(String[] arguments)
    {
        new DivisionClient().run(arguments);
    }

    @Override
    protected void onRun()
    {
        var client = listenTo(new MicroservletClient(
            new MicroserviceGsonFactory(), 
            Host.local().https(8086), 
            Version.parse("1.0"));

        var response = client.post("divide", 
            DivideRequest.DivideResponse.class, 
            new DivideRequest(9, 3));

        Message.println(AsciiArt.box("response => $", response));
    }
}

Here we create a MicroservletClient to access the microservice we built above. We tell it to use the service on port 8086 of the local host. Then we publish a Divide Request divide 9 by 3 using the client, and we read the answer. The answer shows that the quotient is 3:

-------------------
|  response => 3  |
-------------------

Path and query parameters

A query manager does not directly access path and query parameters. Instead, they are automatically transformed into JSON objects. For example, a POST to this URL:

http://localhost:8086/api/1.0/divide/dividend/9/divisor/3

does exactly the same as the POST request in the Customer Division code above. The dividend / 9 / divisor / 3 part of the path is transformed into a JSON object like this:

{
    "dividend": 9,
    "divisor": 3
}

The microservlet treats this JSON as if it had been posted. This feature can be useful when publishing “flat” query objects (objects without nesting). Note that when path variables or query parameters are supplied, the request body is ignored.

Open api

The root path “/ docs” on the server provides an OpenAPI specification generated through Swagger:

The annotations available for OpenAPI are minimal, but effective for simple REST projects:

Coded

The code discussed above is a working example in the kivakit-examples deposit. It can be instructive to follow the code in a debugger.

The KivaKit Microservice API is available for early access in the develop branch of the kivakit-microservice module of the kivakit-extensions repository in KivaKit.

<dependency>
    <groupId>com.telenav.kivakit</groupId>
    <artifactId>kivakit-microservice</artifactId>
    <version>${kivakit.version}</version>
</dependency>

Posted on Java Code Geeks with the permission of Jonathan Locke, partner of our JCG program. See the original article here: KivaKit Microservices

The opinions expressed by contributors to Java Code Geeks are their own.



Source link