I've been struggling to come up with this system architecture for a while now and got to a point where I thought it was perfect. The whole specification is fairly straightforward. We have something called an Extensions
, holding core functionalities to interact with an API:
export abstract class Extension<ConfigType extends object, DataType extends object> {
constructor(public definition: ExtensionDefinition<ConfigType, DataType>) {
this.definition = definition;
}
abstract initilize(): this;
abstract APIFetchSessionByID(sessionId: string) : Promise<ExtensionSession<ConfigType, DataType>>;
abstract APIFetchSessionByToken(token: string) : Promise<ExtensionSession<ConfigType, DataType>>;
abstract doSomethingAmazing() : any;
}
We then come into the main problem known as the ExtensionDefinition
, holding the raw JSON data about the the extension we are creating: configuration
, data
, name
, description
....
export class ExtensionDefinition<ConfigType extends object, DataType extends object> implements IExtensionProperties<ConfigType, DataType> {
constructor(data: IExtensionProperties<ConfigType, DataType>) {
Object.assign(this, data);
}
}
The problem occurs when we realise that the data passed in the ExtensionDefinition
is asynchronous and stored on a third-party API and only needs to be obtained once or until the definition is changed. My current solution stores this data in a .JSON and I simply pass the data from the JSON file directly into the ExtensionDefinition
constructor where I plan on updating the third-party API on start-up. This works but causes lots more errors than it solves. For example, the ExtensionDefinition
data retrieved from the API is configurable via the API so if anything new is introduce, a fix needs to be implemented.
For further context, I have a service that manages and maintains all these extensions:
APIApplication.initilize({
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
devToken: process.env.DEV_TOKEN!,
tokenURL: "...URL",
authorizationURL: "...URL",
extensions: [
new ExampleExtension(),
new ExampleExtension(),
new ExampleExtension(),
...MORE
]
});
A lot of other workarounds ive thought of have worked better but get slowed down by JavaScript inability to await asynchronous data in a class constructor. Some include passing the ExtensionDefinition
as a promise and awaiting the property when needed which works but isnt ideal as I would need to obtain each definition individually from the API, resulting in a lot of overhead.
The entire application depends on these extensions so without them it wouldnt function. I can imagine this is a common problem that many developers have encountered and may have already tackled this problem and come up with a better solution.