"Mount" (run) legacy http handler in Hapi.js - node.js

I did a Node.js meetup presentation and was unable to answer this question. It is still bothering me.
Suppose I have a legacy http application or an Express.js application. It is a function, of the form
function legacy_app(request, response) {
// Handle the request.
}
Suppose I adopt Hapi.js for new versions of my application. But I have lots of debugged legacy or upstream code which I wish to integrate into the Hapi application. For example, a legacy vhost will run the legacy version, or it is accessible inside a /legacy namespace in the URL.
What is the best way to do this?

Wrapping existing HTTP node server dispatch function for use as a hapi handler is probably ok but you must add to your hapi_wrap function (at the end):
reply.close(false);
so that hapi can finish handling the request without messing with you legacy logic (https://github.com/spumko/hapi/blob/master/docs/Reference.md#replycloseoptions).
Wrapping Express handler/middleware is much more complicated because you are probably relying on some other middleware (e.g. body parser, cookie parse, session, etc.) and using some of the Express decorator that are not part of node (e.g. res.send(), res.json(), etc.).

The only way I can think to do this is manually. Just directly break the advice in the documentation: pull out the raw request and response objects and pass them to the legacy handler.
// An application built with http core.
var http = require('http')
var legacy_server = http.createServer(legacy_handler)
function legacy_handler(request, response) {
response.end('I am a standard handler\n')
}
// An express application.
var express = require('express')
var express_app = express()
express_app.get('*', function(request, response) {
response.send('I am an Express app\n')
})
// A Hapi application.
var Hapi = require('hapi')
var server = new Hapi.Server(8080, "0.0.0.0")
server.route({path:'/', method:'*', handler:hapi_handler})
function hapi_handler(request, reply) {
reply('I am a Hapi handler\n')
}
// Okay, great. Now suppose I want to hook the legacy application into the
// newer Hapi application, for example under a vhost or a /deprecated namespace.
server.route({path:'/legacy', method:'*', handler:hapi_wrap(legacy_handler)})
server.route({path:'/express', method:'*', handler:hapi_wrap(express_app)})
// Convert a legacy http handler into a Hapi handler.
function hapi_wrap(handler) {
return hapi_handler
function hapi_handler(request, reply) {
var req = request.raw.req
var res = request.raw.res
reply.close(false)
handler(req, res)
}
}
legacy_server.listen(8081)
express_app.listen(8082)
server.start()
This seems to work, although I would love if somebody who knew Hapi well could confirm that it is bug-free.
$ # Hit the Hapi application
$ curl localhost:8080/
I am a Hapi handler
$ # Hit the http application
$ curl localhost:8081/
I am a standard handler
$ # Hit the Express application
$ curl localhost:8082/
I am an Express app
$ # Hit the http application hosted by Hapi
$ curl localhost:8080/legacy
I am a standard handler
$ # Hit the Express application hosted by Hapi
$ curl localhost:8080/express
I am an Express app

Related

Using Both Express.js and Http module in NodeJS application

Currently, I am developing a simple project, which uses strong-soap module and expressjs. To create a soap server, I have to use http module of NodeJs, using express for soap module causes errors (wsdl file content can't be seen in browser). And i declare my routes and its functions by help of ExpressJS. My simple codebase is similar to the given below.
index.js
const app = require('express')();
const http = require('http');
var MyServiceObject = { /* ...some methods which exist in wsdl file */ };
var xml = require('fs').readFileSync('myWsdlFile.wsdl');
let server = http.createServer(function(request,response) {
response.end("404: Not Found: " + request.url);
});
server.listen(8000);
soap.listen(server, '/wsdl', MyServiceObject, xml);
/*########################### SOME ROUTES ############################################*/
app.listen(8002, (req, res) => {
console.log('App is listening on port 8002');
});
I am concerning about security, so i have a long question:
I'm not able to apply some authorization processes on HTTP Object in my code. How i can apply authorization on http? Is leaving http object as seen in code block, causes some security problems? Must i apply some authorization processes on http object? And i am using strong-soap server in this project. Must i apply some authorization processes on strong-soap object also. I can apply authorization processes on Express.js. Is applying authorization processes on express object (app) is sufficient for security?
Thanks in advance.
You can go with the soap package (https://www.npmjs.com/package/soap), you will get more flexibility to work with. Also, you can install the soap client (https://www.soapui.org/downloads/soapui/) to test services before implementing them with Node.js. It will help you to understand the request and response of each service.

Tracking and logging http calls made internally from a node.js server

I'm debugging calls made from my express app to another micro-service on my network. I'm receiving 401 errors and I need to get full raw http logs to give to my security team for analysis.
I'm looking for some advice on tracking HTTP calls from a micro-service I have deployed on Pivotal Cloud Foundry. I've been doing some research and ran across tools like Zipkin and OpenTracing etc.. but those appear to be more about debugging latency and probably do not show HTTP logs. I've also tried using Morgan/Winston modules but they do not track internal calls. Morgan is currently what I'm using to log out the basic HTTP codes but it doesn't pick up on my calls from inside my app either, just the ones made to the app itself from the browser. I need to get the full raw HTTP request to assist the security team. I'm using the default logging output with morgan (STDOUT). I've console logged the headers to see the headers but would like to get them out in a slightly more readable format.
To log internal HTTP request sent from a Node.js server, you can create a Proxy Node.js server and log all requests there using Morgan.
First, define 3 constants (or read from your project config file):
// The real API endpoint, such as "another micro-service" in your network
const API = http://<real_server>
// Proxy Node.js server running on localhost
const LOGGER_ENDPOINT=http://localhost:3010
// Flag, decide whether logger is enabled.
const ENABLE_LOGGER=true
Second, When your Node.js server is launched, start the logger server at the same time if ENABLE_LOGGER is true. The logger server only do one thing: log the request and forward it to the real API server using request module. You can use Morgan to provide more readable format.
const request = require('request');
const morgan = require('morgan')(':method :url :status Cookie: :req[Cookie] :res[content-length] - :response-time ms');
...
if (ENABLE_LOGGER && LOGGER_ENDPOINT) {
let loggerPort = 3010;
const logger = http.createServer((req, res) => {
morgan(req, res, () => {
req.pipe(request(API + req.url)).pipe(res);
});
});
logger.listen(loggerPort);
}
Third, in your Node.js server, send API request to logger server when ENABLE_LOGGER is true, and send API directly to the real server when ENABLE_LOGGER is false.
let app = express(); // assume Express is used, but this strategy can be easily applied to other Node.js web framework.
...
let API_Endpoint = ENABLE_LOGGER ? LOGGER_ENDPOINT : API;
app.set('API', API_Endpoint);
...
// When HTTP request is sent internally
request(app.get('API') + '/some-url')...

Using both http-server and node express server

I've seen the following setup for a node express server:
server.js
import { Server } from 'http';
import Express from 'express';
const app = new Express();
const server = new Server(app);
Since it is possible just to run express directly, what is the advantage here of returning the express server as an argument of the http server?
Express is a request handler for an HTTP server. It needs an HTTP server in order to run. You can either create one yourself and then pass app as the request handler for that or Express can create it's own HTTP server:
import Express from 'express';
const app = new Express();
app.listen(80);
But, just so you fully understand what's going on here. If you use app.listen(), all it is doing is this (as shown from the Express code):
app.listen = function listen() {
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
which is just creating its own vanilla http server and then calling .listen() on it.
If you are just using a plain vanilla http server, then it saves you some code to have Express create it for you so there's really no benefit to creating it for yourself. If, you want to create a server with some special options or configurations or if you want to create an HTTPS server, then you must create one yourself and then configure it with the Express request handler since Express only creates a plain vanilla http server if you ask it to create it yourself. So, create one yourself if you need to create it with special options.

Post request to third party service from node server

What is the best way to send POST request from node server which has received the request parameter from a client? Reason I am asking for best practice because it should not affect the response time if multiple clients are calling the node service.
Here is the Backbone Model which sends the request to node server:
var LoginModel = Backbone.Model.extend({
url:'http://localhost:3000/login',
defaults: {
email:"",
password:""
},
parse: function(resp) {
return resp;
},
login: function() {
console.log('Here in the model'+JSON.stringify(this));
this.save();
}
});
var loginModel = new LoginModel();
Node Server
var http = require('http'),
express = require('express');
var app = express();
app.listen(3000);
app.post('/login', [express.urlencoded(), express.json()], function(req, res) {
console.log('You are here'); console.log(JSON.stringify(req.body));
//Send the post request to third party service.
});
Should I use something like requestify inside app.post() function and make a call to third party service?
I like superagent personally but request is very popular. hyperquest is also worth consideration as it resolves some issues with just using the node core http module for this.
Reason I am asking for best practice because it should not affect the response time if multiple clients are calling the node service.
First, just get it working. After it's working you can consider putting a cache somewhere in your stack either between your clients and your api or between your server and the third party api. I'm of the opinion that if you don't know exactly where you need a cache, exactly why, and exactly how it will benefit your application, you don't need a cache, or at the very least, you aren't prepared instrumentation-wise to understand whether your cache is helping or not.

What does Express.js do in the MEAN stack?

I have recently have gotten into AngularJS and I love it. For an upcoming project I am looking to use the MEAN stack (MongoDB, Express, Angular, Node). I'm pretty familiar with Angular and I have a modest understanding of the purposes of MongoDB and Node in the stack. However, I don't really understand what the purpose of Express.js is. Is it essential to the MEAN stack? What would you compare it to in a traditional MySQL, PHP, javascript app? What does it do that the other three components can't do?
Also, if someone wants to give their own take on how the four parts of the stack work together, that'd be great.
MongoDB = database
Express.js = back-end web framework
Angular = front-end framework
Node = back-end platform / web framework
Basically, what Express does is that it enables you to easily create web applications by providing a slightly simpler interface for creating your request endpoints, handling cookies, etc. than vanilla Node. You could drop it out of the equation, but then you'd have to do a lot more work in whipping up your web-application. Node itself could do everything express is doing (express is implemented with node), but express just wraps it up in a nicer package.
I would compare Express to some PHP web framework in the stack you describe, something like slim.
You can think of Express as a utility belt for creating web applications with Node.js. It provides functions for pretty much everything you need to do to build a web server. If you were to write the same functionality with vanilla Node.js, you would have to write significantly more code. Here are a couple examples of what Express does:
REST routes are made simple with things like
app.get('/user/:id', function(req, res){ /* req.params('id') is avail */ });
A middleware system that allows you plug in different synchronous functions that do different things with a request or response, ie. authentication or adding properties
app.use(function(req,res,next){ req.timestamp = new Date(); next(); });
Functions for parsing the body of POST requests
Cross site scripting prevention tools
Automatic HTTP header handling
app.get('/', function(req,res){ res.json({object: 'something'}); });
Generally speaking, Sinatra is to Ruby as Express is to Node.js. I know it's not a PHP example, but I don't know much about PHP frameworks.
Express handles things like cookies, parsing the request body, forming the response and handling routes.
It also is the part of the application that listens to a socket to handle incoming requests.
A simple example from express github
var express = require('express');
var app = express();
app.get('/', function(req, res){
res.send('Hello World');
});
app.listen(3000);
Shows the creation of the express server, creating a route app.get('/'... and opening the port to listen for incoming http requests on.
Express allows you to manage http request easily compared to vanilla js.
you need to the following to make a get request
const Http = new XMLHttpRequest();
const url='https://jsonplaceholder.typicode.com/posts';
Http.open("GET", url);
Http.send();
Http.onreadystatechange=(e)=>{
console.log(Http.responseText)
}
In express, you require express and use it and make http requests
const express = require("express")
const app =express();
app.get("url",callback function);
Express in a Node.js based framework which simplifies writing Server-side Code and Logic.
Adds a lot of utility features and offers additional functionality, and in general, makes things easier.
Express is middleware-based : It basically funnels incoming requests through a chain of middlewares (of steps) where we can do something with the request, read some data from it, manipulate it, check if the user is authenticated or basically send back a response immediately.
This middlewares chain allows us to write very structured code
Express is a nodejs Framework build upon the top of Http module with more usable and better functionalities like easy way to handle routes.
eg: Using HTTP
var http = require('http');
//create a server object:
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'}); // http header
var url = req.url;
if(url ==='/about'){
res.write('<h1>about us page<h1>'); //write a response
res.end(); //end the response
}else if(url ==='/contact'){
res.write('<h1>contact us page<h1>'); //write a response
res.end(); //end the response
}else{
res.write('<h1>Hello World!<h1>'); //write a response
res.end(); //end the response
}
}).listen(3000, function(){
console.log("server start at port 3000"); //the server object listens on port 3000
});
using Express:
var express = require('express');
var app = express();
app.get('/about',function(req,res)=>{
res.write('<h1>about us page<h1>'); //write a response
res.end();
})

Resources