Enabling and configuring REST API v2
Enabling REST API v2
To enable REST API v2, you need to add a mixin model to the project and update the environment file.
Including the restapi mixin model
Include the "RestV2 API Infrastructure" (restapi) model in your project. Do one of the following:
- Add the
<Mixin namespace="nexj:model:restapi" version="1+"/>
parameter to the <Mixins> tag in your environment file. - In NexJ Studio, use Edit Mixin Models dialog to add the model to the project.
Updating environment attributes
The following attributes are related to the REST API.
Name | Required? | Description | Example value |
---|---|---|---|
rest.version | Required | The current version of the REST API. | 1.0.0 |
rest.schemaBase | Required | The base message for available REST resource mappings. For more information, see Creating a schema base mapping message. | CRMSchemaBaseJSON |
rest.defaultPageSize | Optional | Default page size for GET requests. | 200 |
rest.configMetadata | Required | Metaclass with REST API configurations such as resource names. | CRMRestAPIConfig |
Add this code to the Environment root element in your project environment file:
<Environment ... rest.configMetadata="CRMRestAPIConfig" rest.schemaBase="CRMSchemaBaseJSON" rest.version="1.0.0"... />
Updating environment channel connections
Three HTTP channel connections are required for using the REST API:
- OpenAPI
- REST
- SelectionOptions
To add these connections, include the following code in the environment file in your project.
Channel connections in the environment file
<ChannelConnections>
<HTTPConnection channel="rest:OpenAPI"/>
<HTTPConnection channel="rest:REST"/>
<HTTPConnection channel="rest:SelectionOptions"/>
</ChannelConnections>
Channel definitions in the restapi model are initialized with basic authentication. Project-specific authentication components should be specified in the channel connection settings in the project environment files.
Enabling single sign-on authentication
If your project already has single sign-on authentication configured then ignore this section.
REST API v2 requires the SSO dependency model for accessing user context in integration services. The dependency model itself is included in the application project, but you must configure the data source in your project environment.
Add the following code to the RelationalDatabaseConnection element in the environment file: <DataSource name="sso:SSO"/>
Add the PKIKeyPair element below to the environment file in your project.
SSO PKIKeyPair
<PKIKeyPairs>
<PKIKeyPair keystore="<keystore>" name="nexjsa" password="text:<password>"/>
</PKIKeyPairs>
For more information about PKI keys and enabling single sign-on authentication, see Configuring single sign-on and Adding PKI keys to an environment file.
Configuring REST API v2
The following diagram demonstrates how the configurations are connected to provide the APIs. In this example, the Entity
class requires an API specification.
Before you start, configure the environment file to initialize the environment attributes and channel connections and perform any necessary configurations to enable SSO.
- Create the RestAPIConfig configuration class. This class is derived from the
rest:BaseRestAPIConfig
class defined in the "RestV2 API Infrastructure" (restapi) model. It contains the resource mappings for the Entity class. - Create the EntityJSON1.0.0 message to define the API specification for the
Entity
class. - Create the SchemaBaseJSON message as the schema base for the project. The schema base message is used by "RestV2 API Infrastructure" (restapi) model to provide API support for resources. The message references the EntityJSON1.0.0 message object.
- Update the configMetadata and schemaBase attributes in the project environment file.
Creating a configuration class
Projects implementing REST APIs must create their own metadata class containing API configurations. This must derive from the rest:BaseRestAPIConfig
class, which provides the template for available configurations.
The name of the configuration class must be specified in the project environment file using the rest.configMetadata environment variable.
The following configurations are available from the rest:BaseRestAPIConfig
template:
Attribute | Description | Configuration | Default value |
---|---|---|---|
mapResourceNames | Collection of available resources. | By default, this attribute points to the getResourceNameMap event. This event is used to configure the collection of resource messages. | Must be overridden. |
INFO_SWAGGER_UI | Message defining info block for SwaggerUI. | Allows configuration of the information header block for SwaggerUI. Configures title, description, and version. | (message (: version (rest:ObjectSnapshotManager'CURRENT_VERSION)) (: title "NexJ CRM") (: description "RESTful API for managing NexJ CRM data") ) |
The following example shows the inform:RestAPIConfig
configuration class for the inform model.
You can now create API endpoints for resources will be exposed through REST API, map these resources to metadata classes, and configure classes for REST API v2 features.
Defining resource mapping event
Resource mappings are defined in the getResourceNameMap event in the metadata configuration class for the project.
Here is an example of a resource mapping for an Interest
class, defined in inform:RestAPIConfig.meta:
Example: Resource mapping
<Class base="rest:BaseRestAPIConfig">
<Events>
<Event name="getResourceNameMap" static="true">
<Actions>
<Action name="main" type="main"><![CDATA[(collection
(message
(: resourceSingular "interest")
(: resourcePlural "interests")
(: className "inform:Interest")
)
)]]></Action>
</Actions>
</Event>
</Events>
</Class>
Available properties for the resource mappings are the following:
Name | Required? | Description |
---|---|---|
resourcePlural | Required | API endpoint for accessing resource. In the example, the resource can be accessed using: <URL for REST Channel>/interests |
resourceSingular | Required | Singular API endpoint used for accessing OpenAPI specification for resource. |
className | Required | Class name associated with the resource. In the example, the resource maps to the inform:Interest class. |
htmlPath | Optional | HTML path for accessing an instance in the UI. This is relevant for providing UI links in a request. |
introductionVersion | Optional | The API version that introduces this resource. This is relevant for OpenAPI documentation purposes. |
deprecationVersion | Optional | The API version that deprecates this resource. This is relevant for OpenAPI documentation purposes. |
Creating JSON resource messages
The JSON resource message for a class defines the class attributes that are accessible using REST APIs.
string
.
For example, a resource message for the Interest
class is called InterestJSON.1.0.0.
Example: JSON resource message
<Message format="JSON">
<Parts>
<Value description="Unique ID of the object." name="id" type="string"/>
<Value description="Related object associated with this instance." name="relatedObjectId" type="string"/>
<Value description="Value used to retrieve list of associated articles." name="value" type="string"/>
</Parts>
</Message>
Creating a schema base mapping message
In addition to creating resources messages, you must define message parts in the relevant schema base message.
The schema base mappings are a snapshot of the available resources using API. It is required so that projects can have independent API resources without having to customize schema for base projects. For example, a client project can have its own schema base, which is different from the base project and is maintained independently. This is also useful for testing. Projects can have a separate schema for testing, by setting the schema base at runtime in a unit test, which are not exposed publicly.
The schema base message has to follow the naming convention {rest.schemaBase}{format}.{rest.version}. The schema base message is defined in the rest.schemaBase environment attribute.
Each resource has a detail
definition and a summary
definition in the schema base message.
- Detail objects reference the resource message definition for a class. They have access to all attributes that are exposed in the resource message.
- Summary objects are a minimal version of the message definition that is accessible for read queries. To optimize read queries, collection associations that require joins (for example, participants) are not usually included in a summary object.
The example below is taken from the ObjectSnapshotJSON.1.0.0 schema base message.
Configuring metadata classes to use REST API v2
You need to configure metadata classes to enable them to use various REST API v2 features.
The following class properties must be set:
- nameAttribute
- caption
They are used for informative error handling and constructing user-friendly responses.
Configuring class attributes
For constructing user-friendly responses conforming to OpenAPI standards, you can configure class attributes using the facets defined in the rest:SubType.facets file. Depending on the attribute type, the configuration may be required.
The following facets are available for the timestamp attribute type:
Facet | Description | Formatting Example |
---|---|---|
UTC_DATETIME | A timezone-agnostic timestamp attribute. For example, activity start time. | 2020-03-08T04:00:00Z |
PURE_DATE | A timezone-agnostic date attribute. For example, date of birth. | 2020-03-08 |
DATETIME_WITH_TIMEZONE | A timezone-sensitive timestamp attribute. For example, a service request resolution time used for reporting. | 2020-03-08T21:00:00Z |
DATE_WITH_TIMEZONE | A timezone-sensitive date attribute. For example, coverage start date for an entity. | 2020-03-08 |
This is an example of a class configuration with SubType facets for timestamp attributes.
Example: Timestamp attributes with SubType facets
<Class caption="rest.TestObjectSnapshot.caption" nameAttribute="name">
<Attributes>
<Attribute description="Name attribute for class." name="name" type="string"/>
<Attribute description="Attribute with "DATETIME_WITH_TIMEZONE" SubType facet." facets="(SubType (DATETIME_WITH_TIMEZONE))" name="datetimeWithTimeZone" type="timestamp"/>
<Attribute description="Attribute with "DATE_WITH_TIMEZONE" SubType facet." facets="(SubType (DATE_WITH_TIMEZONE))" name="dateWithTimeZone" type="timestamp"/>
<Attribute description="Attribute with "PURE_DATE" SubType facet." facets="(SubType (PURE_DATE))" name="pureDate" type="timestamp"/>
<Attribute description="Attribute with "UTC_DATETIME" SubType facet." facets="(SubType (UTC_DATETIME))" name="datetimeUTC" type="timestamp"/>
<Attribute description="Unit for dateTimeWithTimeZone attribute." name="unit_datetimeWithTimeZone" type="string" value=""UTC""/>
<Attribute description="Unit for dateWithTimeZone attribute." name="unit_dateWithTimeZone" type="string" value=""UTC""/>
...
</Attributes>
...
</Class>
Configuring the ALTERNATE_KEY aspect
The ALTERNATE_KEY aspect can be implemented by a class to enable lookup using an alternate unique attribute instead of OID. This is used for classes such as User
, which have unique user names.
Instances of classes implementing this aspect inherit uniqueness validation by the alternate key for create and update commands.
The following inherited attributes are configurable for this aspect.
Attribute | Required? | Description | Example |
---|---|---|---|
API_KEY | Required | Association path to the alternate key to use in place of OID. | '(@ userName) |
API_KEY_ATTRIBUTE_LIST | Optional | Attribute list to automatically include the alternate key in attribute load. | '(firstName lastName) |
API_KEY_DESCRIPTION | Optional | Description of API_KEY value for use in the automatically generated documentation. The value should be a string reference to support localization. | rest.TestObjectTemplate.keyDescription |
API_KEY_EXAMPLE | Optional | Example of API_KEY value for use in the automatically generated documentation. | wm1 |
This is an example configuration of the ALTERNATE_KEY aspect in a TestObjectSnapshotTemplate
class:
Example: ALTERNATE_KEY configuration
<Class aspects="rest:ALTERNATE_KEY" caption="rest.TestObjectSnapshotTemplate.caption" nameAttribute="title">
<Attributes>
<Attribute description="Name attribute of class." name="title" type="string"/>
<Attribute description="Attribute used as alternate key." name="API_KEY" static="true" type="any" value="'(@ title)"/>
<Attribute description="Description of alternate key." name="API_KEY_DESCRIPTION" static="true" type="string" value=""api.TestObjectSnapshotTemplate.keyDescription""/>
...
</Attributes>
...
</Class>
This is an example of a GET request and response for a TestObjectSnapshotTemplate
instance with title "TestTemplate1":
Example: Request and response using ALTERNATE_KEY
Request:
<Base URL>/channel/<API Channel>/testObjectSnapshotTemplates/TestTemplate1
Response:
{
"$commit-hash": 256141559,
"title": "TestTemplate1"
}
Configuring the TEMPLATE aspect
The TEMPLATE aspect is used to simplify assignment of template classes when using the selection options API. For example, when requesting selection options for an activity template, all properties of the template may not be important and only the value and caption may be required for the purpose. This is what the TEMPLATE aspect provides.
The following inherited attributes are configurable from this aspect:
Attribute | Required? | Description |
---|---|---|
value | Required | Reference the string attribute to use as value. Classes implementing this aspect should have this attribute within that class, or overridden from the aspect. If the attribute is not persisted, a processWhere function is required to enable query by "value" for template assignments. |
ordinal | Optional | Ordinal attribute for sorting. Defaults to ordinal of |
TEMPLATE aspect configuration example
In this example, the TestObjectSnapshot
class has an association to the TestObjectSnapshotTemplate
class.
With this configuration, a response with TestObjectSnapshotTemplate
instances is returned when TestObjectSnapshot'template
is requested using selection options. Note that the response messages only contains caption and value properties provided by the TEMPLATE aspect.
This is an example configuration of TEMPLATE aspect in a TestObjectSnapshotTemplate
class:
Example: TEMPLATE configuration
--- TestObjectSnapshot.meta ---
<Class caption="rest.TestObjectSnapshot.caption" nameAttribute="name">
<Attribute description="Association implementing rest:Template aspect." name="template" type="rest:TestObjectSnapshotTemplate"/>
...
</Class>
--- TestObjectSnapshotTemplate.meta ---
<Class aspects="rest:TEMPLATE" caption="rest.TestObjectSnapshotTemplate.caption" nameAttribute="title">
<Attributes>
<Attribute description="Value used for template." name="value" type="string" value="(@ title)"/>
<Attribute description="Name attribute of class." name="title" type="string"/>
...
</Attributes>
...
</Class>
This is an example of a request using selection options to get the templates for a TestObjectSnapshot
class:
Example: Request and response for TEMPLATE instances
Request:
<Base URL>/channel/<Selection options Channel>/testObjectSnapshots/template
Response:
{
"options": [
{
"sortOrder": 0,
"value": "TestTemplate1",
},
{
"sortOrder": 1,
"value": "TestTemplate2",
}
]
}
Schema inheritance from a parent class
An API resource can inherit a schema without further schema configuration if the parent class already has a schema definition. This is to minimize configurations for subclasses when a schema definition already exists for the parent class. For example, in the following resource mappings the "persons" API will inherit the schema from "entities" since the Entity
class is the immediate parent of the Person
class.
Configuring APIs for mixins and parent projects
REST API v2 infrastructure does not automatically publish APIs from mixins or parent projects. If you want to expose APIs for models imported from a mixin or parent project, you must define them explicitly as part of the API specification. This prevents projects from exposing unintended APIs externally.
In order to expose an API for an imported model that already has an API specification message defined, you must do the following:
- Add a resource mapping to the configuration class.
- Add an entry in the schema base message for the project, referencing the specification message for the model.
In the example below, the inform:Interest class is imported from the inform mixin model.
- The first section updates the getMapResourceNames event of the
ExampleRestAPIConfig
configuration class to include "interests" as a resource mapping. - The second section updates the ExampleSchemaBaseJSON schema base message for the project to include references to the inform:schema:InterestJSON.1.0.0 message, where the inform:schema:InterestJSON.1.0.0 message is imported from the inform model.
Example REST API links
The table below illustrates example REST API links.
Description | Link |
---|---|
REST API link to the "entities" resource. This can be used for GET, POST, PUT, and DELETE methods with | Request all entities: |
Link to the full OpenAPI spec in JSON format. | http://localhost:7080/nexj/channel/rest:OpenAPI/en/openAPI.json |
Link to SwaggerUI | http://localhost:7080/nexj/rest:SwaggerUI.html |
Link to selection options for entity "tier". This assumes the tier class is configured | http://localhost:7080/nexj/channel/rest:SelectionOptions/entities/tier |