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

    01 <dependency>
    02 <groupId>org.postgresql</groupId>
    03 <artifactId>postgresql</artifactId>
    04 <version>42.2.16</version>
    05 </dependency>
    06 <dependency>
    07 <groupId>javax.persistence</groupId>
    08 <artifactId>javax.persistence-api</artifactId>
    09 <version>2.2</version>
    10 </dependency>
    11 <dependency>
    12 <groupId>io.micronaut.data</groupId>
    13 <artifactId>micronaut-data-jdbc</artifactId>
    14 <version>1.1.3</version>
    15 </dependency>
    16 <dependency>
    17 <groupId>io.micronaut.configuration</groupId>
    18 <artifactId>micronaut-jdbc-hikari</artifactId>
    19 <scope>runtime</scope>
    20 </dependency>
    21 <dependency>
    22 <groupId>javax.annotation</groupId>
    23 <artifactId>javax.annotation-api</artifactId>
    24 <version>1.3.2</version>
    25 </dependency>
  • Then define the jpa entity Client. This simple table will store basic client data:

    • Generate getters and setters with your IDE
    01 package io.codenow.client.data.db.service.repository.entity;
    02
    03 import java.time.LocalDate;
    04
    05 import javax.persistence.Entity;
    06 import javax.persistence.GeneratedValue;
    07 import javax.persistence.Id;
    08
    09 @Entity
    10 public class Client {
    11 @Id
    12 @GeneratedValue
    13 private Long id;
    14
    15 private String username;
    16 private String firstname;
    17 private String surname;
    18 private LocalDate birthdate;
    19 }
  • Create a new ClientRepository, which is a basic CRUD interface for micronaut data DB access:

    01 package io.codenow.client.data.db.service.repository;
    02
    03 import io.codenow.client.data.db.service.repository.entity.Client;
    04 import io.micronaut.data.jdbc.annotation.JdbcRepository;
    05 import io.micronaut.data.repository.CrudRepository;
    06 import io.reactivex.Maybe;
    07
    08
    09 @JdbcRepository
    10 public interface ClientRepository extends CrudRepository<Client, Long> {
    11 Maybe<Client> findByUsername(String username);
    12 }
  • Create a new controller and put all the parts together

    01 package io.codenow.client.data.db.service.controller;
    02
    03 import javax.inject.Inject;
    04 import javax.validation.constraints.NotNull;
    05
    06 import org.example.service.repository.ClientRepository;
    07 import org.example.service.model.Client;
    08 import io.micronaut.http.annotation.Consumes;
    09 import io.micronaut.http.annotation.Controller;
    10 import io.micronaut.http.annotation.Get;
    11 import io.micronaut.http.annotation.PathVariable;
    12 import io.micronaut.http.annotation.Produces;
    13 import io.micronaut.validation.Validated;
    14 import io.reactivex.Flowable;
    15 import io.reactivex.Maybe;
    16
    17 /**
    18 * ClientDataController.
    19 */
    20 @Validated
    21 @Controller("/clients")
    22 @Produces
    23 @Consumes
    24 public class ClientDataController {
    25
    26 private final ClientRepository clientRepository;
    27
    28 @Inject
    29 public ClientDataController(ClientRepository clientRepository) {
    30 this.clientRepository = clientRepository;
    31 }
    32
    33 @Get("/")
    34 public Flowable<Client> listClients() {
    35 return Flowable.fromIterable(clientRepository.findAll());
    36 }
    37
    38 @Get("/{username}")
    39 public Maybe<Client> getClient(@PathVariable @NotNull String username) {
    40 return clientRepository.findByUsername(username);
    41 }
    42 }
  • 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)

    01 datasources:
    02 default:
    03 url: jdbc:postgresql://localhost:5432/{db_name}
    04 driverClassName: org.postgresql.Driver
    05 username: {db user}
    06 password: {db password}
    07 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.