## Support for OpenAPI and AsyncAPI Interfaces

REpresentational State Transfer (REST) is an architectural style for the design of network-based architectures. It guides the design of APIs that can be accessed over network.

CommaSuite supports REST in the following way:

- Generation of API specifications from an interface or a group of interfaces following OpenAPI and AsyncAPI standards

- Translation of captured REST and WebSocket network traffic to CommaSuite trace format for the purpose of monitoring

- Generation of adapters for REST interfaces for the purpose of online model-based testing with CommaSuite

The remaining part of this page describes in details each item.

### Generation of OpenAPI and AsyncAPI specifications from interfaces

CommaSuite can generate OpenAPI and AsyncAPI specifications in YAML format from a single interface or from a compound interface (a group of interfaces).

The generator task can be specified in the following way:

    Generate REST {
        task1 for compound interface IVendingMachine {
            API name: "VendingMachine"
            version: "1.0.0"
            OpenAPI server URL: "http://localhost:9998"
            AsyncAPI server: "server" URL: "ws://localhost:8026" protocol: "ws"
            paths: vmMappings
        }
    }

Here the compound interface IVendingMachine groups together two interfaces:

    Compound Interfaces {
        IVendingMachine {
            version
            "0.1"

            description
            "Description"

            interfaces
            IService
            IUser
        }
    }

The paths attribute in the generation task specifies the paths for the API endpoints for all commands, signals, and notifications in interfaces. It is given in a separate block for path mappings:

    Path Mappings {
        vmMappings {
            interface IUser:
                InsertCoin -> get /VendingMachine/v1/IUser/InsertCoin
                ReturnMoney -> get /VendingMachine/v1/IUser/ReturnMoney
                OrderProduct -> get /VendingMachine/v1/IUser/OrderProduct/{prodName}
            interface IService:
                SwitchOn -> get /VendingMachine/v1/IService/SwitchOn
                LoadProduct -> put /VendingMachine/v1/IService/LoadProduct/{product}
                Reset -> get /VendingMachine/v1/IService/Reset
                SwitchOff -> put /VendingMachine/v1/IService/SwitchOff
                OutOfOrder -> get /VendingMachine/v1/IService/OutOfOrder
                InventoryUpdate -> get /VendingMachine/v1/IService/InventoryUpdate
                GetStatus -> get /VendingMachine/v1/IService/GetStatus
        }
    }

Here the parameter segments in the paths are based on the parameters in the interface events and are surrounded by curly braces:

    LoadProduct -> put /VendingMachine/v1/IService/LoadProduct/{product}

'product' is a parameter in the command LoadProduct.

The path mappings also specify the HTTP operation to which the interface event is mapped: one of GET, PUT, POST or DELETE. The following rules apply:

- signals are mapped to PUT operations

- commands can be mapped to PUT, GET, POST or DELETE operations

The return types of commands must follow several rules:

- all commands have a return type that is a record

- the first field of the record type is of enumeration type and encodes the supported HTTP response codes

- the other fields indicate the data returned for the supported HTTP response codes. Codes are given as comments

Below is an example of a command following these rules:

    enum ResponseCode {
        OK = 200
        NoContent = 204
        NotFound = 404
    }
    ...
    record BaseResult {
        ResponseCode code
    }

    record GetStatusResult extends BaseResult {
        MachineStatus status // 200: OK
        String msg // 404: Not found
    }
    ...
    signature IService

    commands

    GetStatusResult GetStatus

As can be seen from this example, record type GetStatusResult contains fields commented with the HTTP response code for which they provide data.

If the intention for a command is to be of type void then a field for HTTP response code 200 must not be given. Code 204 (NoContent) will be returned in this case. No field for code 204 is needed.

InOut parameters are not allowed in commands. If a command is mapped to DELETE, it can have only In parameters that must appear in the endpoint path.

AsyncAPI specification is generated from the notifications in the source interfaces. Notifications are mapped to channels.

After executing the generator tasks for REST specifications, a folder 'rest' will be created under 'src-gen' that will contain the generated .yaml files:

    /src-gen
       /rest
          /task1
             /channels
             /datatypes
             /paths
             vendingmachine.errorresponses.yaml
             vendingmachine.event.yaml
             vendingmachine.rest.yaml

Here file vendingmachine.rest.yaml contains the OpenAPI specification and file vendingmachine.event.yaml contains the AsyncAPI specification. In addition, schema data types are generated from CommaSuite record and enumeration types. The YAML files are located in folder 'datatypes'.

The user is encouraged to study the provided example project VendingMachineTestApplicationREST to get familiar with the generated .yaml files.

### Generation of CommaSuite traces from captured OpenAPI and AsyncAPI traffic

Once YAML files are obtained according to the OpenAPI and AsyncAPI standards, various open source tools can be used to generate code and to develop a REST application.

Users might be interested in monitoring the OpenAPI and AsyncAPI traffic to check if it adheres to the interface specification.

The network traffic can be captured by tools like Wireshark and tshark (part of the Wireshark package). CommaSuite supports translating captured REST and WebSocket traffic. Here, WebSocket is used as a technology to implement the AsyncAPI that carries information from the interface notifications.

Once the traffic is captured with Wireshark or tshark in a .pcapng file, the following filter can be used:

    tshark -r <input file .pcapng> -F logcat-long -Tfields -eframe.time_epoch -eip.src -etcp.srcport -eip.dst -etcp.dstport -ehttp.request.method -ehttp.request.uri -ehttp.file_data (http or websocket) > result.txt

In this example, the result is stored in file result.txt.

The filtered content contained in the result file needs to be converted to one of the CommaSuite trace formats. The following generator task can be defined in the .prj file:

    Generate REST Trace {
        task1 {
            component VendingMachine
            path mappings vmMappings
            trace file "trace.txt"
        }
    }

The task requires a component definition that exposes the REST interfaces on its provided ports and the used path mappings. trace.txt is the file with raw REST and WebSocket traffic (after filtering).

After the execution of the task, a trace file is produced in JSONL format according to the CommaSuite trace format. It can be used for monitoring. The result is located as follows:

    src-gen/
      trace/
         trace.jsonl

The interested user can find an example trace file and a generator task in the example project VendingMachineTestApplicationREST.

### Generation of adapter for OpenAPI interfaces to perform online model-based testing

This section requires familiarity with the CommaSuite support for online model-based testing and the generation of test application.

An existing REST application for which a component model is available can be tested using CommaSuite. For this purpose, a test application can be generated. As explained in the section about test application, an adapter is required to translate the calls from the test application to REST calls and back. Such an adapter can be generated automatically using information from the component model and the path mappings.

The generation of the adapter is triggered with the following example generation task:

    Generate REST Adapter {
        vmRESTAdapter for component VendingMachine {
            ports: vmUserPort vmServicePort task: task1
            ports: vmCoinPort task: task2
        }
    }

The generation task is defined only for component models. Interface models are not currently supported. The adapter generation creates infrastructure for both provided and required component ports.

In general, multiple interfaces exposed via provided or required component ports can be accessed via a single REST service. This information needs to be specified in the generation task. In the example above, the interfaces IUser and IService form a single compound REST interface VendingMachine. This REST interface is specified in task1 for generating REST specification. The two interfaces are exposed via ports vmUserPort and vmServicePort. The information in the generation task specifies that these two ports are accessed via a single REST service generated with task1. Similarly, the interface ICoinChecker is used via the required port vmCoinPort. Its REST service specification is generated via task2. The information in the REST specification generation tasks is needed in the adapter generator to access the path mappings and the URLs of the REST services.

Once the adapter generator task is executed, a Java implementation of the adapter is generated. The AsyncAPI support is implemented with the WebSocket technology.

The generated Java files are located in folder named after the adapter generator task:

    src-gen/
       vmRESTAdapter/
          java/
             org/
                ...

All the generated classes are grouped in package org.eclipse.comma.restadapter.

Due to a limitation in the used implementation of the WebSocket technology, the following limitation in the adapter exists for interfaces accessed via required ports. The paths of notifications must have the same length in segments. The last two segments must have the name of the interface and the name of the notification respectively. Parameters in notification paths are not supported. This limitation is not imposed on interfaces accessed via provided ports.

A demo of the adapter generation is available in the example project VendingMachineTestApplicationRESTExample. In this project, an example implementation of a vending machine is made available via a REST service. Notifications from the vending machine are sent via a WebSocket channel. The coin checking functionality is accessed via a required port. The generated adapter connects the test application to the REST service. It also contains functionality for the required port: a REST service for the coin checker and a WebSocket service for the coin checker notifications.