Building a project around Bing translate and Node.js - javascript

I am trying to build a web app that allows a user to press a button and translate a piece of text using the Bing translator api. I try to run a translator.js file through a script tag but I of course cannot run this node.js code through the client html page. What would be the proper way to design this app. Is my only choice to use something such as requirejs? I also have an app.js file built using express from which I run the app. Sorry for posting a lot of code, I want to give people an idea of the structure of my app. My experience is limited so I am feeling somewhat lost as to how to approach the design of this portion of the app. I don't expect anyone to write the code for me, but to just point in a direction of techniques that I could research so that I could build this properly.
Here is my Node.js translation request called translator.js
const request = require('request');
const uuidv4 = require('uuid/v4');
var key_var = 'TRANSLATOR_TEXT_SUBSCRIPTION_KEY';
if (!process.env[key_var]) {
throw new Error('Please set/export the following environment variable: ' + key_var);
}
var subscriptionKey = process.env[key_var];
var endpoint_var = 'TRANSLATOR_TEXT_ENDPOINT';
if (!process.env[endpoint_var]) {
throw new Error('Please set/export the following environment variable: ' + endpoint_var);
}
var endpoint = process.env[endpoint_var];
let options = {
method: 'POST',
baseUrl: endpoint,
url: 'translate',
qs: {
'api-version': '3.0',
'to': ['en']
},
headers: {
'Ocp-Apim-Subscription-Key': subscriptionKey,
'Content-type': 'application/json',
'X-ClientTraceId': uuidv4().toString()
},
body: [{
'text': 'hallo welt'
}],
json: true,
};
function displayBingTranslate() {
request(options, function(err, res, body){
document.querySelector("#bingTranslateOutput") = JSON.stringify(body, null, 4);
});
};
var accessBingTranslate = document.getElementById("accessBingTranslateButton");
accessBingTranslate.addEventListener("click", function() {
displayBingTranslate();
});
And here is my html
<!-- Section to view online translation -->
<div class="container">
<div class="row">
<div class="col-lg-12 p-0">
<button
class="btn btn-outline-dark btn-sm mb-1"
id = "accessBingTranslateButton">Translate Flashcard</button>
<div class="row m-0 p-0">
<div id="bingTranslateOutput" class="col-lg-12 m-0">
</div>
<script>
// Overall list of flashcards.
var flashcardList = {
flashcards: [],
// Adds a flashcard object to Flashcard array.
addFlashcard: function(fcTextQuestion, fcTextTranslated) {
this.flashcards.push({
fcTextQuestion: fcTextQuestion,
fcTextTranslated: fcTextTranslated
});
},
};
// Add flashcards on load.
var flashcardsDB = <%- JSON.stringify(flashcardsDB) %>;
console.log("the DB:", flashcardsDB);
flashcardsDB.forEach(function(fcardDbToAdd){
flashcardList.addFlashcard(fcardDbToAdd.question, fcardDbToAdd.translation);
});
document.querySelector("#displayFlashcardTotal").textContent = flashcardList.flashcards.length;
console.log("the rest:",flashcardList.flashcards);
var currentFlashcard = 0;
</script>
<script src="/scripts/translator.js"></script>
</body>
</html>
and here is my app.js
var express = require("express");
var app = express();
var bodyParser = require("body-parser");
var mongoose = require("mongoose");
var methodOverride = require("method-override");
// Fix mongoose deprecations
mongoose.set('useNewUrlParser', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);
mongoose.set('useUnifiedTopology', true);
// Connect to database.
var url = "///////";
mongoose.connect(url, {
useNewUrlParser: true,
useCreateIndex: true,
}).then(() => {
console.log("connected to mongoDB");
}).catch(err => {
console.log("Error:", err.message);
});
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static(__dirname + '/public'));
// Set 'views' directory for any views
// being rendered res.render()
app.set("view engine", "ejs");
// Override HTTP verbs if necessary.
app.use(methodOverride("_method"));
var flashcardSchema = new mongoose.Schema ({
question: String,
translation: String
});
//creates model with above schema and has methods such as .find etc.
var Flashcard = mongoose.model("Flashcard", flashcardSchema);
app.get('/', (req, res) => {
Flashcard.find({}, function(err, allFlashcards){
if(err){
console.log(err);
} else {
res.render("home", {flashcardsDB: allFlashcards});
}
});
});
// Post to an input action
app.post("/flashcards", function(req, res) {
var question = req.body.question;
var translation = req.body.translation;
var newFlashcard = {question: question, translation: translation};
console.log(newFlashcard);
Flashcard.create(newFlashcard, function(err, newlyCreated){
if(err){
console.log(err);
} else {
res.redirect("/flashcards");
}
});
});
// Show info.
app.get("/info",function (req, res) {
res.render("info");
});
// Show all flashcards
app.get("/flashcards", function(req, res){
Flashcard.find({}, function(err, allFlashcards){
if(err){
console.log(err);
} else {
res.render("flashcards", {flashcards: allFlashcards});
}
});
});
// Show form to create new campground
app.get("/new", function(req, res){
res.render("new");
});
// Edit flashcard
app.get("/flashcards/:id/edit", function(req, res){
Flashcard.findById(req.params.id, function(err, selectedFlashcard){
if(err){
req.flash("error", "Flashcard not found!");
} else {
res.render("edit", {flashcard: selectedFlashcard});
}
});
});
// Update flashcard
app.put("/flashcards/:id", function(req, res){
Flashcard.findByIdAndUpdate(req.params.id, req.body.flashcard, function(err, updatedFlashcard){
if(err){
res.redirect("/flashcards");
} else {
res.redirect("/flashcards");
}
});
});
// Destroy Flashcard
app.delete("/flashcards/:id", function(req, res){
Flashcard.findByIdAndRemove(req.params.id, function(err){
if(err){
res.redirect("back");
} else {
//req.flash("success", "flashcard deleted.");
res.redirect("/flashcards");
}
});
});
app.listen(3000, () => console.log("Flashcard app is listening"));

I think the best aproach would be to pass the translator.js to the node.js server. Create a route on express for translations, and through that route you will call the translator.js and return the result. Then, on your html page, instead of running the translator.js directly, send a request to your server passing the necessary data.
On your app.js, you can do a route like this:
const translator = require('path_to_translator');
app.get('/translation', translator);
And then on your translator.js, you can export a function that will receive the parameters you need and return the result:
const bingTranslate = (req, res) => {
// YOUR CODE HERE
}
module.exports = bingTranslate
And then on your html you will make the button send a request to your server instead of calling translator.js, so you can change the value of the #bingTranslateOutput button based on the response you will receive from the server.

Related

How to post an array to Express API

I'm creating APIs with Express.js and SQL Server. I been posting an object which is easy and very simple, but now i have a new question: how to post an array?
Let's say i have a table which stores only two params:
Table_A
Id | CouponId
In fact, the only record that stores is CouponId, 'cause the Id is created by SQL Server on every record. So, the case is that i get a list of coupons from an api, and the idea is select from one to 'n' with a checkbox and save the selection.
This my code so far:
function getList(){
$http.get('/api/coupons')
.then(function(data){
$scope.infoCoupons = data.data.Response;
}
On the HTML view:
<div class="col-lg-12" align="center">
<input type="checkbox" ng-click="selectAll()"/> <a style="font-size:17px;color:black;text-decoration:none;">Select all coupons</a>
<ul class="coupon-list">
<li ng-repeat="coupon in infoCoupons">
<input type="checkbox" ng-model="coupon.Select" ng-click="checked"/> <a style="font-size:17px;color:black;text-decoration:none;">{{coupon.CodeCoupon}}</a>
</li>
</ul>
</div>
Then, to get the selected coupons:
$scope.selectAll = function(){
$scope.all = !$scope.all;
$scope.infoCoupons.forEach(function(o){
o.Select = $scope.all;
});
}
function chosenCoupons(){
var result = new Array();
var checked = 0;
$scope.infoCoupons.forEach(function(e){
if(e.Select === true){
result.push(e.Id);
checked +=1;
}
});
if($scope.all || checked > 0){
alert("Selected coupons!");
}
else if(checked === 0){
alert("Select at least one coupon");
}
}
Then, my code for the API:
const express = require('express');
const bodyParser = require('body-parser');
const sql = require('mssql');
const app = express();
app.use(bodyParser.json());
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, contentType,Content-Type, Accept, Authorization");
next();
});
const dbConfig = {
user: "daUser",
password: "daPass",
server: "daServa",
database: "daDB"
};
const executeQuery = function (res, query, parameters) {
sql.connect(dbConfig, function (err) {
if (err) {
console.log(`There's an error: ${err}`);
res.send(err);
sql.close();
}
else {
var request = new sql.Request();
if (parameters && parameters.length > 0) {
parameters.forEach(function (p) {
request.input(p.name, p.sqltype, p.value);
});
}
request.query(query, function (err, result) {
if (err) {
console.log(`Theres an error: ${err}`);
res.send(err);
sql.close();
}
else {
res.send(result);
sql.close();
}
});
}
});
}
app.post("/api/testApi", function(req, res){
parameters = [
{ name: 'CouponId', sqltype: sql.VarChar, value: req.body.CouponId }
];
var query = "INSERT INTO [Table_A] VALUES(#CouponId)";
executeQuery(res, query, parameters);
});
const PORT = process.env.PORT || 8080
app.listen(PORT, () => {
console.log(`App running on port ${PORT}`)
});
This is the code that usually works for an object. My question is: how can i send result (where result is the obtained array) on the API. I need to change something on my code on parameters?
Hope you can help me. I'm using Javascript, Node, Express and SQL Server.
How to post an array to Express API
In angular you simply do $http.post(url, data).
If you assign data to an object that has an array, it will reach express.
Then express can parse the body since you have app.use(express.bodyParser()); so the object should be available to you on the body.
URL Query Params
If you are trying to use query parameters, to pass an array, lets say on attribute items so you simply declare it multiple times
items=1&items=2&items=3 should be parsed to req.query.items === [1,2,3]

passing user input of html form to express node js without routing to a new page

I am trying to use imap to search emails in my gmail inbox. It is going to be server side mail parser. To do so, I used express and I want to receive the input of users (from search field) using express. However, all the solutions I searched in the internet use app.post and bring me to a new page. I don't want to show any thing new in user interface. I just want to receive the input of user and give it to a function which performs imap.search. Any help? Here is the code:
index.htm
<!doctype html>
<html>
<body>
<form action="http://127.0.0.1:8081/process_post" method="POST">
Search: <input type = "text" name = "Search_value"> <br>
<input type = "submit" value = "SEARCH">
</form>
</body>
</html>
test.js
var express = require('express')
var bodyParser = require('body-parser');
var app = express()
app.use(express.static('public'));
// use body parser to easy fetch post body
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json())
var Imap = require('imap'),
inspect = require('util').inspect,
MailParser = require("mailparser").MailParser;
var imap = new Imap({
user: '***#gmail.com',
password: '*****',
host: 'imap.gmail.com',
port: 993,
tls: true
});
var fs = require('fs'), fileStream;
function openInbox(cb) {
imap.openBox('INBOX', true, cb);
}
// route to '/index.htm' to return the html file
app.get('/index.htm', function (req, res) {
res.sendfile('index.htm');
});
//route that receives the post body and returns your computation
app.post('/process_post', function (req, res) {
passtoserver(req.body, res);
});
app.listen(8081);
function passtoserver(parms, res) {
//get the parameters based on input name attribute from the html
//and parse strings to numbers
var m = parms.Search_value;
// res.writeHead(200, { 'Content-Type': 'text/html' });
res.end();
openInbox(function(err, box) {
if (err) throw err;
imap.search([ 'ALL', ['FROM', m] ], function(err, results) {
var f = imap.fetch(results, {
bodies: 'HEADER.FIELDS (FROM TO SUBJECT DATE)',
struct: true
});
f.on('message', function(msg, seqno) {
console.log('Message #%d', seqno);
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
var buffer = '';
stream.on('data', function(chunk) {
buffer += chunk.toString('utf8');
});
stream.once('end', function() {
console.log(prefix + 'Parsed header: %s', inspect(Imap.parseHeader(buffer)));
});
});
msg.once('attributes', function(attrs) {
console.log(prefix + 'Attributes: %s', inspect(attrs, false, 8));
});
msg.once('end', function() {
console.log(prefix + 'Finished');
});
});
f.once('error', function(err) {
console.log('Fetch error: ' + err);
});
f.once('end', function() {
console.log('Done fetching all messages!');
});
});
});
}
imap.connect();
After submiting the user input, a new rout called process-post will ope. How to avoid this?
You can try it with:
https.request() API?
http.request() for secure protocal

express routes do not load again

I'm encountering a problem with the express routes. Here's my case:
I have a node js app with the following code in app.js
var express = require('express');
var app = express();
var path = require('path');
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended: false
}));
var cfenv = require('cfenv');
// request module provides a simple way to create HTTP requests in Node.js
var request = require('request');
var routes = require('./routes')(app);
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname + '/public/index.html'));
});
var appEnv = cfenv.getAppEnv();
// compose for mysql code
var dbcontroller = require('./controller/compose-mysql-connection');
dbcontroller.databaseconnection();
const util = require('util');
// and so is assert
const assert = require('assert');
var mysql = require('mysql');
var appEnv = cfenv.getAppEnv();
// Within the application environment (appenv) there's a services object
var services = appEnv.services;
// The services object is a map named by service so we extract the one for Compose for MySQL
var mysql_services = services["compose-for-mysql"];
// This check ensures there is a services for MySQL databases
assert(!util.isUndefined(mysql_services), "Must be bound to compose-for-mysql services");
// We now take the first bound Compose for MySQL database service and extract it's credentials object
var credentials = mysql_services[0].credentials;
var connectionString = credentials.uri;
// set up a new connection using our config details
var connection = mysql.createConnection(credentials.uri);
//reading from the database
app.get("/read_fb_info", function(request, response) {
connection.query('SELECT * FROM fb_info_table ORDER BY name ASC', function (err, result) {
if (err) {
console.log(err);
response.status(500).send(err);
} else {
console.log(result);
response.send(result);
}
});
});
app.use(express.static(__dirname + '/public'));
// start server on the specified port and binding host
app.listen(appEnv.port, '0.0.0.0', function() {
// print a message when the server starts listening
console.log("server starting on " + appEnv.url);
});
Then, in the routes folder I have a file with other two routes I use into the application.
Once the index page is loaded I have two button:
<body>
<div class="container">
<h1>External API Usage</h1>
<h3>LinkedIn</h3>
<a href='/info/linkedin'>
<img src="/images/LinkedIn_image.png" class="img-rounded" alt="LinkedIn" width="150" height="150">
</a>
<h3>Facebook</h3>
<a href='/info/facebook'>
<img src="/images/Facebook_image.png" class="img-rounded" alt="Facebook" width="150" height="150">
</a>
</div>
To handle routes I created an index.js file in the routes folder which includes the following:
retrieveFacebookUserInfo = function() {
var deferred = Q.defer();
var propertiesObject_FB = { id:'id', name:'name', access_token:'access_token' };
request({url:'https://graph.facebook.com/', qs:propertiesObject_FB}, function(err, response, body) {
if(err) {
deferred.resolve(null);
}
else {
var fb_json = JSON.parse(body);
console.log("Get response: " + response.statusCode);
console.log(fb_json);
//storing information to db
dbcontroller.writingtodb();
deferred.resolve(fb_json);
}
});
return deferred.promise;
};
app.get('/info/facebook', function(req, res){
retrieveFacebookUserInfo().then(function(result){
res.render('facebook.ejs', {
title : 'Facebook information',
fb_obj: result
});
});
});
app.get('/info/linkedin', function(req, res){
retrieveLinkedInUserInfo().then(function(result){
res.render('linkedin.ejs', {
title : 'LinkedIn information',
headline_linkedin: result.headline
});
});
});
If I try to open the second one (/info/facebook) at first e then the first one (/info/linkedin) it doesn't load the page related of /info/linkedin route. It shows this message:
404 Not Found: Requested route ('linkedin-demo-app.eu-gb.mybluemix.net') does not exist.
Do you guys know what is this kind of problem? It seems like it doesn' recognize and find the route again.
Thanks in advance
You simply don't have route handler for these two paths. You need to create them like you did for your /read_fb_info path:
app.get("/info/linkedin", function(request, response) {
//do somenthing and send your response
});
app.get("/info/facebook", function(request, response) {
//do somenthing and send your response
});

GET in a Route - Nodejs

what´s the best way if I want to make a GET request in a route?
api.js
api.route('/guests')
.get(function(req, res) {
Guest.find(function(err, guests) {
if (err)
res.send(err);
res.json(guests);
});
});
routes.js
app.get('/export', requiresLogin, function(req, res) {
/* make a GET request to my api (eg.: 'api/guests') */
/* and save the 'guests' to a variable */
});
First Solution
Instead of calling internal apis, you can define a controller guestCtrl.js and call the function from guestCtrl.js in api.js and routes.js
guestCtrl.js
module.exports = {
getGuests : function(){
Guest.find(function(err, guests) {
if (err)
//handle error
return [];
else
return guests;
});
}
}
api.js
//path of guests.js
var guestCtrl = require('guestCtrl.js');
api.route('/guests').get(function(req, res) {
return guestCtrl.getGuests();
});
routes.js
var guestCtrl = require('guestCtrl.js');
app.get('/export', requiresLogin, function(req, res) {
var guests = guestsCtrl.getGuests();
// do whatever you like to do with guests
});
Second Solution
If you really want to work with internal api, then you can use request module.
e.g.
routes.js
var request = require('request');
app.get('/export', requiresLogin, function(req, res) {
// you can put the hostname and port here
request('http://127.0.0.1:3000/api/guests', function(err, body, response){
var guests = body; // and save the 'guests' to a variable
});
});

Node.js API design and route handling

I am not really sure what to title this, but I'm new to Node.js. I just found a neat REST API project on GitHub to implement but I'm not sure how I can split all GET and POST etc. to separate files.
I have one singular api.js file where I have
function API_ROUTER(router, connection, md5) {
var self = this;
self.handleRoutes(router, connection, md5);
}
API_ROUTER.prototype.handleRoutes = function(router, connection, md5) {
router.get("/", function(req, res) {
res.json({"Message" : "Hello World !"});
});
};
module.exports = API_ROUTER;
Now how can I create a sibling other.js and use:
var api = require('./api.js');
// Create router.get, router.post etc. here?
but I'm not sure how I can split all GET and POST etc. to separate files.
One way you can organize your routes would be to have a separate object for each route that has the handlers (separated by HTTP methods) and other needed info such as the path:
api/home.js
module.exports = {
path: '/',
handlers: {
'get': function(req, res) {
res.json({"Message" : "Hello World !"});
},
'post': {
// ...
}
// ...
}
}
api/other.js
module.exports = {
path: '/other',
handlers: {
'get': function(req, res) {
res.json({"Message" : "Other !"});
},
// ...
Then you can load all of these inside the handleRoutes method:
API_ROUTER.prototype.handleRoutes = function(router, connection, md5) {
var routes = ['home', 'other'];
routes.forEach(function(name) {
// load the current route object (NOTE: you should use the path module for determining file path in a cross-platform manner)
var routeObject = require('./' + name + '.js');
var apiPath = routeObject.path;
var handlers = routeObject.handlers;
var methods = Object.keys(handlers);
// assign handlers for each method
methods.forEach(function(method) {
router[method](apiPath, handlers[method]);
});
});
};
This will install all your routes with the appropriate information and handlers.
Now you can call this code by instantiating your API_ROUTER with the necessary data:
// initialize the api (and handle the routes internally)
var Api = new require('./api.js')(router, connection, md5);
If you implement a RESTful API, then you should keep in mind that this is just one way how you can provide data, and you might want to change it in future, as of that the API will most of the time only be a translation layer.
Normally you will split your code based on the resources, and the code that is handling the request won't have so much logic, it will just take the request and pass it to you internal API. For that purpose you not really need an additional layer if you already use express.js or a similar library.
In express the app.use([path,] function [, function...]), already provides the functionality you would need to modularize your code. For each resource your will create an own express.Router that itself also might mount another sub module. So for this part you do not really need a library.
When might a library be useful:
if it automatically translates thrown errors to the correct response codes
if it includes a tool to automatically create a documentation to your API
if it fully abstracts the underlaying routing system so that you can hook into express, hapi, ... without the need to change the code.
Here how a setup with express.js could look like
./lib/rest/customer.js
var customerSystem = require('../customer-system');
var express = require('express');
var router = new express.Router();
router.get('/:id', function(req, res, next) {
customerSystem.find({
id: req.params.id
}, function(err, customer) {
if (err) {
res.status( /*correct status code*/ ).send( /*depending on the api return json, xml, ....*/ )
} else {
res.send( /*depending on the api return json, xml, ....*/ )
}
})
});
router.delete('/:id', function(req, res, next) {
customerSystem.delete({
id: req.params.id
}, function(err) {
//...
});
});
router.post('/', function(req, res, next) {
//...
});
//save the customer id for the pass to the sub routers
router.use('/:id', function(req, res, next) {
req.customerId = req.params.id;
next();
});
router.use('/:id/addresses', require('./customer-address') )
module.exports = router;
./lib/rest/customer-address.js
var customerSystem = require('../customer-system');
var express = require('express');
var router = new express.Router();
router.get('/:id', function(req, res, next) {
customerSystem.find({
id: req.customerId
}, function(err, customer) {
// ...
})
});
/* ..... */
//save the address id for the pass to the sub routers
router.use('/:id', function(req, res, next) {
req.addressId = req.params.id;
next();
});
router.use('/:id/addresses', require('./customer-address') )
module.exports = router;

Categories

Resources