Angular Seed project, set index.html by default - html

I am using the Angular Seed project to build a simple website. When i start the node server and enter the url at localhost:8000, it serves up the directory contents. I would like it to serve up the index.html file but would like to do this without a redirect.
I believe that I need to modify the following function and that I should change the code for the isDirectory check but I'm not sure if that is the correct way to go about doing this. Any suggestions would be appreciated.
StaticServlet.prototype.handleRequest = function(req, res) {
var self = this;
var path = ('./' + req.url.pathname).replace('//','/').replace(/%(..)/g, function(match, hex){
return String.fromCharCode(parseInt(hex, 16));
});
var parts = path.split('/');
if (parts[parts.length-1].charAt(0) === '.')
return self.sendForbidden_(req, res, path);
fs.stat(path, function(err, stat) {
if (err)
return self.sendMissing_(req, res, path);
if (stat.isDirectory())
return self.sendDirectory_(req, res, path);
return self.sendFile_(req, res, path);
});
}
Update #1
I have two screenshots to clarify. The first image is what I currently get, the second image is what I want.
What I Get
What I Want
Update #2
Using the link to Restify below I found the following example which is exactly what I needed.
var server = restify.createServer();
var io = socketio.listen(server);
server.get('/', function indexHTML(req, res, next) {
fs.readFile(__dirname + '/index.html', function (err, data) {
if (err) {
next(err);
return;
}
res.setHeader('Content-Type', 'text/html');
res.writeHead(200);
res.end(data);
next();
});
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
server.listen(8080, function () {
console.log('socket.io server listening at %s', server.url);
});

The angular-seed project is a starting point for the client, but not really for the server side.
They included a simple web-server node script without dependencies. This way you don't need npm or other modules.
For the server side you can use node with connect/express or any other web server/language.
You just need to make rest services and serve some static html.
Since you have already installed Node restify may be something for you.
Update: I created a basic sample for using the angular-seed with restify:
https://github.com/roelandmoors/restify-angular-seed

Related

How to save rendered html view files from ExpressJS Routes

I've built few pages of a static website using ExpressJS and PUG to get the advantage of the template engine.
But now I need to export all the raw HTML that is being rendered by all ExpressJS Routes.
Is there any package that can help me to do that? Or I've to write custom command and iterate over all the Routes and save the rendered output?
If a custom command is the only way, how do I iterate over all the routes and get the rendered output?
I couldn't find any library or resource to achieve what I wanted. But with some of my dirty code, hacks, and packages I was able to export all the routes.
Note: Instead of writing a node command to export the htmls, I've added a route to trigger the operations here is the code for the route:
app.use('/export_templates', router.get('/', async function (req, res, next) {
const endpoints = listEndpoints(app);
const failedEndpoints = [];
for (const i in endpoints) {
const endpoint = endpoints[i];
if (endpoint.path == '/export_templates') {
continue;
}
try {
const res = await axios.get('http://'+req.headers.host+''+endpoint.path+'?export=true');
}
catch(error) {
failedEndpoints.push(endpoint.path);
}
}
res.json({
"status": "succes",
"message": "Please check templates folder for the latest exported html templates",
"failed": failedEndpoints
})
}));
Basically this route iterates and makes a request to all the available routes with a export=true parameter.
Then inside every route view function a condition checks if the export parameter is available then calls the exportTemplateFile function with the pug template location and new file name as the function parameter.
If the request doesn't contain export parameter the requested route will simply output what template.
An example route:
router.get('/', function(req, res, next) {
if (req.query.export) {
exportTemplateFile('views/index.pug', 'index.html');
}
res.render('index.pug');
});
And here is the code for 2 util function to complete the export process
function createTemplateFile(filename) {
fs.open(filename,'r',function(err, fd){
if (err) {
fs.writeFile(filename, '', function(err) {
if(err) {
console.log(err);
}
});
}
});
}
function exportTemplateFile(templateLocation, templateName) {
const html = pretty(pug.renderFile(templateLocation));
createTemplateFile('templates/'+templateName);
var stream = fs.createWriteStream('templates/'+templateName);
stream.once('open', function (fd) {
stream.write(html);
stream.end();
});
}
The createTemplateFile function simply creates a new file if it doesn't exist.
The exportTemplateFile function saves the HTML in the html variable rendered by pug and prettifies it with the pretty package and then overwrites the new template file.
Note: In my case all the pug templates were static so I didn't have to pass any context to the pug.renderFile function. But if you need any context to be used inside the pug template you can simply pass that with the template location.
Edited version of the same answer.
First of all thank you so much for solving this problem.
I have made some changes to your code as per new errors.
Here is the code with async and await function for ejs users
const express = require('express')
const ejs = require('ejs')
const fs = require('fs')
const app = express()
const port = 3000
//set the templating engine as ejs
app.set('view engine', 'ejs');
function createTemplateFile(filename) {
fs.open(filename,'r',function(err, fd){
if (err) {
fs.writeFile(filename, '', function(err) {
if(err) {
console.log(err);
}
});
}
});
}
async function exportTemplateFile(templateLocation, templateName) {
var html = await ejs.renderFile(templateLocation);
createTemplateFile('templates/'+templateName);
var stream = fs.createWriteStream('templates/'+templateName);
stream.once('open', function (fd) {
stream.write(`${html}`);
stream.end();
});
}
app.get('/', (req, res, next) => {
res.render('./pages/home')
exportTemplateFile('views/pages/home.ejs', 'index.html');
console.log('file rendered and saved successfully')
})
app.listen(port, () => {
console.log(`App is listening on port ${port}`)
})

Why does Node.js on http-server freeze when you enter url parameter

I'm setting up a node.js server, and want to fix problem with freezing loading using http-server lib.
I've tried doing other URL parameter methods but it doesn't work and doesn't show any errors on console.
var url = require('url');
http.createServer(function (req, res) {
var queryData = url.parse(req.url, true).query;
if (req.url == '/watch') {
if (!queryData.id) { res.write("Missing watch id?"); res.end(); }
res.end();
fs.readFile('player.html', function (err, html) {
if (err) {
throw err;
}
res.writeHeader(200, {"Content-Type": "text/html"});
res.write(html + "<div id='b6'>" + queryData.id + "</div>");
res.end();
});
}
});
I expect the output to get URL parameter and show the player.html.
There may be more than one issue, but as-written, you have an errant res.end(), before you read in your player.html and return it to the response. Remove that line and see if it behaves as you expect.

Require a file within a route to run a query

Im trying to set up my routes and then include a "content" file that would run a query
app.get('/participants', function(req, res, next) {
var participants = require('./content/participants');
});
and then the participants file:
const db = database.connect('olmsdb.1sserver.com', 'campyio');
db.raw('SELECT * FROM participants').then(function(results) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(results));
return results;
db.destroy();
});
The goal here is to hit the /participants route and then run the the select query and send the query results.
require() doesn't work like source(..) or execute in other languages. The code in it only execute once when first required. Then the module is cached.
You need to return functions and classes in a module file, using module.exports etc.
To do this:
participants.js:
const db = database.connect('olmsdb.1sserver.com', 'campyio');
exports.getParticipants = function() {
return db.raw('SELECT * FROM participants');
}
app.js:
var participants = require('./content/participants');
app.get('/participants', function(req, res, next) {
participants.getParticipants().then(function(results) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(results));
next();
});
});
You need to put that code in an exported function so that you can call it with the request & response every time you get a request.
That means there is no point in require()ing it inside your route handler.

HTML is being sent instead of JSON Data

I'm trying to retrieve data from a SQL database and display that said data on a Reactjs web app. However, all the calls I make to the database results in the HTML of the webpage in focus. I have set the headers, and I've tried to change the way the response from the express call is being handled.
Here is the expressjs script I am using right now:
const express = require('express');
const sql = require('mssql/msnodesqlv8');
const bodyParser = require('body-parser');
const path = require('path');
const cors = require('cors');
const db = require('./db.js');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use('/counselling/triageadmin/', express.static(path.join(__dirname, '/build')));
app.use(cors());
app.get('/getTable', function (req, res, next){
var request = new sql.Request(db);
request.query('select * from Counselling order by TicketID desc', (err, result) =>{
if (err) { return next(err); }
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(result["recordset"]));
});
});
From there, my axios calls look like this:
componentWillMount(){
let self = this;
axios.get("/getTable")
.then(function (response){
console.log(response.data);
self.setState({
data: response.data,
});
})
.catch(function (error){
console.log(error);
})
}
I added the console.log to check what was being returned, and as said, it was the HTML code of the current page of focus.
I made some changes to reflect what steps I took to get the 500 issue out. The current code, however, results in a 404.
If you move your get on top of your put it should work. The problem seems to be that the static clause resolves your request before it gets to your endpoint, so if you do this:
app.get('/counselling/triageadmin/getTable', function (req, res, next){
var request = new sql.Request(db);
request.query('select * from Counselling order by TicketID desc', (err, result) =>{
if (err) { return next(err); }
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(result["recordset"]));
});
});
app.use('/counselling/triageadmin/', express.static(path.join(__dirname, '/build')));
the path to the get will attempt to be matched before you're routed to your static files.
Ideally you would want to have your rest endpoints under a different namespace, i.e. /api but if you decide to keep your setup, this should help.
I think your routes might be conflicting with each other. From the express documentation at: http://expressjs.com/en/4x/api.html#app.use
// this middleware will not allow the request to go beyond it
app.use(function(req, res, next) {
res.send('Hello World');
});
// requests will never reach this route
app.get('/', function (req, res) {
res.send('Welcome');
});
Thus, your route '/counselling/triageadmin/getTable' will never be reached, because your route '/counselling/triageadmin/' is intercepting it, responding with static resources.
To solve this, try organizing your routes in a way that puts all of your API requests at a different subfolder, like '/api'. So your getTable endpoint would be located at: '/api/counselling/triageadmin/getTable/' or something like that.
I'm also learning the MEAN stack and I stumbled upon your question since I had the opposite problem. I wanted it to respond with an HTML instead of a JSON
this line of code MAKES it respond with an HTML
res.send(JSON.stringify(result["recordset"]));
(I tried res.send("<h3 HTML T_T </h3>");) and it did send and HTML
however, if you try
res.json(String(req.params.id)); <= Notice the res.json instead of res.send
It responds with a JSON :)
I hope this helped

Serving HTML file from Node server

Pretty much purely for pedagogical purposes, I'm serving both my front and back end data out of my one node server. Right now, I'm at the point where I've received my client request successfully, created some data based on said request, am able to console log it, etc. Everything is fine up to that point. My issue is that in the event that my data is only an html file, which is being read with the fs library, it will not render on the page when I attempt to serve it out in my res.end() or res.write(). I can see it's exactly what I want and expect when I console log it, but it just doesn't render in the browser. Any help would be appreciated. I've got it set up to where I'm handling my requests in an "if/else" wherein I only have the two scenarios of "/" (home), in which case I serve the html file, and anything else because the server really only needs to handle those two events. Thanks in advance.
Edit. This is what I have so far:
function responseHandler(req, res) {
res.writeHead(200, {"Content-Type": "text/html"});
if (req.url.match("fav")) {
res.end("");
return;
}
else if (req.url.match("/endpoint")) {
var input = req.url.match(/endpoint\/(.*)/)[1];
var output = endpoint.toHTML(decodeURI(input));
res.end(data);
console.log(input, req.url)
}
else {
fs.readFile("index.html", "utf8", function(err, data) {
console.log("data:" + data);
var input = req.url.match(/endpoint\/(.*)/)[1];
var output = endpoint.toHTML(decodeURI(input));
});
}
res.end();
}
I can see the data in the console which, in the last case, is just my HTML file. It just won't render in the page.
How did you attempted to serve the html with res.end() and res.write() ?
I just made a small test here, and this works:
app.js
var http = require('http');
var fs = require('fs');
var html = fs.readFileSync('hello-world.html');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(html);
}).listen(8000);
hello-world.html
<h3>Hello World</h3>
Edit: To match with your code, try this:
function responseHandler(req, res) {
res.writeHead(200, {"Content-Type": "text/html"});
if (req.url.match("fav")) {
res.end("");
return;
} else if (req.url.match("/endpoint")) {
var input = req.url.match(/endpoint\/(.*)/)[1];
var output = endpoint.toHTML(decodeURI(input));
console.log(input, req.url);
// we have no data variable in this scope
res.end("");
// I added a return statement in each step
// Just to be clear that we don't want to go if any
// condition have fit, since we cannot call res.end()
// more than once
return;
} else {
fs.readFile("index.html", "utf8", function(err, data) {
// error handling
if (err) return res.end(err);
// now we have the data
console.log("data:" + data);
res.end(data);
});
return;
}
}
Serving html in asynchronous way works something like that;
var fs = require('fs');
var http = require('http');
http.createServer(function(req, res){
res.writeHead(200, {'Content-Type': 'text/html'});
fs.readFile('index.html', function(err, data){
if(err){
return console.log(err);
}
res.end(data);
});
}).listen(8080);
console.log('Server is running on Port: 8080');