public interface OpenapiSupport RESTHandler servlet, the Smart GWT server can also generate a standard OpenAPI specification of the REST interface supported by RestHandler. This allows any client system that supports OpenAPI to access the operations supported by your DataSources. Because details like field types and validators) are automatically translated to OpenAPI, the OpenAPI specification (OAS) of your DataSource operations is much more specific and detailed than the general RestDataSource protocol spec, and can allow automatically generated UIs or automatically generated communication stubs to be much richer and easier to use. Very often, a reasonably simple DataSource expresses more than can be easily translated to the current OpenAPI specification. In such cases, efforts are made to use the OpenAPI extensions mechanism to provide that level of detail. Validators are one common area of interest. It is worthwhile to inspect the raw YAML output at least once before relying solely on visual tooling, unless said tooling supports vendor extensions. ReDoc, for example, is able to render the generated spec well, and in fact powers the example specification (see link below), but leaves out important details found in the extensions, like the RESTHandler's JSON prefix and suffix.
<filter>
<filter-name>cross-origin</filter-name>
<filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cross-origin</filter-name>
<url-pattern>/restapi/*</url-pattern>
</filter-mapping>
allowing the Swagger Editor to access the YAML generated for you by Smart GWT, through the use of its url query parameter. e.g., http://editor.swagger.io/?url=http://localhost:8080/api/Customer.yaml openapi.yaml resource. For example, if your servlet is configured to respond to requests at /restapi
<servlet-mapping>
<servlet-name>RESTHandler</servlet-name>
<url-pattern>/restapi/</url-pattern>
</servlet-mapping>
then a GET request to /restapi/openapi.yaml will yield the automatically generated documentation, based on your application's DataSource (ds.xml) configurations. This specification is generated dynamically, so that each new request for the specification includes any changes made to new or updated DataSources since the last request. Alternatively, save the file to disk, with modifications if desired, and serve it statically from another location if that's more in line with your requirement. openapi.yaml by default includes a reference to every path exposed by every DataSource.ds.xml file found in your project. The paths exposed by your DataSource are determined by the rules documented in the RESTHandler servlet's SimplifiedREST protocol. For an Order DataSource with only default operationBindings, these references would look something like the following:
paths:
/:
post:
summary: DataSource-agnostic POSTMessage protocol
# and so on... remainder clipped for brevity
/RESTDataSource/Order/fetch:
$ref: Order.yaml#/paths/~1RESTDataSource~1Order~1fetch
/RESTDataSource/Order/add:
$ref: Order.yaml#/paths/~1RESTDataSource~1Order~1add
/RESTDataSource/Order/update:
$ref: Order.yaml#/paths/~1RESTDataSource~1Order~1update
/RESTDataSource/Order/remove:
$ref: Order.yaml#/paths/~1RESTDataSource~1Order~1remove
/RESTDataSource/Order/batch:
$ref: Order.yaml#/paths/~1RESTDataSource~1Order~1batch
/Order:
$ref: Order.yaml#/paths/~1Order
/Order/{orderId}:
$ref: Order.yaml#/paths/~1Order~1%7BorderId%7D
The first path in the above listing documents RESTHandler's singular AdvancedREST endpoint, described by the RESTDataSource's postMessage protocol and found in our example configuration at /restapi/. As documented elsewhere, this should normally be the endpoint preferred by all but the simplest of integrations. On the other hand, it is also the endpoint most difficult to document effectively, due in part to a handful of restrictions found in the OAS 3.x specification. One such restriction is documented in an open issue around request/response correlation, which in short points out that there is no good way to correlate a variation of some request to the matching variation on the response. In the case of the AdvancedREST endpoint, of course, request and response formats both depend entirely on the values provided in dataSource, operationType, and operationId arguments. Ideally, we could document the inputs and outputs of a resource like /restapi/?dataSource=Order&operationType=fetch&operationId=fetchByCustomer separately from one like /restapi/?dataSource=Order&operationType=fetch&operationId=fetchByUser, but this is expressly disallowed.
In the absence of any spec-compliant mechanism like supporting interdependencies between query parameters then, we also provide simplified variations of the AdvancedREST endpoint on each DataSource's specification, seen alongside the other SimplifiedREST endpoints with the RESTDataSource path. These 'SimplifiedPOST' endpoints do allow for Criteria & AdvancedCriteria, as well as batching of multiple operations against the same DataSource.
You can easily view all of the operations for a single DataSource by making the request to {id}.yaml instead of openapi.yaml, where {id} is the ID of any DataSource in your project. Building on the examples above, a request for /restapi/Order.yamlwould include every path except '/'. Again, prefer the RestHandler's AdvancedREST endpoint to SimplifiedREST, with the caveat that SimplifiedREST documentation my be more explicit until a future version of the OAS spec addresses some of the issues discussed here.
A full example specification is too lengthy to include in documentation, so it is left to the reader to experiment with their own DataSources (sample DataSources are included with the SDK and in Maven archetypes or with the example specification bundled in the SDK (link below), using this documentation as guidance. Most of what is generated for you can be pretty easily traced back to your DataSource - description, field names, required/optional attributes, and type mappings are all pretty straightforward, and the rest of it really should work the way you might expect it to. A few specific examples include:
description, complete with i18n translations as applicable, when a locale can be derived from the servlet request or is specified explicitly with a 'locale' query parameter (e.g., ?locale=es). Declarative Security rules are found (rules themselves are not disclosed, by design). criteria, description, outputs, etc. are respected.
<DataSource serverType="sql" schema="PUBLIC" dbName="ClassicModels"
ID="Order"
tableName="orders">
<serverObject className="com.example.classicmodels.OrderOperations" />
<fields>
<field name="orderNumber" type="sequence" primaryKey="true" />
<field name="orderDate" type="date" required="true" />
<field name="requiredDate" type="date" required="true" />
<field name="shippedDate" type="date" />
<field name="status" type="enum" length="15" required="true">
<valueMap>
<value>In Process</value>
<value>Shipped</value>
<value>Cancelled</value>
<value>Disputed</value>
<value>Resolved</value>
<value>On Hold</value>
</valueMap>
</field>
<field name="comments" type="text" length="16777216" />
<field name="customerNumber" title="Customer" type="integer" required="true"
foreignKey="Customer.customerNumber"
displayField="customerName" />
<field name="customerName" includeFrom="Customer.customerName" hidden="true" />
</fields>
<operationBindings>
<binding operationType="add" operationId="addWithDiscountCode" serverMethod="addWithDiscountCode" />
<binding operationType="add" operationId="addWithManualAdjustment" serverMethod="addWithManualAdjustment" />
</operationBindings>
</DataSource>
/Order:
$ref: Order.yaml#/paths/~1Order
/Order/{orderId}:
$ref: Order.yaml#/paths/~1Order~1%7BorderId%7D
/Order/add/addWithDiscountCode:
$ref: Order.yaml#/paths/~1Order~1add~1addWithDiscountCode
/Order/add/addWithManualAdjustment:
$ref: Order.yaml#/paths/~1Order~1add~1addWithManualAdjustment
The simplest means for this kind of minimal customization is through server.properties configuration. Example values for supported properties include:
openapi.info.version: 1.0.0
openapi.info.title: New Application
openapi.info.description: A short description of New Application
## default value derived from servlet context & httpRequest
openapi.servers.servletUrl: http://localhost:8080/restapi
You may also use configuration to control which DataSources are exposed to your specification. Three strategies are supported: <DataSource ID="Order" tableName="orders" apidoc="false">
openapi.ds.blacklisted: Order, OrderDetail
openapi.ds.whitelisted: Order, OrderDetail
openapi.ds.dynamics: DYN_Environment, DYN_Status
request.setAttribute("openapi.ds.dynamics", "DynamicOrder$Foo_0123, DynamicOrderItem$Foo_0123,"); Finally, a DataSource is automatically excluded from the specification under the following circumstances: <binding apidoc="false" operationType="add" operationId="addWithDiscountCode" serverMethod="addWithDiscountCode" />
allowMultiUpdate com.isomorphic.openapi package of the isomorphic-core-rpc module. Any of these templates may be overridden by placing a copy in a location known to the RESTHandler servlet (again, refer to server javadoc), but this kind of thing should normally be considered the last course of action.