Application Configurations

Overview

Appirator applications are made from a mix of resource class definitions, events and their associated handlers. Each class can have its own configuration, can have properties that are primitive or are complex, using other class definitions. Classes additionally have methods, event handlers, migrations, access rules, validation, modifiers and more.

Resource classes are very powerful in their own right and there is essentially no limit to what can be done with them and how complex applications and APIs can be built using them. Resource objects are instances of resource classes. These are normally stored somewhere, either within the internal store or within an external store. But they don’t have to be stored. The ability to store resource objects in multiple ways means that resource classes can come in several configurations. These can be seen below.

Simple Resource

The simplest resource class is one that has no logic and no event handling. The resource uses simple CRUD rules and its resource objects are stored in the Appirator internal store. A resource class of this nature can be configured and published in a matter of minutes.

img

Complex Resources

While it is recommended that resource classes be kept simple, Appirator allows you to make them as complex as you need them to be. Classes support event handling, access rules, validation and much more.

Every CRUD operation on a resource object causes an event to be generated for that object. These events are handled on the resource class or globally. Event handlers can be synchronous or asynchronous. Larger applications and APIs require event handlers to perform their background processing, to ensure that API response times are minimised and to provide a guarantee that asynchronous orchestration logic is performed correctly. Such background processing invariably creates other resource objects that are stored as needed, as well as non-persistent objects that are used as transient event objects.

img

External Stores and Proxies

By default, resource classes are stored in the Appirator internal store. They can be optionally stored in any other store that has been built for the resource class using the Store type.

Stores and proxies within Appirator are essentially the same thing. Stores need to handle CRUD operations for their resource classes and they can use practically any protocol under the hood, including a simple replay of the resource object against an external REST endpoint. By using an external REST API as a store, the store is effectively a REST proxy. Because stores are high customisable, developers can use more than one external endpoint in them and it is therefore possible to have a single resource object in Appirator that binds to multiple external endpoints for its data.

Custom stores also need to handle their own identifiers and these identifiers are the identifiers that are used in the inbound API URLs.

img

Applications can use a mix of resource class stores, including the default internal store, any number or combination of external custom stores, hybrid stores and no storage.

Hybrid Stores

A hybrid store is a special class of store used in Appirator where parts of a resource object are stored in the internal store and parts are stored in one or more custom external stores. There are a number of reasons why such a scenario might be used, for example an enterprise may have an existing API that for business reasons can’t be extended so they create an extended model with Appirator that uses their existing API for its main data and Appirator’s internal store for the extended data.

img

There are several important caveats when using hybrid stores:

  1. The resource object identifiers used in inbound URLs belong to the internal store. If external endpoints require a different identifier, the other identifier can be added as a property to the resource class and if this should not be exposed over the API, that identifier can be hidden using a protected modifier or property access rule.
  2. Updates made to all stores occur within the initiating request. This does not necessarily mean that the updates occur synchronously (it is possible to get some parallelisation applied), but it does mean that the individual update response times dictate the overall response time of the request.
  3. The CRUD operations made between independent stores are not transactionalised, so it is possible for a failure to arise that results in one store getting data stored and the other(s) not.

No Storage

Resource objects don’t need to be stored at all. Sometimes they’re just used to initiate an event flow within the application. In order to make a resource object non-persisting, the resource class simply needs to be marked as such. When resource classes are non-persisting, only one operation is allowed on them - CREATE. Synchronous and asynchronous event handling is still possible on the object, however, because the object is not stored, every asynchronous event handler effectively receives its own copy of the event and every synchronous event handler uses a shared object.

img

Some examples of where non-persisting resource objects are used are:

  • Git notifications. Appirator uses notifications from a linked Git repository in order to trigger a pull from the repository for automated builds. The Git notification triggers the creation of a new git.Notification object, which is non-persisting. It’s only purpose is to create a PullRequest object asynchronously which itself has an asynchronously CREATE handler that performs the Git pull and build. See Development via Git for more detail about this process.
  • Password resets. For security reasons, Appirator does not permit passwords to be updated directly on its user objects, rather it uses a password reset request mechanism. A non-persisting PasswordReset object is created (over the Appirator API normally) and within its asynchronous CREATE handler a email notification is created for the associated user with a generated code in a link. The user clicks the link which commences a password reset exchange.