Depency Injection with "awilix" - javascript

I am learning dependecy injection using awilix. I tried the code below following a tutorial. I tried differently and each time I get the the kind of error below:
//diSetup.js:13
var config = _ref.config;
TypeError: Cannot read property 'config' of undefined
[Screenshot][1]
I tried the following:
const awilix = require("awilix");
const config = {
server: "8.8.8.8",
};
class UserController {
constructor({ config }) {
this.config = config;
}
}
const container = awilix.createContainer({
injectionMode: awilix.InjectionMode.PROXY,
});
container.register({
config: awilix.asValue(config),
userController: awilix.asClass(UserController),
});
function setup() {
const user = new UserController();
console.log(user.config);
}
module.exports = {
container,
setup,
};

You are creating a UserController instance in your setup function.
You shound use awilix resolve function instead. Try this:
const user = container.resolve("userController");

Related

TypeError: obj is not a constructor (error in js / node)

Note: I'm normally coding in Python, so I am completely new to javascript.
I'm trying to use the following repo: https://github.com/omerdn1/otter.ai-api
I used the setup code, but I replaced the import with the following instead: const OtterApi = require('otter.ai-api') because I was getting SyntaxError: Cannot use import statement outside a module.
However, now I'm getting the following error: TypeError: OtterApi is not a constructor. If I look at index.js in the repo, it does look like a constructor? First part of the code is:
class OtterApi {
constructor(options = {}) {
this.options = options;
this.user = {};
this.csrfToken = '';
}
init = async () => {
await this.#login();
};
The code I'm trying to run:
const OtterApi = require('otter.ai-api');
const otterApi = new OtterApi({
email: 'email', // Your otter.ai email
password: 'pw', // Your otter.ai password
});
async function main() {
await otterApi.init() // Performs login
}
main();
I get the error when using new OtterApi(). I'm not sure how to resolve this.
You need to refer to the "default" export:
const OtterApi = require('otter.ai-api').default;

How can I access methods inside a class from outside of class

I have a couple questions regarding Class files. I have the below Class
class CouchController {
constructor(couchbase, config) {
// You may either pass couchbase and config as params, or import directly into the controller
this.cluster = new couchbase.Cluster(config.cluster);
this.cluster.authenticate(config.userid, config.password);
this.bucket = cluster.openBucket(config.bucket);
this.N1qlQuery = couchbase.N1qlQuery;
}
doSomeQuery(queryString, callback) {
this.bucket.manager().createPrimaryIndex(function() {
this.bucket.query(
this.N1qlQuery.fromString("SELECT * FROM bucketname WHERE $1 in interests LIMIT 1"),
[queryString],
callback(err, result)
)
});
}
}
my problem is how can I go and access the doSomeQuery function from outside the class file? Inside there is no issue accessing the function but I need to be able to call it from outside.
I tried something like this
const CouchController = require("../controllers/CouchController")(couchbase, config)
let newTest = new CouchController
doing so newTest never exposes the doSomeQuery method.
Also what are the limitations of a method ? Can it only be a simple one or can it be async and use promises etc ?
There are 2 main things that you should consider with the following problem.
Export it properly first. I'm not sure if you meant to leave this out, but it's important to export the class for use outside as a require. Here is the NodeJS exports documentation if you wish for the technical details.
// common module default export
module.exports = class CouchController {
constructor(couchbase, config) {
// You may either pass couchbase and config as params, or import directly into the controller
this.cluster = new couchbase.Cluster(config.cluster);
this.cluster.authenticate(config.userid, config.password);
this.bucket = cluster.openBucket(config.bucket);
this.N1qlQuery = couchbase.N1qlQuery;
}
doSomeQuery(queryString, callback) {
this.bucket.manager().createPrimaryIndex(function() {
this.bucket.query(
this.N1qlQuery.fromString("SELECT * FROM bucketname WHERE $1 in interests LIMIT 1"),
[queryString],
callback(err, result)
)
});
}
}
The class initialization is slightly incorrect. You can see the docs on this here. You can change your require and initialization to...
const CouchController = require('../controllers/CouchController');
const newTest = new CouchController(couchbase, config);
// now you can access the function :)
newTest.doSomeQuery("query it up", () => {
// here is your callback
})
If you were using ES6 modules or typescript you could export something like...
export default class CouchController {
// ...
}
... and import something like...
import CouchController from '../controllers/CouchController';
const newTest = new CouchController(couchbase, config);
You need to instantiate the class after importing it
Change the following
const CouchController = require("../controllers/CouchController")(couchbase, config)
let newTest = new CouchController
to
const CouchController = require("../controllers/CouchController")
let newTest = new CouchController(couchbase, config)
Also you need to export your class like this
export default class CouchController {
and then access method like this
newTest.doSomeQuery(...)
I figured it out after some forth and back, part of my problem was the fact that for some reason visual studio code did not show me the method which threw me off. Manually typing made it ultimately avail.
Here is my Class and i actually moved the config and couchbase itself into the class file so no need to pass it anymore.
const couchbase = require("couchbase")
const config = require("../config/config")
class CouchController {
constructor() {
// You may either pass couchbase and config as params, or import directly into the controller
this.cluster = new couchbase.Cluster(config.cluster);
this.cluster.authenticate(config.userid, config.password);
this.bucket = this.cluster.openBucket(config.bucket);
this.N1qlQuery = couchbase.N1qlQuery;
}
getDoc2(docID){
return new Promise((resolve,reject)=>{
this.bucket.get(docID ,(err, result)=>{
if(err) return reject(err);
return resolve({docID,result});
});
});
}
}
module.exports = CouchController
And here is how i call my Class now and connect to the backend to fetch my data.
const CouchController = require("./controllers/CouchController")
let newTest = new CouchController
const test= async()=>{
let { docID, result } = await newTest.getDoc2("grid_info::20b05192-79e9-4e9d-94c9-91a4fc0a2765")
console.log(docID)
console.log(result)
}

Raven throws warnings when testing via Jest

I'm trying to test my GraphQL api through Jest and every time I run my tests I keep getting this alert:
raven#2.5.0 alert: This looks like a browser environment; are you sure you don't want Raven.js for browser JavaScript?
The cause:
I create a custom Error class that inherits from Error:
import logError from './errors';
class LoggedErrorClass extends Error {
constructor(error) {
logError(error);
const prototype = new.target.prototype;
if (typeof error === 'string') {
super(error);
} else {
super(error.message);
}
this.__proto__ = prototype;
}
}
LoggedError = LoggedErrorClass;
And use it like this:
if (!user || !Roles.userIsInRole(user._id, ['admin', 'customer'])) {
throw new LoggedError('Access denied');
}
logError is a function that uses Raven. Because I use Meteor I do LoggedError = LoggedErrorClass to make LoggedError accessible globally (notice, I don't export LoggedErrorClass)
My test looks like this:
import { graphql } from 'graphql';
import schema from '../../../graphql';
describe('getMobileSettings query', function() {
// global.LoggedError = class extends Error {
// constructor(...args) {
// super(...args);
// Error.captureStackTrace(this, Error);
// }
// };
it('should work', async () => {
const query = `
query getMobileSettings($app: String!) {
getMobileSettings(app: $app)
}`;
const [rootValue, context, params] = [{}, {}, { app: 'web' }];
await graphql(schema, query, rootValue, context, params);
});
});
I've tried setting LoggedError with the help of global but it didn't help. So, I can't just call jest.mock('path/to/file') because I don't export it. Also, it seems quite weird that Raven is here, because I use it in logError which I only import in a file where I create LoggedErrorClass
Ok, after some digging, I figured out the solution.
I decided not to mock LoggedError class but rather mock logError function that my class uses. As a result I came up with this code that mocks Raven behaviour:
const Raven = {};
const install = jest.fn();
const config = jest.fn();
Raven.install = install;
Raven.config = config;
// mocking chained function calls
install.mockImplementation((...args) => {
return Raven;
});
config.mockImplementation((...args) => {
return Raven;
});
export default Raven;
I've also updated my jest.conf.js by adding raven to moduleNameMapper:
module.exports = {
moduleNameMapper: {
'^meteor/(.*)': '<rootDir>/tests/.mocks/meteor/index.js',
raven: '<rootDir>/tests/.mocks/npm/raven.js',
},
automock: false,
clearMocks: true,
};

Objection.js - Query builder not a function using insert method

I'm new to nodejs Development and I currently practicing CRUD operations on my postgresql. I used Objection.js for the ORM and Model making. I follow some codes from the docs and edit necessary lines but I don't actually get it to success instead it returns this error:
builder.knex(...).queryBuilder is not a function
I am following MVC pattern so I seperate the files according to it.
My controller:
'use strict';
const Todo = require('./../models/Todo');
class TodoController {
createTodo() {
Todo
.query()
.insert({
'title': 'asdasdasda',
'description': 'sdasdasdasdasdsad',
'date': '2017-12-12',
'isActive': true,
})
.then(name => {
console.log(name.description);
})
.catch(err => {
console.log(err);
});
}
}
module.exports = TodoController;
Knex Schema:
knex.schema.createTableIfNotExists('todo', (table) => {
table.increments();
table.string('title', 255).notNullable();
table.text('description').notNullable();
table.boolean('isActive').defaultTo('false');
table.datetime('date').notNullable();
table.timestamp('createdAt').defaultTo(knex.fn.now());
})
Model:
'use strict';
const { Model } = require('objection');
class Todo extends Model {
static get tableName() {
return 'Todo';
}
}
module.exports = Todo;
server.js:
...
const KnexConfig = require('./knexfile');
const { Model } = require('objection');
...
...
Model.knex(KnexConfig.development);
Hopefully someone could guide me, I'm still newbie on nodejs
It looks like you're trying to pass the knex configuration object to Model.knex() whereas you need to pass the actual knex instance.
On server.js:
const { Model } = require('objection');
const knex = require('knex');
const KnexConfig = require('./knexfile');
Model.knex(knex(KnexConfig.development));
This error message seems to arise whenever the knex instance passed to Objection.js is not what is should be.

Property in class is undefined when used in class method

Writing a test REST api with NodeJs for learning purposes.
Currently I only have 1 route which accepts a parameter (which works fine).
I'm using an express router to route the GET request to my controller.
All of the routing is working as expected.
My ServiceController currently has a ctor function which accepts 2 parameters. Both of these parameters are passed into the ctor function by the router during instantiation.
In the ServiceController ctor I store the parameters in to fields.
The issue is, when I try to access these fields in a class method I'm getting a "TypeError: Cannot read property 'exec' of undefined".
I did write both of these values to the console to ensure that the ServiceController was receiving these values correctly (which it is).
So, i'm unsure why im getting this error when I attempt to access either "this.exec" or "this.logger" in the get method.
Router
import express from 'express';
import { exec } from 'child-process-promise';
import ServiceController from '../controllers/serviceController';
let routes = (logger) => {
const router = express.Router();
let controller = new ServiceController(exec, logger);
router.route('/status/:name')
.get(controller.get);
return router;
};
module.exports = routes;
ServiceController
export default class ServiceController {
constructor(childProcess, logger) {
this.logger = logger;
this.exec = childProcess;
}
get(req, res) {
if (!req.params.name) {
res.status(400).send('A service name was not provided');
} else {
this.exec(`sc query ${req.params.name}`).then(result => {
if (result.stderr) {
this.logger.log.warn(`stderr: ${result.stderr}`);
}
const regex = /STATE\s+:\s+\d+\s+(\w+)/;
let [, status] = result.stdout.toString().match(regex);
if (!status) {
throw new Error('Status query unsuccessful');
}
let service = {
name: req.params.name,
status: status
};
res.json(service);
return service;
}).catch(error => {
this.logger.log.error(`${error.name} ${error.message}`);
res.status(500).send('An error occurred while executing command');
});
}
}
}
It's a problem of this context. You use the get method on a context which is not your ServiceController instance.
Bind the method on your instance:
router.route('/status/:name')
.get(controller.get.bind(controller));
Or you can also define an arrow function in the ServiceController class.

Categories