Store request/reponse into a database table in NodeJS Express - javascript

I’m trying
to create a mini Wireshark/debuging playground
I want to store all the requests & responses that pass through my API Back End so I can leverage them to debug what was going on.
The main goal is to generate the logs table on a web page with the ability to export as JSON format.
I have
an API written in Node JS using Express connecting to Postgres Database via Sequelize
I have a lot a requests come through my API.
Here are an example my requests
POST /api/login
POST /api/getSessionTimeOut
POST /api/checkIfGroupExist/25050-telenet
POST /api/listUsersInGroup/25050-telenet
POST /api/primary/createVxLan/ingress/103
POST /api/primary/createVxLan/egress/103
POST /api/primary/createSwitch/103
POST /api/primary/createVxLan/ingress/104
POST /api/primary/createVxLan/egress/104
POST /api/primary/createSwitch/104
POST /api/backup/createVxLan/ingress/103
POST /api/backup/createVxLan/egress/103
POST /api/backup/createSwitch/103
POST /api/backup/createVxLan/ingress/104
POST /api/backup/createVxLan/egress/104
POST /api/backup/createSwitch/104
POST /api/primary/installDevice
POST /api/monitor/2724
...
POST /api/monitor/2724
POST /api/backup/installDevice
POST /api/monitor/2725
...
POST /api/monitor/2725
POST /api/createDynamicInterface/ingress/103
POST /api/createDynamicInterface/egress/103
POST /api/createDynamicInterface/ingress/104
POST /api/createDynamicInterface/egress/104
POST /api/createPolicyFirewall/v4/103/vpn
POST /api/createPolicyFirewall/v4/104/inline
POST /api/createPolicyFirewall/v4/103/inline
POST /api/createPolicyFirewall/v4/103/inline
POST /api/createPolicyFirewall/v6/103/vpn
POST /api/createPolicyFirewall/v6/103/inline
POST /api/createPolicyFirewall/v6/104/inline
POST /api/createPolicyFirewall/v6/103/inline
POST /api/installPackage/inline
POST /api/monitor/2726
...
POST /api/monitor/2726
POST /api/installPackage/vpn
POST /api/monitor/2727
...
POST /api/monitor/2727
I would like to store each request into a logs table in my database.
I’ve tried
Migration
module.exports = {
up: (queryInterface, Sequelize) =>
queryInterface.sequelize.query('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";')
.then(() => {
queryInterface.createTable('Logs', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.Sequelize.UUID,
defaultValue: Sequelize.literal('uuid_generate_v4()')
},
user: {
type: Sequelize.STRING,
allowNull: true
},
accountId: {
type: Sequelize.STRING,
allowNull: true
},
cpeMac: {
type: Sequelize.STRING,
allowNull: false
},
pHnsId: {
type: Sequelize.STRING,
allowNull: true
},
gHnsId: {
type: Sequelize.STRING,
allowNull: true
},
serviceType: {
type: Sequelize.STRING,
allowNull: true
},
securityCluster: {
type: Sequelize.STRING,
allowNull: true
},
method: {
type: Sequelize.STRING,
allowNull: true
},
portalUrl: {
type: Sequelize.STRING,
allowNull: true
},
apiUrl: {
type: Sequelize.STRING,
allowNull: true
},
data: {
type: Sequelize.STRING,
allowNull: true
},
response: {
type: Sequelize.STRING,
allowNull: true
},
createdAt: {
type: Sequelize.DATE,
allowNull: false
},
updatedAt: {
type: Sequelize.DATE,
allowNull: false
},
deletedAt: {
type: Sequelize.DATE,
allowNull: true
}
})
}),
down: (queryInterface) => queryInterface.dropTable('Logs')
};
Model
module.exports = (sequelize, DataTypes) => {
const Log = sequelize.define('Log', {
user: {
type: DataTypes.STRING,
allowNull: true
},
accountId: {
type: DataTypes.STRING,
allowNull: true
},
cpeMac: {
type: DataTypes.STRING,
allowNull: false
},
pHnsId: {
type: DataTypes.STRING,
allowNull: true
},
gHnsId: {
type: DataTypes.STRING,
allowNull: true
},
serviceType: {
type: DataTypes.STRING,
allowNull: true
},
securityCluster: {
type: DataTypes.STRING,
allowNull: true
},
method: {
type: DataTypes.STRING,
allowNull: true
},
portalUrl: {
type: DataTypes.STRING,
allowNull: true
},
apiUrl: {
type: DataTypes.STRING,
allowNull: true
},
data: {
type: DataTypes.STRING,
allowNull: true
},
response: {
type: DataTypes.STRING,
allowNull: true
}
});
const schema = {
user: "user",
accountId: "accountId",
cpeMac: "cpeMac",
pHnsId: "pHnsId",
gHnsId: "gHnsId",
serviceType: "serviceType",
securityCluster: "securityCluster",
method: "method",
portalUrl: "portalUrl",
apiUrl: "apiUrl",
data: "data",
response: "response"
};
Log.list = (models) => new Transformer.List(models, schema).parse();
Log.single = (model) => new Transformer.Single(model, schema).parse();
return Log;
};
Controller
const Log = require('../models').Log;
module.exports = (config, jwtDecode, Op) => {
let logs = {};
/**
* Create a Log
*
* #return {object} log
*/
logs.create = async(req, res, next) => {
try {
let $body = {
name: log.name,
accountId: log.accountId,
cpeMac: log.cpeMac,
pHnsId: log.pHnsId,
gHnsId: log.gHnsId,
serviceType: log.serviceType,
securityCluster: log.securityCluster,
method: log.method,
portalUrl: log.portalUrl,
apiUrl: log.apiUrl,
data: log.data,
response: log.response
};
let response = await Log.create($body);
res.status(200).send(JSON.parse(response));
} catch (error) {
next(error);
}
};
return logs;
};
Service
module.exports = (config, request) => {
let log = {};
/*==============================
= create =
==============================*/
log.create = ($body) => {
let $options = {
method: "POST",
uri: `/api/logs/create`,
body: $body
};
return new Promise((resolve, reject) => {
request($options)
.then(data => resolve(JSON.stringify(data)))
.catch(error => reject(error));
});
};
return log;
};
route
app.post('/api/logs/create', controllers.logs.create);
Result
Now, that I have all of the pieces ready to go, but I am not sure how to connect all of these to be able to store all the requests/responses in the database?

As a basic outline for creating this as middleware, you would do something like this:
App.js
/* You're imports and setup */
/*
any time a call is made, it will hit this function
app.use accepts a function, which will give the parameters
req, res, next.
i.e. app.use((req, res, next) => { ... })
so we'll pass in you're logs.create function
and the request will have all the information on what
endpoint is being given.
*/
app.use(controllers.logs.create)
/* the rest of your routes */
If you provide your app.js file, I can give you a better version of what is above
Let me know if there is anything else I can do.

Related

Generated table using belongstomany is not associated with any table

I have three tables companies, subscriptions and companySubscription. As name defined company can canbuy/have plan or one subscription belongs to many companies.
So in model/schema I have defined as follows:
companies.js
const sequelize = require("../utils/database");
const bcrypt = require("bcrypt");
const { DataTypes, Model } = require("sequelize");
const subscription = require("./subscriptions");
const CompanySubscription = require("./companySubscription");
class companies extends Model {}
companies.init(
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
},
contactNo: {
type: DataTypes.STRING,
allowNull: true,
},
companySize: {
type: DataTypes.INTEGER,
allowNull: true,
},
},
{ sequelize, modelName: "companies" }
);
subscription.belongsToMany(companies, { through: CompanySubscription });
module.exports = companies;
subscription.js
const sequelize = require("../utils/database");
const { DataTypes, Model } = require("sequelize");
class subscription extends Model {}
subscription.init(
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
subscriptionPlanType: {
type: DataTypes.ENUM,
values: ["Yearly", "Monthly"],
allowNull: false,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
memberCount: {
type: DataTypes.INTEGER,
allowNull: false,
},
amount: {
type: DataTypes.FLOAT,
allowNull: false,
},
},
{ sequelize, modelName: "subscription" }
);
module.exports = subscription;
companySubscription.js
const sequelize = require("../utils/database");
const companies = require("./companies");
const subscription = require("./subscriptions");
const { DataTypes, Model } = require("sequelize");
class CompanySubscription extends Model {}
CompanySubscription.init(
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
status: {
type: DataTypes.ENUM,
values: ["active", "inactive"],
},
subscriptionType: {
type: DataTypes.ENUM,
values: ["Yearly", "Monthly"],
},
subscriptionPlanStartDate: {
type: DataTypes.DATE,
},
subscriptionPlanEndDate: {
type: DataTypes.DATE,
},
paidStatus: {
type: DataTypes.ENUM,
values: ["paid", "unpaid"],
},
paidDate: {
type: DataTypes.DATE,
},
},
{ sequelize, modelName: "CompanySubscription" }
);
module.exports = CompanySubscription;
In controller file I am able to manage to insert the data. Below is the code:
const addBIlling = async (req, res) => {
const foundSubcscription = await subscription.create({
subscriptionPlanType: "Monthly",
name: "s1",
memberCount: 15,
amount: 50.55,
});
const foundCompany = await companies.create({
name: "company1",
email: "company1#gmail.com",
contactNo: "87964644",
companySize: 20,
});
const insertedData = await foundSubcscription.addCompany(foundCompany, {
through: {
status: "active",
paidStatus: "paid",
subscriptionType: "Monthly",
subscriptionPlanEndDate: moment().add(1, "months"),
paidDate: moment().add(1, "months"),
},
});
console.log("inserted data ", insertedData);
res.json({ data: insertedData });
};
Now I want to fetch the records from db as which company has bought which subscription plan!
i.e. company name, subscription plan and its active and paid status and plan's expiry date.
I tried below code:
const billingList = async (req, res) => {
const billingData = await CompanySubscription.findAll({
include: [{ model: companies }],
});
console.log("billing data ", billingData);
};
Above code is throwing error "companies is not associated to CompanySubscription!".
Where have I made a mistake?
Don't try to import models to each other's modules directly. Define model registration functions in each model module and use them all to register models in one place/module and for associations you can define associate function inside each registration function and call them after ALL your models are already registered. That way you won't have cyclic dependencies and all associations will be correct.
See my answer here to get an idea how to do it.

Sequilize Mysql Foreign Key is null

These are my models
Files
exports.models = File = sequelize.define("File", {
originalname: {
type: DataTypes.STRING,
allowNull: false,
},
destination: {
type: DataTypes.STRING,
allowNull: false,
},
filename: {
type: DataTypes.STRING,
allowNull: false,
},
path: {
type: DataTypes.STRING,
allowNull: false,
},
});
Sales
exports.models = Sales = sequelize.define("sales", {
OrderDate: {
type: DataTypes.STRING,
allowNull: false,
},
Region: {
type: DataTypes.STRING,
allowNull: false,
},
City: {
type: DataTypes.STRING,
allowNull: false,
},
Category: {
type: DataTypes.STRING,
allowNull: false,
},
Product: {
type: DataTypes.STRING,
allowNull: false,
},
Quantity: {
type: DataTypes.STRING,
allowNull: false,
},
UnitPrice: {
type: DataTypes.STRING,
allowNull: false,
},
TotalPrice: {
type: DataTypes.STRING,
allowNull: false,
},
});
and now I add the relation
await File.hasMany(Sales);
await Sales.belongsTo(File);
await sequelize
.sync({ force: true })
.then(async () => {
console.log("Database & tables created!");
})
.catch((err) => {
console.log("Error: " + err);
});
});
now with the sync method
the ORM Creates my Tables with all the columns that I have defined and additionally, it will create an id column in both the Sales and Files Tables automatically along with a FileID column in the Sales table as a foreign key
And Now
try {
await File.create(req.file);
} catch (err) {
console.log(err);
res
.status(500)
.json({ message: "Server Error File NOt Uploaded To Database" });
return;
}
try {
await Sales.bulkCreate(data);
} catch (error) {
console.log(error);
res
.status(500)
.json({ message: "Internal Server Error Data canot be uploaded" });
return;
}
when I try to insert data into my Database all the data is inserted correctly except for the foreign key which is null
I tried putting the NOT Null Constrain in there but after I do that the database returns an error which basically says that this table can not have this constrain
to my knowledge I have tried everything under sun and I really need help
Thank you in advance

Sequelize association not syncing with model definition

'use strict';
module.exports = (sequelize, type) => {
const article_comment = sequelize.define('article_comments', {
// attributes
id: {
type: type.INTEGER,
primaryKey: true,
autoIncrement: true
},
positive_rating:{
type: type.INTEGER,
allowNull: false
},
negative_rating:{
type: type.INTEGER,
allowNull: false
},
comment:{
type: type.STRING,
allowNull: false
},
updatedAt:{
type: type.STRING,
allowNull: false
},
createdAt:{
type: type.STRING,
allowNull: false
},
}, {});
article_comment.associate = function(models) {
// associations can be defined here
article_comment.hasMany(models.article_comments_user_ratings,{foreignKey:'comment_id'});
article_comment.hasMany(models.article_replies,{foreignKey:'comment_id'});
};
return article_comment;
};
And my rating for comments
'use strict';
module.exports = (sequelize, type) => {
const article_comments_user_ratings = sequelize.define('article_comments_user_ratings', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: type.INTEGER
},
rating:{
type: type.BOOLEAN,
allowNull: false
},
createdAt: {
allowNull: false,
type: type.DATE
},
updatedAt: {
allowNull: false,
type: type.DATE
}
}, {});
article_comments_user_ratings.associate = function(models) {
// associations can be defined here
article_comments_user_ratings.belongsTo(models.article_comments)
};
return article_comments_user_ratings;
};
However, when I use the findOrCreate method, it only does INSERT INTO "article_comments_user_ratings" ("id","rating","createdAt","updatedAt"). Which obviously is failing because In the database I also have the additional columns of user_id and comment_id for the article_comments_user_ratings table.
This isn't making any sense because with the sync() function, prior to moving to migrations, it was working.
I don't know what to do?
I fixed this issue by defining the associations after defining the model.
Example:
const User = UserModel(sequelize, Sequelize)
const Comment = CommentsModel(sequelize, Sequelize)
User.hasMany(UserCommentRating,{foreignKey:'user_id'})
Comment.hasMany(UserCommentRating,{foreignKey:'comment_id'})
It seems that the assocations inside the model is deprecated.

Associate in Sequelize not working as intended

I am trying to associate two tables in Sequelize but I am getting the SequelizeEagerLoadingError that one table is not associated to another despite trying all the available fixes on this platform.
I have two tables, User and Item.
User (user.js)
const User = dbconnection.sequelize.define('users', {
id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true},
name: {
type: Sequelize.STRING(80),
allowNull: false
},
email: {
type: Sequelize.STRING(120),
allowNull: false,
unique: true
},
dob: {
type: Sequelize.DATEONLY,
allowNull: false
},
password: {
type: Sequelize.STRING(256),
allowNull: false
}
});
User.associate = models => {
User.hasMany(models.Item, { as: 'items',foreignKey: 'user_id' })
}
dbconnection.sequelize.sync({ force: false })
.then(() => {
//console.log('Table created!')
});
module.exports = {
User
};
Item (item.js)
const Item = dbconnection.sequelize.define('items', {
id: { type: Sequelize.INTEGER, unique: true, autoIncrement: true, primaryKey: true},
item: {
type: Sequelize.STRING(80),
allowNull: true
},
item_type: {
type: Sequelize.STRING(10),
allowNull: false
},
comment: {
type: Sequelize.STRING(1000),
allowNull: true
},
user_id: {
type: Sequelize.INTEGER,
allowNull: false,
references: { model: 'users', key: 'id' }
},
});
Item.associate = models => {
Item.belongsTo(models.User, { as: 'users',foreignKey: 'user_id' })
}
dbconnection.sequelize.sync({ force: false })
.then(() => {
// console.log('Table created!')
})
});
module.exports = {
Item
};
User hasMany(Item) while Item belongsTo(User) as shown above.
However, when I make a query to the Item table (as below),
const usersdb = require('./userdb')
const itemsdb = require('./itemdb')
class ItemsController {
static async getAllItems(req, res, next) {
try{
let allitems = await itemsdb.Item.findAll({
include: [{
model: usersdb.User
}]
})
return {items: allitems, status: true}
}
catch (e) {
return {items: e, status: false}
}
}
}
module.exports = ItemsController;
I get the SequelizeEagerLoadingError that "users is not associated to items!"
I have tried all the available fixes including this and this among others but to no success.
I have finally found a workaround. First, I dropped the tables and discarded the model definitions. Second, I generated migrations and models using the sequelize model:create --name ModelName --attributes columnName:columnType command. I then used the generated models to associate the two tables just as I had done earlier. Lastly, I ran the sequelize db:migrate command to create the tables and on running the query, it worked!
Earlier, I was creating the models manually. I was also creating the tables using the sequelize.sync({force: false/true}) command after loading the models.
User Model (user.js)
'use strict';
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
email: {
type: DataTypes(120),
allowNull: false,
unique: true
},
dob: {
type: DataTypes.DATEONLY,
allowNull: false
},
password: {
type: DataTypes.STRING(256),
allowNull: false
}
}, {});
User.associate = function(models) {
User.hasMany(models.Item, {as: 'Item', foreignKey: 'user_id'})
};
return User;
};
Item model (item.js)
'use strict';
module.exports = (sequelize, DataTypes) => {
const Item = sequelize.define('Item', {
item: {
type: DataTypes.STRING(80),
allowNull: true
},
item_type: {
type: DataTypes.STRING(10),
allowNull: false
},
comment: {
type: DataTypes.STRING(1000),
allowNull: true
},
user_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: { model: 'User', key: 'id' }
}
}, {});
Item.associate = function(models) {
Item.belongsTo(models.User, { as: 'User',foreignKey: 'user_id' })
};
return Item;
};
Query (queryitem.js)
const Item = require('../models').Item
const User = require('../models').User
class ItemsController {
static async getAllItems() {
try{
let allitems = await Item.findAll({
include: [{
model: User,
as: 'User'
}]
})
return {items: allitems, status: true}
}
catch (e) {
return {items: e, status: false}
}
}
}
module.exports = ItemsController;

Sequelize: TypeError: User.hasMany is not a function

I am having this weird behavior.
I have a User model, and a Client model. User has many Clients.
I am using this docs: http://docs.sequelizejs.com/manual/tutorial/associations.html
When I run the server, Sequelize throws TypeError: User.hasMany is not a function
Node version: 8.9.1
Dialect: postgres
Database version: Postgres 10
Sequelize version: 4.22.15
The following files are all in the same folder
user.js model
const Sequelize = require('sequelize');
const db = require('../index.js'); //This is an instance of new Sequelize(...)
const tableName = 'users';
const User = db.define('user', {
firstName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
lastName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
username: { //Username will be the email
type: Sequelize.STRING(80),
allowNull: false,
unique: true,
validate: {
isEmail: true
}
},
password: {
type: Sequelize.STRING,
allowNull: false,
validate: {
notEmpty: true
}
},
isAdmin: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
},
isActive: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
}
}, { tableName });
module.exports = User;
client.js model
'use strict'
const Sequelize = require('sequelize');
const db = require('../index.js');
const instanceMethods = {
toJSON() {
const values = Object.assign({}, this.get());
return values;
},
};
const Client = db.define('clients', {
ibid: {
type: Sequelize.BIGINT,
allowNull: true,
defaultValue: null
},
firstName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
lastName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
agreementSigned: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
},
totalBalance: {
type: Sequelize.DECIMAL(11,2),
allowNull: true,
defaultValue: null
},
currentAllocation: {
type: Sequelize.STRING,
allowNull: true,
defaultValue: null
}
}, { instanceMethods });
module.exports = Client;
index.js models
'use strict';
const User = require('./user')
const Client = require('./client');
User.hasMany(Client);
Client.belongsTo(User);
module.exports = {User, Client};
In the index.js,
you haven't exported the new sequelize instance you have initialised and thus it is not available to the client.js and user.js! the define function works on the sequelize instance object that you have created!
Also there is a circular dependency in the project which might create problem!
I tried your code and changed the structure and it works now! There might be another structures possible too but this one works for me!
1) Don't create a new instance of sequelize in the index.js rather create another file that will serve as initialisation for the sequelize instance!
sequelize_index.js (I have used this file for creating a base instance and then using this base instance in both the client and user models)
const Sequelize = require('sequelize');
const dbconfig=require('./dbconfig.json');
const sequelize = new Sequelize('postgres://' + dbconfig.USER + ":" + dbconfig.PASSWORD + "#" + dbconfig.HOST + ":5432/" + dbconfig.DB, {
host: dbconfig.HOST,
dialect: dbconfig.DIALECT,
pool: {
min: 0,
max: 5,
idle: 1000
}
});
module.exports={sequelize};
2) The client.js would look something like this!
'use strict'
const Sequelize = require('sequelize');
const sequelize=require('./sequelize_index').sequelize;
const db = require('./index.js');
const instanceMethods = {
toJSON() {
const values = Object.assign({}, this.get());
return values;
},
};
const Client = sequelize.define('clients', {
ibid: {
type: Sequelize.BIGINT,
allowNull: true,
defaultValue: null
},
firstName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
lastName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
agreementSigned: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
},
totalBalance: {
type: Sequelize.DECIMAL(11,2),
allowNull: true,
defaultValue: null
},
currentAllocation: {
type: Sequelize.STRING,
allowNull: true,
defaultValue: null
}
}, { instanceMethods });
module.exports = Client;
3) User.js
const Sequelize = require('sequelize');
const sequelize=require('./sequelize_index').sequelize;
const db = require('./index.js'); //This is an instance of new Sequelize(...)
const tableName = 'users';
const User = sequelize.define('user', {
firstName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
lastName: {
type: Sequelize.STRING(50),
allowNull: false,
validate: {
notEmpty: true
}
},
username: { //Username will be the email
type: Sequelize.STRING(80),
allowNull: false,
unique: true,
validate: {
isEmail: true
}
},
password: {
type: Sequelize.STRING,
allowNull: false,
validate: {
notEmpty: true
}
},
isAdmin: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
},
isActive: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
}
}, { tableName });
module.exports = User;
4) index.js
'use strict';
const sequelize = require('./sequelize_index').sequelize;
const User = require('./user')
const Client = require('./client');
User.hasMany(Client);
Client.belongsTo(User);
sequelize.sync({force: false}).then(function () {
console.log("Database Configured");
});
module.exports = {User, Client};
After running the index.js, the database would be created!

Categories