Before creating custom Service Types, it is very important that you understand the terms that are used in the SmartObject architecture, how the components work together and the role of each component.
The diagram below illustrates the conceptual architecture of SmartObjects and the JSSP. Pay special attention to the red, italic text: these are the terms you need to understand while developing a custom service type. We describe each term in more detail following the diagram.
JSSP Architecture
Let’s take our sample diagram and break down the SmartObjects components:
Service Type
A Service Type is a TypeScript JavaScript file that contains all the code necessary to interact with a specific provider. Typically, this file contains the code required to interact with the provider's APIs and it would contain code that discovers and/or describes the provider's objects to K2 in a consistent way as Service Objects. In some circumstances, the Service Type may also implement logic to handle security for the provider's API. Essentially, the Service Type's task is to "translate" the provider's native objects into Service Objects (and vice-versa), and to call the various methods in the Provider's API at runtime. Service Types are normally written to expose a particular technology. In our example diagram, we have a Service Type that understands how to interact with a hypothetical service that provides Employee and Account data.
Since the Service Type contains all the code necessary to interact with a provider, this is the only item a developer needs to implement when they want to expose some other system as K2 SmartObjects. As long as the Service Type conforms to the outline and base methods described in the Understanding JavaScript Service Provider project structure topic, the components in the architecture can load the necessary functionality.
In addition to the logic required to interact with the provider's APIs and describing the Service Objects, the Service Type can also define configuration settings (known as Service Keys) that allow the administrator to configure the Service Instance when they register a Service Instance. Typically, these configuration keys define values like URLs to reach the provider's APIs, or other configuration values that may differ between instances of the same Service Type.
Service Type files reside in a location accessible to the server (such as a GitHub RAW URL), or you can upload the Service Type file to the server when you register the Service Type with K2.
You must register the Service Type with a K2 environment before you can start adding Service Instances of that type.
Service Instance
Once a Service Type is registered in the K2 environment, Administrators can create one or more Service Instances for that Service Type. A Service Instance is essentially a configured instance of a Service Type, and contains various configuration values that are required by the Service Type. The configuration values could include values required to connect to the data provider (for example, a server name or a URL) and perhaps additional configuration values that describe how the service type should behave. Another important setting for a Service Instance is the Authentication Mode setting: this determines the user credentials that are passed to the underlying Service Type at runtime.
In the diagram, there is one Service Instance for the sample Service Type. You could, however, have more than one instance of the same Service Type. For example, if you had a Service Type that exposes PostgreSQL databases to K2, you might have two separate Instances of the Service Type, each configured to connect to a different PostgreSQL database.
When you register a Service Instance, K2 executes the ondescribe method that describes the available Service Objects for the targeted Service Instance.
Service Object
Service Objects are essentially "translated" representations of the entities in the underlying data provider. Under the covers, Service Objects are just representations of the entities in the provider and contain no processing logic.
Service Objects expose the properties and methods for objects in a Provider as consistent SmartObject Method Types and Property Types. It is the responsibility of the code in the Service Type to perform the necessary mapping between the Provider's types and the types used by SmartObjects. You can define Service Objects statically or discover them dynamically.
Service Objects are always tied to a Service Instance, because the Service Instance exposes the Schema that describes the Service Object. Note that Service Objects are defined by the Service Type and cannot be consumed in applications directly. Designers must create SmartObjects that are tied to one or more Service Objects before the service can be consumed in an application.
A Service Instance would usually contain one or more Service Objects. As part of the translation, the Service Type will convert the objects in the provider to Service Objects; the properties of the objects are converted to Service Object Properties and the methods in the provider's objects are converted to Service Object Methods. A large part of implementing a customer Service Type is to write the code that will perform this "translation" to represent the underlying system's artifacts as Service Objects.
In our sample diagram, we have two Service Objects (soEmployee and soAccount), each with two preoprties and two methods. Ultimately, these Service Objects represent the entities in the Provider's API (poEmployee and poAccount).
SmartObject
The final step to integrate a data provider with applications is to create SmartObjects that reference one or more Service Objects. This task can be performed by K2 Administrators by automatically generating SmartObjects when a Service Instance is registered, or by Designers that use the Designer to create more advanced SmartObjects that interact with Service Objects. Eventually, these SmartObjects are used in the consuming applications. Note that the consuming application does not need to know anything about the underlying provider to use the SmartObject.
When a SmartObject is executed at runtime, K2 calls the Service Type's onexecute method, passing in the name of the Service Object and which method was called, along with any method parameters and properties. The Service Type code will then typically direct processing to a helper method based on which Service Object and which Service OBject Method was called.