I try to make RESTFUL API with node js and oracle database for my first time
I make a table in the database named "EMPLOYEES" and I add some data there
I make my backend file and I try to get the information in the database and it's worked successfuly
but when I try to make POST to add a new employee I don't get an error and the employee is not added to the database
when I try to test it with POSTMAN I got this result a null object like this {}
I know that I'm missing something
const express = require('express')
const oracledb = require('oracledb');
const bodyPerser=require("body-parser")
const app = express();
const port = 3000;
var password = 'mypassword';
app.use(bodyPerser.json());
async function selectAllEmployees(req, res) {
try {
connection = await oracledb.getConnection({
user: "system",
password: password,
connectString: "localhost:1521/XE"
});
console.log('connected to database');
// run query to get all employees
result = await connection.execute(`SELECT * FROM EMPLOYEES`);
} catch (err) {
//send error message
return res.send(err.message);
} finally {
if (connection) {
try {
// Always close connections
await connection.close();
console.log('close connection success');
} catch (err) {
console.error(err.message);
}
}
if (result.rows.length == 0) {
//query return zero employees
return res.send('query send no rows');
} else {
//send all employees
//return res.send(result.rows);
console.log(JSON.stringify(result.rows));
console.log(result.metaData[0].name);
let list=[]
result.rows.forEach(element => {
let agent = {
"ID": element[0],
"EMPNAME": element[1],
"EMPLASTNAME": element[2],
"AGE":element[3]
}
list.push(agent)
});
return res.send(JSON.stringify(list));
}
}
}
//get /employess
app.get('/employees', function (req, res) {
selectAllEmployees(req, res);
})
//////////////////post//////////////////////
app.post("/addNewEmployee", async (req, res) => {
try {
connection = await oracledb.getConnection({
user: "system",
password: password,
connectString: "localhost:1521/XE"
});
console.log('connected to database');
// I don't know what i'm missing here
result=connection.execute(`INSERT INTO EMPLOYEES VALUES ('${req.body.ID}','${req.body.EMPNAME}','${req.body.EMPLASTNAME}','${req.body.AGE}')`);
res.send(result)
} catch (err) {
//send error message
return res.send(err.message);
}
})
app.listen(port, () => console.log("nodeOracleRestApi app listening on port %s!", port))
Review node-oracledb examples and make sure you have basic techniques covered e.g. using bind variables. (The way you build your INSERT is open to SQL injection security attacks). Look at how webapp.js uses a connection pool - which you'll need if you have more than one person accessing your service.
Make sure you commit the data after inserting.
Add an 'await' before your connection.execute() for INSERT, something like:
result = await connection.execute(`INSERT INTO EMPLOYEES VALUES (:id, :empname, :emplastname, :age)`,
[req.body.ID, req.body.EMPNAME, req.body.EMPLASTNAME, req.body.AGE],
{autoCommit: true}
);
Do some debugging and see what is not working.
Avoid using SYSTEM for testing. Create a 'normal' (non privileged) user:
https://blogs.oracle.com/sql/how-to-create-users-grant-them-privileges-and-remove-them-in-oracle-database
Finally check out this series on creating a REST service with node-oracledb:
https://blogs.oracle.com/oraclemagazine/build-rest-apis-for-nodejs-part-1
https://github.com/oracle/oracle-db-examples/tree/master/javascript/rest-api
Related
I am using nodejs to listen to my table's data change using oracle CQN.
I do have the grant permission and vice versa connection from my DB server to my production server. The below code is working fine from a DB server and APP Hosting server
function myCallback(message) {
console.log(`myCallback:: Listened new data insertion`);
runFunction();
}
const options = {
callback: myCallback,
sql: `SELECT * FROM ${schemaName}.${tableName} where STATUS=0`,
qos : oracledb.SUBSCR_QOS_ROWIDS,
clientInitiated: true,
};
async function listener() {
//Create Connection Pool
try {
await oracledb.createPool({
user: `${userName}`,
password: `${userPass}`,
connectString: `${connString}`,
externalAuth: false,
events: true,
poolMax: parseInt(`${poolMax}`),
poolMin: parseInt(`${poolMin}`),
// poolTimeout: parseInt(`${poolTimeout}`),
// queueMax: parseInt(`${queueMax}`),
// queueTimeout: parseInt(`${queueTimeout}`),
});
//Create Connection
const connection = await oracledb.getConnection();
await connection.subscribe('mysub', options);
console.log("App is Listening ");
} catch (e) {
console.log("Error on Listening" + e);
}
}
But while changing to a new DB hosting server I don't receive the change notification. I have used the query to check whether the event registration is working or not.
SELECT * from USER_CHANGE_NOTIFICATION_REGS
I do get many regid which means the event registration is working fine.
So why the CallBack function is not working.
Thanks.
I would like to read a collection in mLab(mongoDB) and get result document based on the request from AWS LAMBDA function.
I could write a nodeJS function code snippet and whatever timeout I set it results in
Task timed out after *** seconds
Any solution, link or thoughts will be helpful. Either JAVA or NODE
'use strict';
const MongoClient = require('mongodb').MongoClient;
exports.handler = (event, context, callback) => {
console.log('=> connect to database');
MongoClient.connect('mongodb://test:test123#ds.xyx.fleet.mlab.com:1234', function (err, client) {
if (err) {
console.log("ERR ",err );
throw err;
}
var db = client.db('user');
db.collection('sessions').findOne({}, function (findErr, result) {
if (findErr){
console.log("findErr ",findErr);
throw findErr;
} else {
console.log("#",result);
console.log("##",result.name);
context.succeed(result);
}
client.close();
});
});
};
P.S : Referred all related stack questions.
Lambda function returned success after adding db name in
MongoClient.connect('mongodb://test:test123#ds.xyx.fleet.mlab.com:1234/dbNAME')
Apart from declaring db name in
var db = client.db('dbNAME');
It should also be added in mLab connection URI.
I am migrating an application from parse.com to buddy.com. One of the caveats of the migration was that Parse.User.current() is no longer available on buddy.com, instead you have to get the user and session token from the request itself: https://github.com/ParsePlatform/Parse-Server/wiki/Compatibility-with-Hosted-Parse#no-current-user
The application I am migrating has a logoutUser method that I am attempting to migrate:
Parse.Cloud.define("logoutUser", function(request, response) {
Parse.User.logOut().then(
function onSuccess(result){
response.success(result);
},
function onError(error) {
response.error(error);
}
)
});
now I am attempting to do this in the new style, but am receiving an error. (NOTE: This is cloud code not a nodejs environment)
{
"code":"500",
"error":"Error: There is no current user user on a node.js server environment."
}
New implementation:
function logoutUser(request, response) {
var user = request.user;
var sessionToken = user.getSessionToken();
Parse.User.logOut({ sessionToken }).then(
function onSuccess(result){
response.success(result);
},
function onError(error) {
response.error(error);
}
)
}
Parse.Cloud.define("logoutUser", function(request, response) {
logoutUser(request, response);
});
Suggestions on how to correctly log out users in the Parse on Buddy cloud code?
You could fetch user's session or sessions and delete it / them:
var query = new Parse.Query("_Session");
query.descending('createdAt');
query.equalTo('user', {__type:"Pointer", className:"_User", objectId:"idhere"});
query.first({
useMasterKey: true
}).then(function(session) {
var sessions = [];
sessions.push(session);
Parse.Object.destroyAll(sessions);
}, function (err) {
console.log("Internal error " + err);
});
OR for more tokens you could use find instead of first like:
var query = new Parse.Query("_Session");
query.equalTo('user', {__type:"Pointer", className:"_User", objectId:"idhere"});
query.find({
useMasterKey: true
}).then(function(sessions) {
Parse.Object.destroyAll(sessions);
}, function (err) {
console.log("Internal error " + err);
});
The above will mostly delete or tokens related to the given user. If you wish to delete only tokens used for login, and not for signup or upgrade, then you could put into your query:
query.equalTo('createdWith', { action: 'login', authProvider: 'password'});
As far as i know, deleting a user's last used for login token, then he is logged-out.
To add to the above, if you pass up the user's session key to the Cloud Code function via the X-Parse-Session-Token header, you can use the populated request.user object in the session query directly, instead of the user's ID.
I wrote a simple function in an angularJS application for signing up new users:
$scope.registerUser = function(username, password) {
var user = new Parse.User();
user.set("username", username);
user.set("email", username);
user.set("password", password);
user.signUp(null, {
success: function(result) {
console.log(result);
$scope.registerUserSuccess = true;
$scope.registerUserError = false;
$scope.registerUserSuccessMessage = "You have successfully registered!";
$scope.$apply();
$timeout(function(){
$state.go("user");
}, 1000);
},
error: function(user, error) {
$scope.registerUserError = true;
$scope.registerUserSuccess = false;
$scope.registerUserErrorMessage = "Error: [" + error.code + "] " + error.message;
$scope.$apply();
}
});
Initially it worked fine, but when I deleted all the users directly through Parse.com, I can't sign up new users using this function anymore. Each time I get error 209 invalid session token. Here's a screenshot of my Parse database:
I've googled the error message and the solution is always to log out the current user. However, if no users exist this isn't an action I can possibly take.
So I would not only like to fix this problem, but also know how to prevent it in the future so my application can be used safely.
Edit: I created a user directly in Parse.com, wrote a function to log in that user, but got the same error. I am completely stuck until this session issue is resolved.
delete all your session tokens, and anything else Parse related really, from local storage:
if needed turn off legacy session tokens, and follow migration tutorial from scratch:
I encountered this same error when building apps with react native using back4app. to clear anything Parse related, from local storage:
add
import { AsyncStorage } from "react-native";
in to the page and Use
AsyncStorage.clear();
See Example Below:
import { AsyncStorage } from "react-native";
import Parse from "parse/react-native";
// Initialize Parse SDK
Parse.setAsyncStorage(AsyncStorage);
Parse.serverURL = "https://parseapi.back4app.com"; // This is your Server URL
Parse.initialize(
"APPLICATION_ID_HERE", // This is your Application ID
"JAVASCRIPT_KEY_HERE" // This is your Javascript key
);
.........
_handleSignup = () => {
// Pass the username, email and password to Signup function
const user = new Parse.User();
user.set("username", "username);
user.set("email", "email");
user.set("password", "password");
user.signUp().then(user => {
AsyncStorage.clear();
if (condition) {
Alert.alert(
"Successful!",
"Signin Successful! Log in to your account.",
[
{
text: "Proceed",
onPress: () => {
//in this example, i navigated back to my login screen
this.props.navigation.navigate("LoginScreen");
}
}
],
{ cancelable: false }
);
}
})
.catch(error => {
Alert.alert("" +error);
});
};
I understand the reason to have the business logic in both client and server, but I don't understand well how to do that in some situations. Here for example:
// client/client.js
// hnadling click event on the Create Accounts button
Template.homecontent.events({
'click #btnCreateAccount': function (event, template) {
var userEmail = template.find('#email').value,
userName = template.find('#newusername').value,
password = template.find('#newpassword').value,
password2 = template.find('#password2').value,
name = template.find('#fullname').value;
validates = true;
//do some validation here
if(password != password2) {
validates = false;
}
if(validates === true) {
Accounts.createUser({
username: userName,
email: userEmail,
password: password,
profile: {
name: name
}
}, function (error) {
if (error) {
console.log("Cannot create user");
}
});
}
}
});
Since the validation is on the client only, it can easily be bypassed.
But there's a problem here: this is triggered by a user event, so I'm not sure what's the best way to have this code running on client & server.
You may be looking for something like Meteor.methods();, which allows you to define functions on the server that the client can call using Meteor.call(). You could provide a validation function and a user save function on the server, and call them both from the client, passing in the form data.
What I have done in the past is (on the client) I have a userFormParse() function that takes a form object and parses it into an object that can be passed into a server side validation function. I use the same userFormParse function for user edit and creation forms.
The validation function returns an error object to the client, or, if it's all valid data, I'll pass the data object on to a userCreateWithRole function (I usually always have roles assigned to users).
On the server:
Meteor.methods({
'createUserWithRole': function(data, role) {
var userId;
Meteor.call('createUserNoRole', data, function(err, result) {
if (err) {
return err;
}
Roles.addUsersToRoles(result, role);
return userId = result;
});
return userId;
},
'createUserNoRole': function(data) {
//Do server side validation
return Accounts.createUser({
email: data.email,
password: data.password,
profile: data.profile
});
}
});
And then on the client:
Template.userSignup.events({
'submit #userSignup': function(event) {
var data, validationErrors;
event.preventDefault();
data = userInputParse($(event.target)); //this function parses form into user object that can be inserted
validationErrors = userObjectValidate(data); //this function takes and does client side validation on the user object.
data.profile.status = 0;
if (validationErrors) {
//Show the user the validation errors
} else {
return Meteor.call('createUserWithRole', data, 'standard', function(err, userId) {
if (!err) {
//User created!!
} else {
//Insertion Error
}
});
}
}
});
That code is conceptual and untested :)
You should be doing it on server side, using Accounts.onCreateUser
The previous answers are not really exact.
Creating and using a Meteor method won't stop users to call the Accounts.createUser from the console for example. Therefore you also need to prevent the creation of users on the client :
Accounts.config({
forbidClientAccountCreation : true
});
You might want to look into Accounts.validateNewUser.
Example (taken from the docs):
Accounts.validateNewUser(function (user) {
if (user.username && user.username.length >= 3)
return true;
throw new Meteor.Error(403, "Username must have at least 3 characters");
});