Tokamak Energy developed a quench resistant magnet

Tokamak Energy develops a quench resistant magnet .

More on APIs

  • By Artem V. Shamsutdinov
  • October 10th, 2021
Recently I got the inital implementation of application isolates working (in browser only, without pulling application code from remote location) and as part of that did a pass on API implementations.

Locking down APIs

One thing that is likely be needed in the future is the ability to differentiate between "Application APIs" and "External APIs". An Application developer should be able to lock down APIs to be either other Application facing or External facing (like web UI, or anything else not running in an App isolate).
This can be accomplished by adding more precision to the @Api decorator:
@Injectable()
export class AnApiClass {

    @Api({ applications: true, external: true})
    async anApi(): any {
        ...
    }        
}
                            
Current thinking is to leave the API wide open by default and allow the developers to lock it down as needed.

AIRport path

One of the tradeoffs that AIRport had to make is to give up some of the elegance when it comes to deleting records but instead not have to maintain a session.
I sent quite a bit of time developing with Hibernate (in Java world). It is a great piece of technology but one thing I never liked about it is the fact that entities can be attached and detached from the ORM session. For INSERTs vs UPDATEs AIRport got around this by maintaing an __originalValues__ property on each object retrieved from the database and diffing it with the passed in values on the "save" operation. But DELETEs cannot be just as easily maintained.

Ackward DELETEs

The best I can come with for deletes so far is the following:
  /*
   * Marks the object as deleted in 
   */
  markAsDeleted(record)

  /*
   * True if record is deleted, false otherwise
   */
  isDeleted(record)
                            
This API allows the developers to explicitly mark a given object as deleted and also detect if an object has been marked as deleted. This delete API is rather crude but purposely makes the "save" operation the segway for all entity based insert, update and delete operations ( there is also no explicit update for entity API). Of course the developers are always free to write explicit update and delete statements, expecially for bulk operations.

Rare deletes

It is worth noting that I don't exect deletes to be a common operation. There really shouldn't be much reason to delete records, expecially since they can be split into time bound Repositories and archived when no longer actively needed. On top of that in AIRport no data is really ever deleted since it is preseved in the transaction logs. Hence I don't exect high usage for the delete operation, just lots of archiving.

Locking down object state

Thinking about deletes made me realize that one more API lockdown can be added to @Api - ability to pass in Object State.
Object state is what keeps track of if the object has been deleted or not and what the original values of the object were. It is possible that the application developer wants to maintain all CRUD logic internally to the application (at least on certain APIs). If that's the case AIRport can accomidate that but scrubbing all object State when an API is called.
@Injectable()
export class AnApiClass {

    @Api({ objectState: true})
    async anApi(): any {
        ...
    }        
}
                            
Again the default will be to leave the API open to external modifications, at this point it is hard to determine what will likely be the most common scenario - direct modifications from modern think UIs or more traditional lockdown approach of server side development.

@SaveEntryPoint()

To build on top of initial application interability thoughts I'm proposing a new decorator to mark points where save operations can cascade. As a recap - save operations that cross application schema boundaries will call into the logic of the Applications that contain the schemas with nested objects. That way the application always has control over how the objects in it's schema get saved and can run the necessary validation logic to make sure that records are maintained in a proper order.

A accomplish this a new @SaveEntryPoint() decorator will be introduced. A method decorated with this decorator will always take an array of the corresponding entity objects and nothing else and there may only be one @EntitySave() method per entity type. This is necessary for the framework to make a determination what method to invoke for a given entity- if there is more than one than it becomes unclear what method to invoke. Note that for any given save operation, this acts as an entry point. The entire object sub-graph that belongs to this Application's schema will be processed without calling any other @SaveEntryPoint()s for nested objects.