Java Micronaut REST Server with CockroachDB

đź•“ 45 minutes

What you’ll learn#

How to setup your application for :

  • connecting to CockroachDB database,
  • getting data from REST API,
  • providing data to REST API.

In this tutorial, we will create a simple java component with Java Micronaut scaffolder with a connection to CockroachDB database storage. We want to expose a single REST endpoint for getting the basic client data information, creating a microservice CRUD layer above the DB storage.

clientDataDB

Project source#

This example project can be cloned from: http://gitlab.factory.codenow-control.codenow.com/public-docs/java-micronaut-demo/rest-server-with-cockroachdb.git

Prerequisites#

Steps#

Open your IDE, import the created component and start coding:

  • First, add maven dependency to your pom.xml

    <dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.2.16</version>
    </dependency>
    <dependency>
    <groupId>javax.persistence</groupId>
    <artifactId>javax.persistence-api</artifactId>
    <version>2.2</version>
    </dependency>
    <dependency>
    <groupId>io.micronaut.data</groupId>
    <artifactId>micronaut-data-jdbc</artifactId>
    <version>1.1.3</version>
    </dependency>
    <dependency>
    <groupId>io.micronaut.configuration</groupId>
    <artifactId>micronaut-jdbc-hikari</artifactId>
    <scope>runtime</scope>
    </dependency>
    <dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
    </dependency>
  • Then define the jpa entity Client. This simple table will store basic client data:

    • Generate getters and setters with your IDE
    package io.codenow.client.data.db.service.repository.entity;
    import java.time.LocalDate;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    @Entity
    public class Client {
    @Id
    @GeneratedValue
    private Long id;
    private String username;
    private String firstname;
    private String surname;
    private LocalDate birthdate;
    }
  • Create a new ClientRepository, which is a basic CRUD interface for micronaut data DB access:

    package io.codenow.client.data.db.service.repository;
    import io.codenow.client.data.db.service.repository.entity.Client;
    import io.micronaut.data.jdbc.annotation.JdbcRepository;
    import io.micronaut.data.repository.CrudRepository;
    import io.reactivex.Maybe;
    @JdbcRepository
    public interface ClientRepository extends CrudRepository<Client, Long> {
    Maybe<Client> findByUsername(String username);
    }
  • Create a new controller and put all the parts together

    package io.codenow.client.data.db.service.controller;
    import javax.inject.Inject;
    import javax.validation.constraints.NotNull;
    import org.example.service.repository.ClientRepository;
    import org.example.service.model.Client;
    import io.micronaut.http.annotation.Consumes;
    import io.micronaut.http.annotation.Controller;
    import io.micronaut.http.annotation.Get;
    import io.micronaut.http.annotation.PathVariable;
    import io.micronaut.http.annotation.Produces;
    import io.micronaut.validation.Validated;
    import io.reactivex.Flowable;
    import io.reactivex.Maybe;
    /**
    * ClientDataController.
    */
    @Validated
    @Controller("/clients")
    @Produces
    @Consumes
    public class ClientDataController {
    private final ClientRepository clientRepository;
    @Inject
    public ClientDataController(ClientRepository clientRepository) {
    this.clientRepository = clientRepository;
    }
    @Get("/")
    public Flowable<Client> listClients() {
    return Flowable.fromIterable(clientRepository.findAll());
    }
    @Get("/{username}")
    public Maybe<Client> getClient(@PathVariable @NotNull String username) {
    return clientRepository.findByUsername(username);
    }
    }
  • Next prepare the database configuration:

  • Now change the configuration in config/application.yaml:

  • Fill {db user} and {db password} according to your configuration

  • Make sure you follow yaml syntax (especially whitespaces)

    datasources:
    default:
    url: jdbc:postgresql://localhost:5432/{db_name}
    driverClassName: org.postgresql.Driver
    username: {db user}
    password: {db password}
    dialect: POSTGRES
  • Do not forget to change the swagger.yaml. Add these lines into your src/main/resources/META-INF/swagger/swagger.yaml :

    paths:
    /clients:
    get:
    tags:
    - data
    summary: Get all clients
    description: Return all clients from the database
    operationId: listClients
    responses:
    '200':
    description: response
    content:
    application/json:
    schema:
    $ref: '#/components/schemas/Clients'
    '400':
    description: Bad request (e.g. validation)
    content:
    application/json:
    schema:
    $ref: '#/components/schemas/ErrorMessage'
    '500':
    description: Server error
    content:
    application/json:
    schema:
    $ref: '#/components/schemas/ErrorMessage'
    /clients/{username}:
    get:
    tags:
    - data
    summary: Client by username
    description: Return client by username
    operationId: getClient
    parameters:
    - name: username
    schema:
    type: string
    in: path
    description: username
    responses:
    '200':
    description: response
    content:
    application/json:
    schema:
    $ref: '#/components/schemas/Client'
    '400':
    description: Bad request (e.g. validation)
    content:
    application/json:
    schema:
    $ref: '#/components/schemas/ErrorMessage'
    '500':
    description: Server error
    content:
    application/json:
    schema:
    $ref: '#/components/schemas/ErrorMessage'
    components:
    schemas:
    ErrorMessage:
    type: object
    properties:
    errorId:
    type: string
    traceId:
    type: string
    errorDetail:
    type: string
    errorParams:
    type: array
    items:
    $ref: '#/components/schemas/ErrorParam'
    requestMapping:
    type: array
    items:
    type: string
    ErrorParam:
    type: object
    required:
    - key
    - value
    properties:
    key:
    type: string
    value:
    type: string
    Clients:
    type: array
    items:
    $ref: '#/components/schemas/Client'
    Client:
    required:
    - id
    - username
    - firstname
    - surname
    - birthdate
    type: object
  • Try to build and run the application in your IDE. After startup, you should be able to access your new controller’s swagger: http://localhost:8080/swagger/index.html

clientDataDBSwagger

Deploy to CodeNOW#

If your code works in the local development, you are ready to push your changes to GIT and try to build and deploy your new component version to the CodeNOW environment.

What’s next?#

See the tutorial Micronaut REST server with Redis and Kafka.