I have a master application that accepts plugin modules, except for some functionality (authentication) where for some reason it seems hell-bent to prevent plugins from adding authentication methods. Despite that, I still need to do exactly that - add a new authentication method, but via a plugin.
The master application has a typescript module that exports an Authenticator class,
export class Authenticator {
constructor(arg) { dostuff(arg); }
}
I need to somehow intercept the constructor argument and store it in my plugin. The Authenticator class is instantiated in private code, but fortunately, after my plugin is initialized - so I get a chance to run some code; is there any way to dynamically modify the Authenticator class object (i.e. the class itself) so that I may capture the argument, when it is actually instantiated? Note that I can't use a decorator (I'd need to modify the main app), and I can't instantiate a proxy instead of the Authenticator (again, I would need to modify the main app in order to do so).
I've tried modifying Authenticator.constructor or Authenticator.prototype.constructor but neither works apparently. Is there any other way?
Related
I am trying to understand decorators which are not java's annotations but more like pre-processors in this article and I also found this SO question on setting info on a function. Let's say I have an interface like so
export default interface UserService {
#Path("/users/create")
#POST
createUser(user: CreateUserRequest): Promise<CreateUserResponse>;
#Path("/users/delete")
#POST
deleteUser(user: DeleteUserRequest): Promise<DeleteUserResponse>;
}
sidenote: It would be great to use this generated client in react UI as well as use in nodejs
I want my #Path and #POST, #GET to save info I can read and I think
class Path(path:string):
def __init__(self, path):
self.path = path
def __call__(self, func):
func.pathAnnotation = self
return func
I read I cannot loop over methods in an interface yet I would like to generate the http client that implements this interface so any API developers create, it automatically creates the implementation. (In java, we use the Proxy.java to generate an implementation). On server side, the controller implements the same exact API and I like to generate the 'scaffolding' meaning the http request to which endpoint to call if possible (not sure I can do that in nodejs just yet).
EDIT: An idea: Perhaps, I create an abstract class or class and every method throws an exception "Use XXXFactory to generate the implementation of this class". How do I loop over method in that class? and can I create classes that extend all these 'apis' at runtime such that I can inject him for everyone to use(like Proxy.java in java world)?
EDIT: perhaps I could do this in javascript with a prototype class somehow... generate all the methods to call a method with signature
Promise<Object> invoke(String method, object[] paramsToMethod);
Then, I can look up the method and #Path and #GET/#POST properties on that method. Can a prototype class extend a class in javascript such that any api defined (perhaps defined in typescript) is implemented by this one class? Then I have every api implemented by the same code for every microservice like we do in java? (This then means the platform team can swap protocols and developers do not care about protocols anymore like http, http2, binary, etc)
As per request, I have took some time to tinker around with reflection. The reflection is mostly needed to make the client automatically conform to what the service expects (type of parameters/return type), and I think it might be possible with reflect-metadata.
Ok so the idea is to have decorators store metadata about the method in a map, where a key is the class and the value is a collection of the methods with metadata.
Then where you get the client, it aggregates all the metadata for each method into one function that can be used.
It's a vague start but I think it can work. I actually might also turn this into a small snippet or library too if I have the time.
But actually, this should be a statically generated client, not a dynamic one. Because then it is far easier to validate and do the code generation.
Playground
manage-document.service.ts
WorkflowApprovalCallback(){
//subscribing to workflow event
this.makeAnEntryInDb(); // this is undefined
}
makeAnEntryInDb(){ //another function in same class}
workflow.service.ts
someWorkflowMethod(){
event.emit(data);
}
Both are in different classes and different modules. They are in no way related.
The problem is that when workflow service's someWorkflowMethod() is invoked it emits an event.
This is event is being listened to by the manage document service's WorkflowApprovalCallback(). I want to call makeAnEntryInDb() but then we do not have an instance of manage-document so this is undefiend.
If I create a new instance of manage-document class with new keyword I will have to manually create and provide the constructor dependencies. Also it may create multiple instances of manage-document
How can I provide manage-document context or what is the correct way of doing it?
I can not import manage-document service in workflow because there could be a lot of such services that may need to be imported in workflow. I want to keep workflow independent. Not having to make any changes anytime there is a new service.
So I have an external models/interfaces package published via npm, it is built using typegoose + mongoose, so I can have my interfaces in one place and then use the interfaces/models across multiple apps whilst also keeping them in sync.
Here's and example of a model/class.
Now the issue is, I'm making some dynamic tables on the frontend to work with either collection, so I'm trying to find a way to get the keys as strings whilst keeping it all dynamic in one place.
So far I've tried ts-transformer-keys but due to having to implement some stuff around compile-time, it won't work inside angular.
I also can't use the class directly into angular due to the class extending Typegoose which depends on mongoose which throws an error about some global thing and then crashes the whole app.
Where User is my class which extends Typegoose and IUser is the type from that class, things like:
class test extends User {}
still have mongo dependency error
class test implements User{}
still need to manually add all properties
Object.keys(User)
mongoose dependency will throw an error
Object.keys(IUser)
doesn't woork because type doesn't exist at runtime;
Perhaps a decorator on the class that loops over all the keys & adds the constructor name to the class prototype? That doesn't seem likely to be working at runtime.
For future readers, read this github issue, TL;DR: typegoose currently dosnt support clientside classes
My backend includes multiple microservices, each with its own base url. At the moment I have the user and the metadata services, but this could expand in the future.
I have a React app and I'm trying to create an API wrapper class to call when I need to modify something. My first approach was to create multiple api instances for each service and import as needed:
import userApi from '../userApi'
import metadataApi from '../metadataApi'
userApi.getUser(user_id)
metadataApi.getCollections()
But I'd like to use a different approach that wouldn't require keeping note where each entity is located in order to use it, like so:
import API from '../api'
API.getUser(user_id)
API.getCollections()
API.deleteUser(user_id)
But I'm not sure how I can achive this without bloating up the API class. Can I import an array of methods inside it and just attach them to the class prototype before exporting?
I want to find a suitable structure to better separate each entity and make it easier to build and modify it in the future.
To be honest, separating your API classes into separate files / modules is fine. It feels like a bit of an overhead when the app is small, but as it grows, it helps keeps things organised.
You have already indicated that your backend API's are structured into microservices, why not keep them separate entities in the front end too? It will be easier to manage your API classes when / if you ever come to start hitting different endpoints.
I have though, in the past, created a base class that each of those API classes may inherit from, where I can set up common logic, such as request headers etc, if you want to get some reuse that way.
I have even went a step further again which would create another level of abstraction that handles how the integration is happening, i.e. via HTTP, where I would declare which HTTP client to use for example. That way, if I ever change the HTTP client, I only change it in one place
That kind of structure looked like ->
_ServiceProxy.js
Common functions such as GET, POST, PUT, DELETE, etc.
HTTP client defined here
High level error handling defined here
_someBaseAPI.js
An an abstract client that would define how to interact with a set of common microservices, e.g. Auth logic etc
UserAPI.js
A concrete / static class, only interested in how to handle requests / responses to do with Users
You can define and export a separate component in which all api files will imported and use individual api in its functions, then you will be able to use its function for specific api.
Here's link from Ember API. Why is private. That's mean, that I shouldn't use it in my production?
You're misinterpreting the meaning of private, the Ember API page is referring to what functions the Ember API can call within your code. The definition of public and private methods is the same in every programming language, and their scope is also similar:
private - These methods can only be accessed within the method's class, for example, you cannot call the private method named transitionTo from the Ember.ArrayProxy class. You can however call transitionTo from a function or procedure inside the Ember.Route class.
public - These methods can be accessed from anywhere in your code, for example you will be able to call the public method named addObserver from any other class, hence the name 'public'
It should also be noted that use of some methods are discouraged; such methods are prefixed with an _ underscore.
These methods may be outdated, or generally be unsafe to use.
Thanks to Daniel for suggesting I add that in.