Skip to main content

Java Micronaut REST Server with CockroachDB

🕓 45 minutes

What you’ll learn

How to set up 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.cloud.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 local configuration in codenow/config/application.yaml:

    • Fill {db user} and {db password} according to your local development setup
      danger

      These settings are valid only in your local development environment to connect to your local database! Never store your credentials in the codebase! You don't have to implement your own solution for the secure storage of credentials. In CodeNOW, credentials are securely stored for each deployed service (database/message broker/...). You can find how to set up the service connection in CodeNOW in the Deployment Tutorial and in the Connecting Services Tutorial.

  • 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.