REST Builder & OpenAPI

REST Builder is based on OpenAPI, and its philosophy is “OpenAPI first”: first you write the profile and then you use it as the base of your implementation.

But first you must create a project with two empty bundles (a Blade template will follow soon). The bundles (-api and -impl) should have the files you are already used to: a build.gradle and a bnd.bnd. The novelty is two YAML files, a configuration file (rest-config.yaml) and the OpenAPI profile (rest-openapi.yaml). An example project is here.

Let’s see the configuration file in detail. In the root of the -impl project we have to create a YAML file to specify paths and the basic configuration of our new API. A sample implementation would be:

apiDir: "../headless-test-api/src/main/java"
apiPackagePath: "com.liferay.headless.test"
application:
    baseURI: "/headless-test"
    className: "HeadlessTestApplication"
    name: "Liferay.Headless.Test"
author: "Javier Gamarra"

This file specifies the path of the -api bundle, the java package that we will use across all the bundles and the information of the JAX-RS application: the path of our application, the name of the class and the JAX-RS name of our API.

I’ve skipped two advanced features, generating a client and automated tests, will see them later.

Just one step left, writing our OpenAPI profile.

OpenAPI profile

The OpenAPI profile will be the source of all our APIs, in this file, we will add the paths and entities of our API. First, we’ll create a YAML file called rest-openapi.yaml. Writing YAML files is tricky so we recommend using the swagger editor to do it, which validates the YAML file against YAML syntax and the OpenAPI specification.

A simple OpenAPI profile that retrieves a fictitious entity might look like this:

components:
  schemas:
    Entity:
      description: A very simple entity
      properties:
        name:
          description: The entity name.
          type: string
        id:
          description: The entity ID.
          type: integer
      type: object
info:
  description: ""
  title: "My API"
  version: v1.0
openapi: 3.0.1
paths:
  "/entities/{entityId}":
    get:
      parameters:
        - in: path
          name: entityId
          required: true
          schema:
            type: integer
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Entity"
          description: ""
      tags: ["Entity"]

All OpenAPI profiles have three different sections: components, info, and paths. The easiest one is the information block. It contains the OpenAPI version, the title and the version of your API:

info:
  description: ""
  title: "My API"
  version: v1.0
openapi: 3.0.1

Indentations should be spaces. The swagger editor helps with formatting.

The components section specifies the schemas/entities to return or accept on your APIs. In this case, you define a schema called Entity that has two string fields: a name and an id.

components:
  schemas:
    Entity:
      description: A very simple entity
      properties:
        name:
          description: The entity name.
          type: string
        id:
          description: The entity ID.
          type: integer
      type: object

The OpenAPI specification defines many types and fields you can use in your schemas.

The other common type is $ref, a reference type that allows you to refer to an existing type like this:

$ref: '#/components/schemas/Entity'

The last block, called paths, defines the URLs that you’ll expose in your APIs, with the type of HTTP verbs, list of parameters, status codes, etc.

paths:
  "/entities/{entityId}":
    get:
      parameters:
        - in: path
          name: entityId
          required: true
          schema:
            type: integer
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Entity"
          description: ""
      tags: ["Entity"]

The pattern above, "/entities/{entity}", follows a common pattern in REST APIs. This is the endpoint that retrieves one element, "/entities". It returns a list of elements, and a POST request creates one.

For every path, it is mandatory to add a tag that points to an existing schema to indicate where to generate your code. REST Builder creates a method inside the class [TAG]ResourceImpl.java.

Generation

Once you’ve written your OpenAPI configuration and profile, it’s time to generate your scaffolding for REST and GraphQL.

In the -impl or in the root module folder, execute this command:

gw buildREST

You can use gw bR if you want to save a few keystrokes.

If everything’s indented properly and the OpenAPI profile validates, REST Builder generates your JAX-RS resources and the GraphQL endpoint. Next, you’ll see what has been generated and how to implement our business logic.

Examples

Here’s a complete example that defines all CRUD operations in OpenAPI.

GET Collection

paths:
    "/entities":
        get:
            responses:
                200:
                    content:
                        application/json:
                            schema:
                                items:
                                    $ref: "#/components/schemas/Entity"
                                type: array
                    description: ""
            tags: ["Entity"]

DELETE

paths:
    "/entities/{entityId}":
        delete:
            parameters:
                - in: path
                  name: entityId
                  required: true
                  schema:
                      type: integer
            responses:
                204:
                    content:
                        application/json: {}
                    description: ""
            tags: ["Entity"]

POST

paths:
    "/entities":
        post:
            requestBody:
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/Entity"
            responses:
                200:
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/Entity"
                    description: ""
            tags: ["Entity"]

PUT

paths:
    "/entities/{entityId}":
        put:
            parameters:
                - in: path
                  name: entityId
                  required: true
                  schema:
                      type: integer
            requestBody:
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/Entity"
            responses:
                200:
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/Entity"
                    description: ""
            tags: ["Entity"]

Summary

There are more examples showcasing all the supported OpenAPI syntax here and here. Your next step is to create your API.

« How to install REST BuilderDeveloping an API with REST Builder »
Was this article helpful?
1 out of 1 found this helpful