How to access the .setup function on a feather-sequelize object? - javascript

I want to nest a service behind another one, just as described in the FAQ and this issue
As I understood, you need the .setup property to get access to the app object, on which you can add a listener that you link to your service. So far so good.
However, the service I would need to do that on is not a custom service, on which the setup property is readily available, but a feathers-sequelize service, which seems to be built else where, the .class.js is not even present.
Searching around, I ve seen you can still access the property with the protoype, but not I am reticent in modifying it without knowing it to be something supported.
TL:DR: How to nest a feather-sequelize service behind another one?

You can extend the existing Sequelize ES6 class as documented here:
const { Service } = require( 'feathers-sequelize');
class MyService extends Service {
setup(app, path) {
this.app = app;
// Do stuff here
}
}
app.use('/todos', new MyService({
paginate: {
default: 2,
max: 4
}
}));

Related

Registering service with constructor arguments using tsyringe

I have a service to handle some data-fetching and I am trying to use tsyringe with it, the function to create the service gets called multiple times (i cant really do anything about that), so it is creating many instances of the service. I tried to wrap it in "container.isRegistered" checks, but when I do that it doesn't register the service at all.
What I have so far is:
#singleton()
#injectable()
export class Service implements IService {
constructor(#inject('arg1') arg1: string, #inject('arg2') arg2: string) {
}
Then I am registering it here in another file:
if (!container.isRegistered('arg1', true)) {
container.register('arg1', {useValue: this.arg1});
}
if (!container.isRegistered('arg2', true)) {
container.register('arg2', {useValue: this.arg2});
}
if (!container.isRegistered('IService', true)) {
container.register('IService', {useClass: Service});
}
In another file I resolve it like so:
this.service = container.resolve('IService');
Trying to check if it is registered stops the Service from being registered at all, but if I don't I have multiple instances running. The service mainly handles data-fetching, it's only supposed to fetch some data once on startup but I am seeing many calls that do so. I put some logs in the service constructor and I can see it being created many times.
Thanks for your help!
When you are creating new registry in IoC using method register, in fact you create another link on service that doesn't related to your decorator #singlton inside of class. You need set additional parameter in the register method. It will describe lifecycle of injectable object. Because be default it doesn't use Singleton. You should do this like that:
import { container, autoInjectable, Lifecycle } from 'tsyringe';
...
container.register<UsersService>('IService', {useClass: UsersService}, { lifecycle: Lifecycle.Singleton } );
More info here and types here

AngularJS 1.8 and ES6 modules: how to make an service or factory that "passes through" a class based API interface?

I am gradually improving a codebase that originally had some AngularJs in various versions and some code that was not in a framework at all using various versions of a software API. (For some reason this API is available - to pages loaded through the application - on AngularJS's $window.external...go figure.)
In my pre-ES6, AngularJs 1.8 phase, I have three services that interact with the software's API (call them someAPIget, someAPIset, and someAPIforms). Something like this:
// someAPIget.service.js
;(function () {
var APIget = function ($window, helperfunctions) {
function someFunc (param) {
// Do something with $window.external.someExternalFunc
return doSomethingWith(param)
}
return {
someFunc: someFunc
}
}
angular.module('someAPIModule').factory('someAPIget', ['$window', 'helperfunctions', someAPIget])
})()
I then had a service and module a level up from this, with someAPIModule as a dependency, that aggregated these functions and passed them through under one name, like this:
// apiinterface.service.js
;(function () {
// Change these lines to switch which API service all functions will use.
var APIget = 'someAPIget'
var APIset = 'someAPIset'
var APIforms = 'someAPIforms'
var APIInterface = function (APIget, APIset, APIforms) {
return {
someFunc: APIget.someFunc,
someSettingFunc: APIset.someSettingFunc,
someFormLoadingFunc: APIforms.someFormLoadingFunc
}
}
angular.module('APIInterface').factory('APIInterface', [APIget, APIset, APIforms, APIInterface])
})()
I would then call these functions in various other controllers and services by using APIInterface.someFunc(etc). It worked fine, and if we switch to a different software provider, we can use our same pages without rewriting everything, just the interface logic.
However, I'm trying to upgrade to Typescript and ES6 so I can use import and export and build some logic accessible via command line, plus prepare for upgrading to Angular 11 or whatever the latest version is when I'm ready to do it. So I rebuilt someAPIget to a class:
// someAPIget.service.ts
export class someAPIget {
private readonly $window
private readonly helperfunctions
static $inject = ['$window', 'helperfunctions']
constructor ($window, helperfunctions) {
this.$window = $window
this.helperfunctions = helperfunctions
}
someFunc (param) {
// Do something with this.$window.external.someExternalFunc
return doSomethingWith(param)
}
}
}
angular
.module('someAPImodule')
.service('someAPIget', ['$window', 'helperfunctions', someAPIget])
Initially it seemed like it worked (my tests still pass, or at least after a bit of cleanup in the Typescript compilation department they do), but then when I load it into the live app... this.$window is not defined. If, however, I use a direct dependency and call someAPIget.someFunc(param) instead of through APIInterface.someFunc(param) it works fine (but I really don't want to rewrite thousands of lines of code using APIInterface for the calls, plus it will moot the whole point of wrapping it in an interface to begin with). I've tried making APIInterface into a class and assigning getters for every function that return the imported function, but $window still isn't defined. Using console.log statements I can see that this.$window is defined inside someFunc itself, and it's defined inside the getter in APIInterface, but from what I can tell when I try to call it using APIInterface it's calling it without first running the constructor on someAPIget, even if I make sure to use $onInit() for the relevant calls.
I feel like I am missing something simple here. Is there some way to properly aggregate and rename these functions to use throughout my program? How do alias them correctly to a post-constructed version?
Edit to add: I have tried with someAPIget as both a factory and a service, and APIInterface as both a factory and a service, and by calling APIInterface in the .run() of the overall app.module.ts file, none of which works. (The last one just changes the location of the undefined error.)
Edit again: I have also tried using static for such a case, which is somewhat obviously wrong, but then at least I get the helpful error highlight in VSCode of Property 'someProp' is used before its initialization.ts(2729).
How exactly are you supposed to use a property that is assigned in the constructor? How can I force AngularJS to execute the constructor before attempting to access the class's members?
I am not at all convinced that I found an optimal or "correct" solution, but I did find one that works, which I'll share here in case it helps anyone else.
I ended up calling each imported function in a class method of the same name on the APIInterface class, something like this:
// apiinterface.service.ts
// Change these lines to switch which API service all functions will use.
const APIget = 'someAPIget'
const APIset = 'someAPIset'
const APIforms = 'someAPIforms'
export class APIInterface {
private readonly APIget
private readonly APIset
private readonly APIforms
constructor (APIget, APIset, APIforms) {
this.APIget = APIget
this.APIset = APIset
this.APIforms = APIforms
}
someFunc(param: string): string {
return this.APIget.someFunc(param)
}
someSettingFunc(param: string): string {
return this.APIset.someSettingFunc(param)
}
someFormLoadingFunc(param: string): string {
return this.APIforms.someFormLoadingFunc(param)
}
}
angular
.module('APIInterface')
.factory('APIInterface', [APIget, APIset, APIforms, APIInterface])
It feels hacky to me, but it does work.
Later Update:
I am now using Angular12, not AngularJS, so some details may be a bit different. Lately I have been looking at using the public-api.ts file that Angular12 generates to accomplish the same thing (ie, export { someAPIget as APIget } from './filename' but have not yet experimented with this, since it would still require either consolidating my functions somehow or rewriting the code that consumes them to use one of three possible solutions. It would be nice not to have to duplicate function signatures and doc strings however. It's still a question I'm trying to answer more effectively, I will update again if I find something that really works.

Using singleton design pattern for better code quality

We have a node-express app with multiple endpoints. We have created 5 different services that does different jobs such as making HTTP calls, process/modify data, cache data, search specific data, etc.
We realized that the services we created are not singleton. The services were being instantiated left right and center. A total of 26 objects were being created.
We changed that and made all our services singleton, and now only 5 objects get created across the entire application. We want to structure the app properly now.
We want each express route to call DataService (which checks if that data is available in the CacheService, if not then make an HTTP call and store the data in cache and return the data to the express route).
But, the current code makes use of CacheService and DataService together to check if the data is available in the cache or fetches fresh data using DataService. Which approach is recommended? Use one service (Dataservice) that internally uses multiple services (CacheService, DataModificationService), or use all the services together in the express route (DataService, CacheService, DataModificationService)
Before making the classes singleton, we were using static classes. Do we even need to make services singleton or continue to use static classes? Which one is more recommended and why?
Here's the code that we've written to create a Singleton Service . Is this the correct way?
class DataService {
private dataModificationService: DataModificationService;
private tokenService: TokenService;
private constructor(tokenService: TokenService, dataModificationService: DataModificationService) {
this.tokenService = tokenService;
this.dataModificationService = dataModificationService;
}
public static getInstance(): DataService {
const dataModificationService: DataModificationService = DataModificationService.getInstance();
const tokenService: TokenService = TokenService.getInstance();
if (!DataService.instance) {
DataService.instance = new DataService(tokenService, dataModificationService);
}
return DataService.instance;
}
}
It's good that you've reduced the number of singletons. Now try and get rid of the rest!
Changing from a static class to a singleton object often makes no difference - they're both just ways of making stuff global.
What you need to be doing is looking at how many places use each singleton, and if the usages are localised, then try to replace the singleton with dependency injection. Nothing fancy, just pass the (non static) instance of the DataService or whatever in as a parameter where needed. If that would create too much code, then what you've done is perfectly fine.

Class and scope in ember js

Im building an ember application consuming a couple of web services. And I'm trying to pass a class object throw the config/environment file doing this:
var myclass = require('myclass-package');
var ENV = {
APP: {
MY_OBJ_CLASS: new myclass({
//CONSTRUCTOR PARAMS...
PROP1: "HELLO"
})
}
}
In my ember app/controllers I'm doing this:
import ENV from '../config/environment';
var obj1 = ENV.APP.MY_OBJ_CLASS;
I can see that the object is instantiated if I console.log the class object but when I try to access to the properties and functions, I can't and I get back this error:
var data = obj1.my_function_class({param1:1});
console.log(data)
TypeError: obj1.my_function_class is not a function
But the function exist...
What is the way to access to my class properties and functions?
config/environment.js is a special file. It is executed in Node, then serialized to be made available for the browser app.
You should not store any functionality in that file.
Put your class into a proper Ember module. Depending on what you're trying to achieve, that could be a service, a model, an util, etc.
Provide more details on your original problem, not your attempted solution. See http://xyproblem.info .

Ember.js - What is the best way to store application specific data in ember?

I need to access the application specific data in my components as well as routes. I also need to set the application specific data from normal JS.
I have currently created an object with global namespaces (App.globalSetting) and then created the variables as properties on this object.
I am then able to set and get the variable using App.globalSetting.set() and App.globalSetting.get().
Is the above method a good practice or is there a better way to do the same.
Also the data to be stored is critical. So please suggest a best way to accomplish this task.
You may want to take a look at Services: http://guides.emberjs.com/v2.0.0/services/.
From the guides:
"An Ember.Service is a long-lived Ember object that can be injected as needed."
Example service:
settings-service.js
export default Ember.Service.extend({
exampleSetting: true,
update(value) {
this.set('exampleSetting', value);
}
});
How to access this service from a Component (or Route):
export default Ember.Component.extend({
settings: Ember.inject.service('settings-service'),
actions: {
doSomething(val) {
this.get('settings').update(val);
}
}
});

Categories