Calling a stored procedure with sequelize and an express API - node.js

This is probably pretty easy but I've been unable to piece it together properly.
I'm trying to use the Sequelize NPM to call a stored procedure that I built and then I want to trigger it with a GET request from from an express api and return the output of the procedure to the api.
Here is what my code looks like for the Sequelize portion....
// Testing stored procedure //
const Retrieve = (testName) => connection.testdata_connection.query("EXEC [SPROC] [INPUTS]")
module.exports = {
tests: Tests(),
retrieve: Retrieve()
};
This part "connection.testdata_connection" is just establishing my connection to the database and I have tested this and I know this part is set.
I would like to be able to hit that with something like...
const query = require('./database/queries'); ///Imports sequelize queries
const app = express();
app.get('/decrypt', function(req,res){
query.retrieve()
})
})
This doesn't work at all.
Now if I do something like this in the queries file...
const Retrieve = async function() {
const decrypt = await connection.testdata_connection.query("EXEC [SPROC] [INPUT]")
console.log(decrypt)
}
module.exports = {
tests: Tests(),
retrieve: Retrieve()
};
This will log to my console with correct data when I start the server. I want it to do that when I hit it with my endpoint.

First, your function should be exported but not executed:
// creating an async function (all i/o operations should be async).
const Retrieve = async(testName) => connection.testdata_connection.query("EXEC [SPROC] [INPUTS]")
module.exports = {
retrieve: Retrieve,
// retrieve: Retrieve() if you call the function with (), the function will be executed and we don't want that yet
};
Now we can call it in the route:
const query = require('./database/queries'); ///Imports sequelize queries
const app = express();
// the route is async because it is executing async code
app.get('/decrypt', async (req,res) => {
// waiting for the answer with await
const response = await query.retrieve();
// Doing something with the response
})
You still need to check for errors, but that is the basics.

Related

Handling consecutive DynamoDB calls in a node.js Lambda for AWS

My example is quite simple. I am using AWS Lambda in proxy mode where the index.js looks like this.
const awsServerlessExpress = require('aws-serverless-express');
const app = require('./app');
const server = awsServerlessExpress.createServer(app);
exports.handler = (event, context) => {
console.log(`EVENT: ${JSON.stringify(event)}`);
return awsServerlessExpress.proxy(server, event, context, 'PROMISE').promise;
};
I have a separate app.js file which has a POST endpoint. Inside this endpoint I need to make two queries on a DynamoDB table.
I need to first query the table to determine if something exists.
My code looks like this.
// DynamoDB Document Client
const docClient = new AWS.DynamoDB.DocumentClient();
app.post('/profile/:userSub', (req, res) => {
const userSub = req.params.userSub;
const accountName = req.body.accountName;
// First query
const params = {
TableName: profileTableName,
IndexName: profileIndexAccountName,
KeyConditionExpression: 'accountName = :accountName',
ExpressionAttributeValues: {
':accountName' : accountName
}
};
docClient.query(params, (err, data) => {
// Process the results
});
}
The problem is that I want to do a follow up query docClient.put based on the results from the first query.
I don't understand how to chain the queries together so that the first one is completed before the second one is executed.
Can someone please point me to an example? Or alternatively, if there's a better using async/await then I'm happy to follow it.
TL;DR prefer the SDK's async-await patterns.
Here is an example of consecutive async-await calls using the AWS SDK for JavaScript v3.*. Note the async keyword in the function signature and the await keyword before the promise-returning method calls. The docs have the complete client initialization code.
// myLambda.js
import { DynamoDBDocument } from '#aws-sdk/lib-dynamodb';
// ... configure client
const ddbDocClient = DynamoDBDocument.from(client);
export async function handler(event) {
// ... other stuff
const getResult = await ddbDocClient.get({ TableName, Key });
const putResult = await ddbDocClient.put({
TableName,
Item: { id: '2', content: getResult.Item.Name },
});
}
* The #aws-sdk/lib-dynamodb library's DynamoDBDocument is the v3 equivalent of the v2 client in your code. It exposes convenience methods like .get and .put. It also helps convert between native js types and DynamoDB attribute values.

Pass parameter to middleware function and return result

So guys, what I want to accomplish and not manage to get is to write a function that performs a query against database as a middleware, using req and res objects, and also can be used in a socket connection, to pass parameters to it and not use the req and res objects. Also I want it to return the result of the query. I tried using a middleware wrapper
function myFunc(param1, param2){
return (req, res) => {
here query
}}
works when hitting the endpoint with or without args i send, but dosnt work when i call the function from somewhere else
When you call myFunc you get returned a new function. You need to invoke that funcion, something like
myFunc('value1', 'value2')()
This will cause an error since you have no request or response object. These are express objects.
A better way to re-use the database code would be to put it in a function and inject that function to the middlewere.
E.g.
function getArticleById(id) {
return db.query('select * from articles where id = $1', [id])
}
Then create a middlewhere that takes this function in as dependency
function makeMiddlewere (getArticleById) {
return (req, res) => {
return articleById(req.query.id).then(articles => {
res.json(articles)
})
}
}
Then in your code you can do
Normal way
getArticleById(5).then(articles => {
console.log(articles)
})
Create the middlwere an
const express = require('express')
const getArticleById = require('./articlebyid')
const makeMiddlewere = require('./makemiddlewere')
const middlwere = makeMiddlwere(getArticleById)
const app = express.app
app.get('/article', middlewere)

Express JS - Load data from a REST call and set to an Application variable when the Application starts up

I have a middleware that load some JSON data from a REST API.
loadDataStartup.js
'use strict';
const db_contants = require('./db_contants');
async function loadData () {
console.log("*** loadData() called");
var equipmentCategoryArr = await db_contants.getEquipmentCategory();
return equipmentCategoryArr;
}
module.exports = {loadData};
In my app.js, I need to set the data to an Application-level variable by app.set such that it can be later used by other Routers.
app.js
const { loadData } = require('./db/loadDataStartup');
var app = express();
app.set('dataOnStartup', async loadData());
When I ran npm start, it threw the following error:
app.set('dataOnStartup', async loadData());
^^^^^
SyntaxError: missing ) after argument list
I am with node.js version 8.11.3.
First of all, you don't do async callAsyncFn(), but await callAsyncFn(). So async loadData() is a syntax error. What you probably wanted to do was await loadData(). But you also can't do this in the entry-level app file, because this statement is not in an async function (you can only await inside async functions).
The workaround would be using an async IIFE (Immediately-Invoked Function Expression), like this:
const { loadData } = require("./db/loadDataStartup");
var app = express();
(async function() {
app.set("dataOnStartup", await loadData());
// The rest of your app startup logic
})();

run mongoose methods synchronously in node.js

I'm trying to call getMarchandiseList() method that call a mongoose method " find({}) " in my marchandise router.
the problem is when I send the responce I find that I get a result=0 before the find({}) method send it's result
//the result should be
{id_marchandise : 01 , libelle_marchandise : 'fer'}.
[MarchandiseDAO.js][1]
*
var express = require("express");
var router = express.Router();
var marchandiseDAO = require ('../DAO/marchandises');
router.get('/listmarchandise', function (req,res) {
var marchandise = new marchandiseDAO();
marchandise.getMarchandiseList();
res.send("result" +marchandise.result);
});
module.exports = router;
*
[marchandiserouter.js][2]
var model = require("../Models/model");
var marchandiseDAO = function () {
console.log("get instance ");
this.result = 0 ;
}
marchandiseDAO.prototype.getMarchandiseList = function () {
console.log("begin");
model.MarchandiseModel.find({},function(err,marchandiselist){
console.log("traitement");
if(err) result = err;
else result = marchandiselist;
});
console.log("end");
}
You cannot run mongoose methods synchronously. But if you use a modern version of Node then you can make it appear as if it was run asynchronously.
Unfortunately you posted your code examples as screenshots which would require me to use Photoshop to fix your code, which is obviously not worth the hassle. So instead I will show you a general solution.
Using normal promises:
Model.find({...}).then(data => {
// you can only use data here
}).catch(err => {
// always handle errors
});
Using await:
try {
let data = await Model.find({...});
// you can only use data here
} catch (err) {
// always handle errors
}
The second example can only be used in an async function. See this for more info:
try/catch blocks with async/await
Use await outside async
Using acyns/await in Node 6 with Babel
When do async methods throw and how do you catch them?
using promises in node.js to create and compare two arrays
Keeping Promise Chains Readable
function will return null from javascript post/get

Node.js Unit Testing - Create Mock Layer Using mocha

I have written a web service that indeed consumes an external web service, after performing some validations and data manipulations (plain business logic). I need to write unit tests for the same and need to have code coverage report as well. Many suggestions are available on the net, Mocha being the prominent one. But in all available examples, actual DB call or external service call happens. My requirement is not to have actual external service call, but just mock the call (Just how, we do using EasyMock in Java). Any help would be highly appreciated. Is it possible to create a mock of DB call or external service call in node js ?
You can use Sinon with Mocha to provide stubbing, or spying of calls. It is important to also write you code to aid mocking. For instance, don't assume the database handler exists in the web component, pass it in through the constructor. That way its easy for testing to replace the database with your own "mocked" version.
As an example - here is the start of one of my bunch of tests where I instanciate a mocked connection pool to my database handler and pass it into the test. I am actually also mocking the web server, and just testing the API.
(function(){
'use strict';
const DBHOST = 'dummy';
const DBNAME = 'dummy';
const expect = require('chai').expect;
const sinon = require('sinon');
const mock = require('../mock/server');
const DB = require('../database');
const Logging = require('../log');
Logging.debug(true); //set to log debug message
const logger = Logging.logger;
const poolPromise = mock.getPool();
const db = new DB(mock.Pool,DBNAME,logger);
const API = require('../api');
const api = new API(mock.server,db,logger);
describe('API tests',function() {
let sandbox, testConnection;
beforeEach(function(){
sandbox = sinon.sandbox.create();
testConnection = new mock.Connection();
return poolPromise.then(pool => {
pool.getConnection().then(cb => {
cb(null,testConnection);
});
});
});
afterEach(function(){
sandbox.restore();
});
describe('/logon',function() {
let params;
describe('Admin', function() {
beforeEach(function() {
params = {name: 'Admin', password: 'abcde'};
})
it('Performs logon if username is "Admin" and password is good', function(done) {
mock.server.emit('/logon', params, (status,user) => {
expect(status).to.be.true;
expect(user).to.be.an('object');
expect(user.uid).to.be.equal(0);
expect(user.name).to.be.equal('Super User');
expect(user.keys).to.be.equal('A');
done();
});
testConnection.next.then(value => {
let request = value.request;
expect(value.name).to.equal('execSql');
expect(request.sqlTextOrProcedure).to.equal('SELECT passwordsalt FROM Admin WHERE AdminID = 0');
request.emit('row', mock.makeRow('passwordsalt',['salt']));
request.callback(null,1);
return testConnection.next;
}).then(value => {
let request = value.request
expect(value.name).to.equal('callProcedure');
expect(request.sqlTextOrProcedure).to.equal('CheckPassword');
request.emit('row',mock.makeRow('a',[1]));
request.callback(null,0);
});
});

Resources