With express.js i can do this
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var port = 9200;
var path = require('path');
var options = {
index: "html/index.html"
};
app.use('/', express.static('res', options));
server.listen(port);
console.log("Listening on port " + port);
How do i achieve the same thing using Hapi.js?
I have tried some things also with inertjs but I can't seem to find the correct way. Does anyone have experience with it?
Found my way to this implementation, but im getting TypeErrors:
TypeError: Cannot read property 'register' of undefined
server.register(require('inert'), (err) => {
if (err) {
throw err;
}
server.route({
method: 'GET',
path: '/index',
handler: function (request, reply) {
reply.file('C:/blabla/html/index.html');
}
});
});
Straight from the doc
In detail, you just have to call reply.file()
This will not work with hapi 17 because of the major change in the request system
server.route({
method: 'GET',
path: '/picture.jpg',
handler: function (request, reply) {
reply.file('/path/to/picture.jpg');
}
});
Fixed by using Hapi#16.x.x and Inert#4.x.x and using Ernest Jones answer.
For anyone dealing with this problem in the future here is my complete change:
const Hapi = require('hapi');
const Inert = require('inert');
const server = new Hapi.Server();
server.connection({port: 9200});
server.register(Inert, (err) => {
if (err) {
throw err;
}
server.route({
method: 'GET',
path: '/index',
handler: function (request, reply) {
reply.file('/res/html/index.html');
}
});
server.route({
path: "/res/{path*}",
method: "GET",
handler: {
directory: {
path: "./res",
listing: false,
index: false
}
}});
});
server.start();
Related
I am new to mongodb and Hapi.js. I am trying to create an API for read requests, but am not sure how to write the handler method in server.route.
Here's how I have my mongoclient configured with hapi:
'use strict';
var MongoClient = require('mongodb').MongoClient; //using version 3.x
var Hapi = require('hapi');//using v16
var url = 'mongodb://****:****#ds131687.mlab.com:31687/learning_mongo';
var db;
var server = new Hapi.Server();
server.connection({
port:8080
});
server.route( [
// Get tour list
{
method: 'GET',
path: '/api/tours',
handler: function(request, reply){
collection.find().toArray(function(err,tours){
reply(tours);
});
}
},
// Home page
{
method: 'GET',
path: '/',
handler: function(request, reply) {
reply( "Hello world from Hapi/Mongo example.");
}
}
]);
var tours = function(db, callback) {
var collection = db.collection('tours');
collection.find().toArray(function(err, docs){
console.log(docs);
callback;
});
};
MongoClient.connect(url, function(err,client) {
server.start(function(err) {
tours(client.db('learning_mongo'), function(){
console.log('Hapi is listening to http://localhost:8080');
client.close();
});
});//end server
})
Going to the homepage path works fine, but when I go to ./api/tours path, I get the following error in terminal:
Debug: internal, implementation, error
ReferenceError: Uncaught error: collection is not defined
at handler (/home/ubuntu/workspace/index.js:22:13)
at Object.internals.handler (/home/ubuntu/workspace/node_modules/hapi/lib/handler.js:101:51)
at request._protect.run (/home/ubuntu/workspace/node_modules/hapi/lib/handler.js:32:23)
at module.exports.internals.Protect.internals.Protect.run (/home/ubuntu/workspace/node_modules/hapi/lib/protect.js:60:12)
at exports.execute (/home/ubuntu/workspace/node_modules/hapi/lib/handler.js:26:22)
at each (/home/ubuntu/workspace/node_modules/hapi/lib/request.js:401:16)
at iterate (/home/ubuntu/workspace/node_modules/items/lib/index.js:36:13)
at done (/home/ubuntu/workspace/node_modules/items/lib/index.js:28:25)
at module.exports.internals.Auth.internals.Auth._authenticate (/home/ubuntu/workspace/node_modules/hapi/lib/auth.js:222:16)
at internals.Auth.authenticate (/home/ubuntu/workspace/node_modules/hapi/lib/auth.js:197:17)
How do I correctly define the collection ? Thank you.
Your error message means that collection is out of scope inside the handler. You declare it inside the tours function.
But you also got have a minor error how you approach the database and the collection with the Mongoclient.
Let me show you how it would work while keeping your general set-up. There you can see that db can be accessed by the handler now.
'use strict';
var MongoClient = require('mongodb').MongoClient; //using version 3.x
var Hapi = require('hapi'); //using v16
var url = 'mongodb://****:****#ds131687.mlab.com:31687/';
var db;
var server = new Hapi.Server();
server.connection({
port: 8080
});
server.route([
// Get tour list
{
method: 'GET',
path: '/api/tours',
handler: function(request, reply) {
db.collection('tours').find().toArray(function(err, tours) {
reply(tours);
});
}
},
// Home page
{
method: 'GET',
path: '/',
handler: function(request, reply) {
reply("Hello world from Hapi/Mongo example.");
}
}
]);
var tours = function(db, callback) {
db.collection('tours').find().toArray(function(err, docs) {
console.log(docs);
callback;
});
};
new MongoClient.connect(url, function(err, client) {
db = client.db('learning_mongo')
server.start(function(err) {
tours(db, function() {
console.log('Hapi is listening to http://localhost:8080');
client.close();
});
}); //end server
})
I understand that this is only a learning example from your side. But maybe you want to consider starting with the latest hapijs version: 17. There are some bigger changes involved and it makes your life easier starting with that version now. Your short code has already lot of nested callbacks. Version 17 will support using await/async.
I have this code in Ionic app but I don't know how to make an API with Node.js to send this values to sever only by using Node.js.
submitForm() {
let headers = new Headers(
{
'Content-Type': 'application/json',
'Accept': 'application/json'
});
let options = new RequestOptions({ headers: headers });
let data = JSON.stringify({
Value1: this.form.value1,
Value2: this.form.value2,
Value3: this.form.value3
});
console.log(data);
let url = 'http://localhost:3000/calculate';
console.log(url);
return new Promise((resolve, reject) => {
this.http.post(url, data, options)
.toPromise()
.then((response) => {
console.log('API Response : ', response.status);
resolve(response.json());
})
.catch((error) => {
console.error('API Error : ', error.status);
console.error('API Error : ', JSON.stringify(error));
reject(error.json());
});
});
}
You may like to use ExpressJS. Following example may help you
Create a directory lets called api with following 2 files
create app.js in api directory
var http = require('http');
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.post('/calculate', function(req, res) {
var data = req.body;
console.log('Here are your data: ', data);
res.json({message: 'you posted successfully'});
});
var port = process.env.PORT || 3000;
var server = http.createServer(app);
server.listen(port);
server.on('error', function(){
console.error('Error')
});
server.on('listening', function(){
console.log('server started on port ' + port)
});
create package.json file in api directory
{
"name": "api",
"version": "1.0.0",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"body-parser": "~1.17.1",
"express": "~4.15.2"
}
}
now open command line/terminal and install dependencies by running following command(you must go to inside api directory)
npm install
now you can run by just running either npm start or node app.js
You should google for learning and studying and post questions for bug/issue
Update: without any dependencies or library but not recommended
It will be better to use http framework like express, sailsjs, etc. but if you like to play with nodejs then following example may help you
var http = require('http');
var port = process.env.PORT || 3000;
var server = http.createServer(function(req, res) {
var contentType = req.headers['content-type'];
var rawData = '';
req.on('data', function (chunk) {
rawData += chunk;
});
req.on('end', function () {
if(req.method === 'POST' && req.url === '/calculate' && contentType.indexOf('application/json')>-1){
try {
const data = JSON.parse(rawData);
console.log('Your data is here: ', data);
res.writeHead(200, { 'Content-Type': 'application/json'});
var result = {message: 'you have posted successfully'}
res.end(JSON.stringify(result));
} catch (e) {
console.error(e.message);
res.writeHead(400, { 'Content-Type': 'application/json'});
var result = {message: e.message}
res.end(JSON.stringify(result));
}
} else {
res.writeHead(404, { 'Content-Type': 'application/json'});
var result = {message: 'Url not found'}
res.end(JSON.stringify(result));
}
});
});
server.listen(port);
server.on('error', function(){
console.error('Error')
});
server.on('listening', function(){
console.log('server started on port ' + port)
});
I've created an example Node.js project that illustrates client/server request/response using AJAX and JSON. It "requires" only 'http', 'path', and 'fs'.
It implements a 'calculate' function server-side, and has a web page that presents 3 input boxes and a 'Calculate' button.
It's on Github: "https://github.com/bobwirka/NodeClientServer.git"
Hope this will be of help.
I try to learn from an example to use express together with handlebars on firebase.
For the express way, we can send the "app" instance directly to the "functions.https.onRequest" like...
const app = express();
...
app.get('/', (req, res) => {
...
});
exports.app = functions.https.onRequest(app);
See live functions
As my understanding it's working because "express" act like http-node, so it can respond "http plain".
Comparing to hapi, here is hello-world
const Hapi = require('hapi');
const server = new Hapi.Server();
server.connection({
host: 'localhost',
port: 8000
});
server.route({
method: 'GET',
path:'/hello',
handler: function (request, reply) {
return reply('hello world');
}
});
server.start((err) => {
console.log('Server running at:', server.info.uri);
});
From the hapi example, is it possible to use hapi on firebase cloud function?
Can I use hapi without starting a server like express?
This code was straight forward as i mixed the express API that used by Firebase with hapijs API, thanks to the blog given by mister #dkolba
You can ivoke the url hapijs handler by going to
http://localhost:5000/your-app-name/some-location/v1/hi
example: http://localhost:5000/helloworld/us-central1/v1/hi
const Hapi = require('hapi');
const server = new Hapi.Server();
const functions = require('firebase-functions');
server.connection();
const options = {
ops: {
interval: 1000
},
reporters: {
myConsoleReporter: [{
module: 'good-squeeze',
name: 'Squeeze',
args: [{ log: '*', response: '*' }]
}, {
module: 'good-console'
}, 'stdout']
}
};
server.route({
method: 'GET',
path: '/hi',
handler: function (request, reply) {
reply({data:'helloworld'});
}
});
server.register({
register: require('good'),
options,
}, (err) => {
if (err) {
return console.error(err);
}
});
// Create and Deploy Your First Cloud Functions
// https://firebase.google.com/docs/functions/write-firebase-functions
exports.v1 = functions.https.onRequest((event, resp) => {
const options = {
method: event.httpMethod,
url: event.path,
payload: event.body,
headers: event.headers,
validate: false
};
console.log(options);
server.inject(options, function (res) {
const response = {
statusCode: res.statusCode,
body: res.result
};
resp.status(res.statusCode).send(res.result);
});
//resp.send("Hellworld");
});
Have a look at the inject method (last code example): http://www.carbonatethis.com/hosting-a-serverless-hapi-js-api-with-aws-lambda/
However, I don't think that this is feasible, because you would still need to hold onto the response object of the express app instance Google Cloud Functions provide to http triggered functions, as only send(), redirect() or end() will work to respond to the incoming request and not hapi's methods (see https://firebase.google.com/docs/functions/http-events).
A few changes are required in order to get compatible with hapijs 18.x.x
'use strict';
const Hapi = require('#hapi/hapi')
, functions = require('firebase-functions');
const server = Hapi.server({
routes: {cors: true},
});
server.register([
{
plugin: require('./src/plugins/tools'),
routes: {
prefix: '/tools'
}
},
]);
server.route({
method: 'GET',
path: '/',
handler: (request, h) => {
return 'It worlks!';
}
});
exports.v1 = functions.https.onRequest((event, resp) => {
//resp: express.Response
const options = {
method: event.httpMethod,
headers: event.headers,
url: event.path,
payload: event.body
};
return server
.inject(options)
.then(response => {
delete response.headers['content-encoding']
delete response.headers['transfer-encoding']
response.headers['x-powered-by'] = 'hapijs'
resp.set(response.headers);
return resp.status(response.statusCode).send(response.result);
})
.catch(error => resp.status(500).send(error.message || "unknown error"));
});
I have my server.js file working. at localhost:8080 it will serve the file i give it from the the corresponding url name like so http://localhost:8080/about.html, as long as the file exists in public/pages. I'm wondering if I can somehow set a wildcard to leave of extensions for all html files in the url so that I don't have to individually specify each file as an alias in the routes like - ['about','about.html'].
Here is my working code -
'use strict';
const Path = require('path');
const Hapi = require('hapi');
const server = new Hapi.Server();
server.connection({
port: Number(process.argv[2] || 8080),
host: 'localhost'
});
server.register(require('inert'), (err) => {
if (err) {
throw err;
}
server.route({
method: 'GET',
path: '/{param*}',
handler: {
directory: {
path: 'public/pages',
listing: true
}
},
config: {
state: {
parse: false, // parse and store in request.state
failAction: 'ignore' // may also be 'ignore' or 'log'
}
}
});
server.start((err) => {
if (err) {
throw err;
}
console.log('Server running at:', server.info.uri);
});
});
Any help is greatly appreciated, thank you.
I'm trying to use SQL server and nodejs with my HTML file.
I'm connecting with my database with nodejs using mssql and hapijs, and i can obtain my table in json format, but i dont know how to obtain this information on my HTML.
Also, how can i make the server update from HTML?
Here is my nodejs code:
var http = require("http");
getData = function(callback){
var sql = require('mssql');
//Data Connection
sql.connect("mssql://username:password#localhost\\SQLEXPRESS/CrudExample?encrypt:true").then(function() {
// Query
new sql.Request().query('select * from MOCK_DATA').then(function(recordset) {
//console.dir(recordset);
callback(recordset)
response.writeHead(200, {"Content-Length": results.length});
response.writeHead(200, {"Content-Type": "application/json"});
response.end(results);
}).catch(function(err) {
// ... query error checks
});
}).catch(function(err) {
// ... connect error checks
console.log('Error en la consulta')
console.log(err)
});
}
const Hapi = require('hapi');
const Path = require('path');
// Create a server with a host and port
const server = new Hapi.Server({
connections: {
routes: {
files: {
relativeTo: Path.join(__dirname, 'public')
}
}
}
});
server.connection({
host: 'localhost',
port: 8000
});
// Add the route
// Start the server
server.register(require('inert'), (err) => {
if (err) {
throw err;
}
server.route({
method: 'GET',
path:'/getTable',
handler: function (request, reply) {
getData(function(r) {return reply(r)})
}
});
server.route({
method: 'GET',
path:'/',
handler: function (request, reply) {
reply("hello world")
}
});
server.start((err) => {
if (err) {
throw err;
}
console.log('Server running at:', server.info.uri);
});
});
You can use handlebars as a view engine
refer to http://hapijs.com/tutorials/views