DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Data Engineering
  3. Databases
  4. Improvements in CUBAs REST API v2

Improvements in CUBAs REST API v2

The release of the CUBA platform 6.3 has brought huge changes. Take a second look at the platform and its REST API features in this article.

Mario David user avatar by
Mario David
·
May. 31, 17 · Opinion
Like (14)
Save
Tweet
Share
4.33K Views

Join the DZone community and get the full member experience.

Join For Free

Along with the application components, there is another interesting feature that is a part of the 6.3 release of the CUBA platform. It deals with the REST API feature. In this post, we will have a deeper look into it and see the differences and potential benefits of it.

Once Upon a Time, There Was a Blog Post

Last year I did a blog post about the REST-API implementation of the CUBA platform. In the 6.3 release, the generic REST API has been more or less redesigned completely. Due to the massive changes, it is worth taking another look into it.

Just to give you a quick recap on what the old (v1) REST API was all about, here’s a small list of features that have been included:

  • (API-)user authentication.
  • CRUD on single entity instances.
  • Get a list of entities through a JPQL query definition.
  • Execute business logic through service calls via HTTP.
  • Upload/Download files from file storage.
  • Create views to customize entity representation retrieval.

In the new implementation, the feature list pretty much remains the same, but the way to execute the different features changed quite a bit.

Let’s look at the things that have changed.

Changes on CUBA's REST API

First, the authentication mechanism has changed to the OAuth2 mechanism. Next, the CRUD operations on the entity level have become much more “RESTful” towards a de-facto standard resource naming, which is implemented by most of the major web application frameworks. This also includes usage of the most common HTTP verbs.

Authenticate via OAuth2

The first major change concerns the login mechanism. The v1 login mechanism was based on a homegrown login mechanism. In version 2, it is a fully compatible implementation of the OAuth2 specification. The login mechanism basically goes like this (to communicate to the REST API I use the cmd line tool Httpie):

The API client sends a POST request to the server to get an access token. In order to accept the request, it has to be executed with basic auth in place (client:secret). These hard-coded client secrets can be configured in the app.properties of the CUBA application (cuba.rest.client.id and cuba.rest.client.secret). In the body, a form is sent with the actual credentials of the user.

The result is a JSON with a access_token in it. This token has to be used for further requests in the Authorization header like this: 'Authorization:Bearer abc315c8-2790-4d5a-8ca9-7e9c9922e168'.

Here is the full example:

$ http --form --auth client:secret  POST localhost:8080/app/rest/v2/oauth/token grant_type=password username=admin password=admin

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
    "access_token": "abc315c8-2790-4d5a-8ca9-7e9c9922e168",
    "expires_in": 43199,
    "scope": "rest-api",
    "token_type": "bearer"
}

CRUD Operations on Entities

With the access token, we are able to consume the REST API by passing the token to every request. One example of this is that we can create a request that will list all customers that the user is allowed to see (you can download the example app from GitHub).

$ http localhost:8080/app/rest/v2/entities/cesdra\$Customer 'Authorization:Bearer abc315c8-2790-4d5a-8ca9-7e9c9922e168'

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

[
    {
        "_entityName": "cesdra$Customer",
        "_instanceName": "Reuben C. Bridges",
        "id": "091e878a-2da1-a73f-6274-28e6ba7e902e",
        "name": "Reuben C. Bridges",
        "version": 2
    },
    {
        "_entityName": "cesdra$Customer",
        "_instanceName": "Ida B. Rossi",
        "id": "16158ff7-d162-2e76-97cf-4fd04883861c",
        "name": "Ida B. Rossi",
        "version": 2
    },
    {
        "_entityName": "cesdra$Customer",
        "_instanceName": "Joshua Howe",
        "id": "68dfa571-be1c-2559-c5b6-743aa87d4c8c",
        "name": "Joshua Howe",
        "version": 1
    }
]

This structure is basically the same that all of the major web frameworks support nowadays. CUBA offers a swagger API description, which is a very cool feature to get familiar with the API structure.

Entity CRUD part of the CUBA Swagger API description.

Predefined Queries Instead of per-request-JPQL

One thing that changed dramatically is the feature to execute arbitrary JPQL queries. In version 1, the client could create a request that had a JPQL in it, which should get executed. This exposure of the database query language in the API is something that might be valuable for integration purposes, where you control the sender as well as the receiver. But from an API point of view, it is like exposing detailed information about the implementation structure to the outside world.

Since in v2 the API moves much more towards a public facing API facility, this feature was removed. The replacement for that is that you can define something that is very similar to named queries in the JPA world for the API on the server. These named queries act as the abstraction mechanism to the API consumer. This way the customer is not forced to know about the internal entity structure. Instead, it only has to know about the name of the query and the parameter that this query might have.

Here’s a small example of that definition:

<queries xmlns="http://schemas.haulmont.com/cuba/rest-queries.xsd">
    <query name="customerByType" entity="cesdra$Customer" view="customer-view">
        <jpql><![CDATA[select c from cesdra$Customer c where c.customerType = :customerType]]></jpql>
        <params>
            <param name="customerType" type="java.lang.String"/>
        </params>
    </query>
</queries>

It can be created in a file within your war file or in an external config folder on the server, but the main idea is that it has to be created in advance, so the client is not forced to define these details (which also means that the consumer can’t either). Generally, I think this is a very good way of defining an API abstraction.

Batch Mode of Entities is Gone

Another thing to notice is that it is not possible to make a bulk import out of the box anymore. In the previous version is was possible to POST instances with the following JSON structure:

{
  "commitInstances": [
    {
      "id": "NEW-cesdra$Customer",
      "name": "Mike"
    }
  ]
}

In the commitInstances array, a list of entities can be created and inserted into the database within one database transaction.

Due to the change towards the de-facto standard REST URI resource pattern, this is no longer possible, because the instances are treated like resources. When an instance is created, you’ll get back an HTTP response 201 - created with a corresponding LocationHeader that points to this newly created resource (in this case - the entity). Something like this is hardly possible in a batch mode, because the response can’t point to the created resource. Also, it would be problematic to handle validation errors in this case (which have been included in 6.4 with bean validation).

This is just something to know. It would be possible to create a service that brings back this feature of doing bulk create, but with that, you would get back to the RPC-based approach of the API (which is exactly the point of the v2 API to drift away from that, at least in my understanding of it).

Using the REST API

There are several examples in the docs on how to communicate with the new API. Therefore I will not go into detail about the different CRUD operations, service invocations, etc.

Instead, I would like to show you two little tools that I found quite appealing to deal with the API on a day-to-day basis. Above we have already seen the command line based tool called httpie. Httpie is just like cURL but optimized for ease of use. cURL has the downside that certain operations on HTTP (like form submit) are fairly verbose when you want to type them.

This is where Httpie kicks in. Let’s look at the Login process in cURL:

curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -H "Accept: application/json" -H "Authorization: Basic Y2xpZW50OnNlY3JldA==" -d 'grant_type=password&username=admin&password=admin' "http://localhost:8080/app/rest/v2/oauth/token"

With Httpie it changes to this:

http --form --auth client:secret  POST localhost:8080/app/rest/v2/oauth/token grant_type=password username=admin password=admin

It gives you a fairly nice tool to do the easy HTTP things. But for some people, fiddling around with the command line all the time is not the preferred way of doing it (including myself), so there is one other tool I used lately.

Explore Your API With Postman

The next thing that I use really often for interacting with the CUBA API is the tool Postman. Postman is a UI based HTTP client that started out as a Chrome plugin and emerged to a full fletched application. It is built on Electron, which is pretty cool.

Postman has the possibility to create “request collections.” These are groups pre-defined requests to your API. You can just select one and “send” it.

Additionally, there is another building block called “environments.” An environment is the possibility to parameterize your collections. One example of this might be the server URL. When you have different deployments of your application- say, in dev, testing, and production- you can create three environments with the definition of a particular variable that you use in your requests.

Here’s an example of the UI of Postman:

CUBA API usage through Postman.

To give you an easy start with the tool, I created the Postman collection as well as the Postman environment within the GitHub example. You can just import it into your Postman client and start fiddling around with it.

One very interesting thing that I noticed is that it is possible to not only use this for debugging purposes and manual communication with the API, but for test automation as well. For this, there is a Test tab in the UI where you can do asserts on the response with JavaScript. I’ll probably go into more detail on that topic in an extra blog post.

Within the shared collection, I used it not for automated testing, but instead used the scripting facility to do some kind of automation. When you look at the Tests tabs of the Login request, you will find that I’ve programmatically created an environment variable within postman called ‘access_token’:

if (isResponseOk()) {
    var jsonData = getJson();

    var noErrorInBody = !('error' in jsonData);
    tests["No error in JSON response"] = noErrorInBody;

    if (noErrorInBody) {
        var access_token = jsonData.access_token;
        var accessTokenInBody = 'access_token' in jsonData;
        tests["Access token received"] = accessTokenInBody;

        postman.setEnvironmentVariable("access_token", access_token);
    }
}

function isResponseOk() {
    isResponseCodeOk = responseCode.code === 200
    istContentTypeOk = postman.getResponseHeader("Content-Type") == "application/json;charset=UTF-8";
    tests["Response is OK"] = isResponseCodeOk;
    tests["Content-Type is JSON"] = istContentTypeOk;

    return isResponseCodeOk && istContentTypeOk
}

function getJson() { return JSON.parse(responseBody) }

This script basically checks if the response is valid, and if it is, it will set the environment variable like this: postman.setEnvironmentVariable("access_token", access_token);.

With that everywhere in Postman, the variable can be used just by using the double-curly braces notation (like shown below in the Authorisation header).

Using Swagger Description in Postman

If you want to try out all features of the v2 API in Postman, there is even an easier way to do so, instead of creating all the requests by hand. Postman is able to import not only the collections in their format, but read the Swagger format as well. With this, you can just point Postman to the URL of the YAML description of CUBA.

With that, you have imported the whole description of Swagger into your app and can start uploading files, doing service requests, and more.

API REST Web Protocols Database

Published at DZone with permission of Mario David. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Steel Threads Are a Technique That Will Make You a Better Engineer
  • Spring Boot, Quarkus, or Micronaut?
  • The Path From APIs to Containers
  • 11 Observability Tools You Should Know

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: