CLOUD & DEVOPS

Quarkus & Couchbase: a simple REST example

event 20 aprile 2023

In one of the events I attended in the past months, I had the opportunity to meet some colleagues who work for Couchbase. I was familiar with the renowned product but had never had a chance to use it, so I asked them to briefly explain its features, and I must say it was interesting. I invited the guys to come to Extra Red and share their products with us, and they will indeed be guests at one of our Symposiums, a monthly event where we talk about technologies, methodologies, projects, and much more with all our colleagues.

For those who are not familiar, Couchbase is an open-source, distributed NoSQL database designed to provide fast, scalable, and flexible data management with high performance. It utilizes a document-based data model, where data is organized in JSON documents that can easily scale horizontally across multiple nodes. It is also capable of handling large amounts of data reliably and offers data redundancy and fault tolerance, thanks to its native integration with Kubernetes and Openshift. In fact, there is a dedicated operator that makes cluster creation extremely simple and fast.

I am particularly interested in the application aspect, especially the use of Couchbase as a database. That's why I started doing some usage tests with Quarkus, a Java cloud-native technology that we extensively use. The idea was to create a simple REST interface to write and read JSON files to the database. However, since I found very few examples, I decided to write this short article to share my experience, hoping it could be useful to others as well.

You can find the link to the repository on GitHub with the example code at the end.

As I mentioned, it is a simple project created using Quarkus' own Maven project generator. Then, I used the (still in alpha) "quarkus-couchbase" connection library by simply adding the following dependency to the pom file:

<dependency>
 <groupId>com.couchbase</groupId>
 <artifactId>quarkus-couchbase</artifactId>
 <version>1.0.0-alpha.1</version>
</dependency>

As you can see in the library info, it is configured simply by adding the properties to the "application.properties" file:

quarkus.couchbase.connection-string=localhost
quarkus.couchbase.username=username
quarkus.couchbase.password=password

The usage of the library is quite simple, and you will find what I describe in the "QuarkusCouchbaseService" class, where the REST methods are defined:

The library allows us to inject the Cluster, from which we retrieve the bucket we want to read/write to.

  • Through this, we retrieve the bucket on which we want to read/write.
  • At this point, we use the 'get' and 'upsert' methods of the collection, respectively, to read and write the files we have received via REST
@Inject
Cluster cluster;

@ConfigProperty(name = "couchbase.bucketName")
String couchbaseBucketName;

@GET
@Path("/getFile/{id}")
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Gets a file", description = "Retrieves a json file by id")
@APIResponses(value = {
       @APIResponse(responseCode = "200", description = "Success",
               content = @Content(mediaType = "application/json")),
       @APIResponse(responseCode = "404", description="File not found",
               content = @Content(mediaType = "application/json"))
})
public Response getFile(@PathParam("id") String id) {

   var bucket = cluster.bucket(couchbaseBucketName);
   var collection = bucket.defaultCollection();

   try {
       return Response.ok(collection.get(id).contentAsObject().toString()).build();
   } catch (DocumentNotFoundException e){

       return Response.status(Response.Status.NOT_FOUND.getStatusCode(),"{\"error\":\"Not Found\"}").build();
   }

}

@POST
@Path("/sendFile")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Store File", description = "Store a json file into database, return the id of the new element")
@APIResponses(value = { @APIResponse(responseCode = "200", description = "Success",
       content = @Content(mediaType = "application/json")),
   @APIResponse(responseCode = "404", description="File not found",
       content = @Content(mediaType = "application/json"))
})
public Response storeFile(String body) {

   var bucket = cluster.bucket(couchbaseBucketName);
   var collection = bucket.defaultCollection();

   String id = UUID.randomUUID().toString();

   JsonObject jsonObj = JsonObject.fromJson(body);
   MutationResult upsertResult = collection.upsert(id,jsonObj);

   return Response.ok("{\"id\":\"" + id +"\"}").build();
}

Note that for the insert case, I created a generic id, which should then be used as a parameter in the GET request to retrieve the specific JSON file. This is because the server does not generate an identifier automatically but needs to be explicitly specified during creation.

That's it! To perform various tests, I simply used the Couchbase Docker image available on Docker Hub. I ran the database locally using Docker, created a bucket, and configured the accesses as specified above.

At this point, you can write and retrieve files from the database, perhaps using Postman or simply with curl:

Write a file to the database:

curl --location --request POST 'http://localhost:8080/quarkus/sample/sendFile' \
--header 'Content-Type: application/json' \
--data-raw '{
   "prova":123,
   "test":"stringa"
}'

The response will be similar to this:

{ 
  "id": "f8b980eb-1fa0-4070-bcd6-ff3fdce23faf"
}

Now let's test retrieving the file:

curl --location --request GET 'http://localhost:8080/quarkus/sample/getFile/f8b980eb-1fa0-4070-bcd6-ff3fdce23faf' \
--data-raw ''

This will give us the following response:

{ 
  "test": "stringa",
   "prova": 123
}

That's it! I hope this was helpful. If you have any suggestions or proposals, they are welcome, perhaps even an in-depth look at Quarkus, for example.

Useful Links:

other articles on the topic

explore Read All!