diff --git a/servers/express/basics/README.md b/servers/express/basics/README.md new file mode 100644 index 00000000..78115235 --- /dev/null +++ b/servers/express/basics/README.md @@ -0,0 +1,25 @@ +# Node.js Examples: express + +This directory contains some non-trivial examples for express. Express is an exemplary web server framework that implements a simple and powerful backend API interface. According to [their own website](https://expressjs.com/), express is a fast, unopinionated, minimalist web framework for Node.js. + +## References: +- npm: https://www.npmjs.com/package/express +- GitHub: https://github.com/expressjs/express +- website: https://expressjs.com/ + + +## Usage: + +`npm install` to install as a local project +`node index.js` to run as a standalone server +`npm test` to run the tests + +## Contributors ✨ + +Gireesh Punathil + +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! + +Contribution opportunities: + - adding a couple of more common scenarios + - tightening and widening the tests diff --git a/servers/express/basics/app.js b/servers/express/basics/app.js new file mode 100644 index 00000000..a07a4043 --- /dev/null +++ b/servers/express/basics/app.js @@ -0,0 +1,56 @@ +// An express example project to showcase few abstractions +// General layout is: +// - source-in the modules that implement individual functions +// - create an express server app +// - initialize each modules and setup their routes +// - listen for clients + +// main express module +var express = require('express') + +// implements response redirect +const redirect = require('./redirect.js') + +// implements session feature +const session = require('./session.js') + +// implements a file upload function +const upload = require('./upload.js') + +// a simple time retrieve function +const time = require('./time.js') + +// a simple db operation +const db = require('./db.js') + +// a default page that lists valid routes +const defaults = require('./defaults.js') + +// create the express app +var app = express() + +var server + +function start() { + // initialize the modules + redirect.setup(app) + session.setup(app) + upload.setup(app, express) + time.setup(app) + db.setup(app) + defaults.setup(app) + + // listen for clients! + server = app.listen(12000, () => { + console.log('waiting for client connections!') + console.log('access \'http://localhost:12000\' to get started!') + }) +} + +function stop() { + db.dbstop() + server.close() +} + +exports.stop = stop +exports.start = start diff --git a/servers/express/basics/db.js b/servers/express/basics/db.js new file mode 100644 index 00000000..9b3b6a85 --- /dev/null +++ b/servers/express/basics/db.js @@ -0,0 +1,75 @@ +// An example that shows a database operation. +// I used an in-memory mongodb server for this +// extract the client address, compute the current +// time and store these in the db. Respond back +// with the history of all client accesses. + +// server + +// source-in an in-memory server module +const { MongoMemoryServer } = require('mongodb-memory-server') + +// server host +const HOST = 'localhost' + +// server port +const PORT = 13000 + +// db instance name +const DBNAME = 'mydb' + +// server instance, created through dbstart +let mongod = null + +// start a server instance +async function dbstart() { + mongod = new MongoMemoryServer({instance: {port: PORT, dbName: DBNAME}}) + await mongod.getDbName() +} + +// stop the server instance +exports.dbstop = async function() { + if(mongod) + await mongod.stop() +} + +// client + +async function exec(req, res) { + // source-in the db client + const MongoClient = require('mongodb').MongoClient + + // start the db server + await dbstart() + const url = `mongodb://${HOST}:${PORT}` + + // connect to the db server + MongoClient.connect(url, (err, client) => { + const db = client.db(DBNAME) + const collection = db.collection('documents') + + // create a new record + var record = {} + record.time= new Date().toString() + record.client = req.connection.remoteAddress + + // insert the record into the db + collection.insertMany([record], function(err, result) { + + // retrieve all the records back + collection.find({}).toArray(function(err, docs) { + + // send it as the response. + res.end(JSON.stringify(docs)) + client.close() + }) + }) + }) +} + +exports.setup = function(app) { + app.get('/db', (req, res) => { + exec(req, res) + }) +} + diff --git a/servers/express/basics/defaults.js b/servers/express/basics/defaults.js new file mode 100644 index 00000000..ef5cff4c --- /dev/null +++ b/servers/express/basics/defaults.js @@ -0,0 +1,10 @@ +exports.setup = function(app) { + app.get('/', (req, res) => { + res.write('welcome to express examples! the options are:\n\n') + res.write('/time : yields the current server time\n') + res.write('/session : tracks the client visit count, with an expiry\n') + res.write('/upload : a single file upload function\n') + res.write('/db : a simple db example, with an in-memory mongodb\n') + res.end('/redirect : forwards to /landing, a simple demonstration of redirect function\n') + }) +} diff --git a/servers/express/basics/index.js b/servers/express/basics/index.js new file mode 100644 index 00000000..4ee87e17 --- /dev/null +++ b/servers/express/basics/index.js @@ -0,0 +1,4 @@ +// Entry point of the app when you ran as a server + +var app = require('./app.js') +app.start() diff --git a/servers/express/basics/package.json b/servers/express/basics/package.json new file mode 100644 index 00000000..7aaa1805 --- /dev/null +++ b/servers/express/basics/package.json @@ -0,0 +1,28 @@ +{ + "name": "express-basics", + "version": "1.0.0", + "description": "Express basic function examples", + "main": "index.js", + "directories": { + "test": "test" + }, + "scripts": { + "test": "tap test/*.js" + }, + "keywords": [ + "express", + "examples", + "nodejs" + ], + "author": "gpunathi@in.ibm.com", + "license": "Apache-2.0", + "devDependences": { + "tap": "^14.10.7" + }, + "dependencies": { + "express": "^4.17.1", + "express-session": "^1.17.1", + "mongodb-memory-server": "^6.6.1", + "multer": "^1.4.2" + } +} diff --git a/servers/express/basics/public/index.html b/servers/express/basics/public/index.html new file mode 100644 index 00000000..c7889062 --- /dev/null +++ b/servers/express/basics/public/index.html @@ -0,0 +1,10 @@ + + +
+Select file to upload: + + +
+ + + diff --git a/servers/express/basics/redirect.js b/servers/express/basics/redirect.js new file mode 100644 index 00000000..53b65af4 --- /dev/null +++ b/servers/express/basics/redirect.js @@ -0,0 +1,14 @@ +// An example that demonstrates +// response redirect functionality +// It redirects requests to /redirect, to /landing + +exports.setup = function(app) { + app.get('/redirect', (req, res) => { + res.redirect('/landing') + }) + + app.get('/landing', (req, res) => { + res.end('I am a redirect of /redirect') + }) +} + diff --git a/servers/express/basics/session.js b/servers/express/basics/session.js new file mode 100644 index 00000000..419530aa --- /dev/null +++ b/servers/express/basics/session.js @@ -0,0 +1,22 @@ +// An example that demonstrates +// express session functionality +// A session is created with expiry of 10 seconds +// and attached with the express app + +var session = require('express-session') + +exports.setup = function(app) { + app.use(session({ secret: 'random secret', cookie: { maxAge: 10000}})) + + app.get('/session', (req, res) => { + if (!req.session.views) { + req.session.views = 1 + } else { + req.session.views++ + } + if (req.session.views === 1) + res.end(`thanks for visiting ${req.session.views}st time! (session expires in 10 seconds)`) + else + res.end(`thanks for visiting ${req.session.views}th time! (session expires in 10 seconds)`) + }) +} diff --git a/servers/express/basics/test/db.js b/servers/express/basics/test/db.js new file mode 100644 index 00000000..686ed260 --- /dev/null +++ b/servers/express/basics/test/db.js @@ -0,0 +1,17 @@ +const request = require('request') +const server = require('../app.js') +const tap = require('tap') + +// start the server +server.start() + +// test the /db route +const url = 'http://localhost:12000/db' +request(url, (err, res, body) => { + if(err) + tap.fail(err) + else + tap.match(body, /client/, 'db record has keyword "client" in it') + server.stop() +}) + diff --git a/servers/express/basics/test/defaults.js b/servers/express/basics/test/defaults.js new file mode 100644 index 00000000..927e62e6 --- /dev/null +++ b/servers/express/basics/test/defaults.js @@ -0,0 +1,18 @@ +const request = require('request') +const server = require('../app.js') +const tap = require('tap') + +// start the server +server.start() + +// test the / route +const url = 'http://localhost:12000' +request(url, (err, res, body) => { + if(err) + tap.fail(err) + else + tap.match(body, /examples/, 'response string has keyword "examples" in it') + server.stop() +}) + + diff --git a/servers/express/basics/test/forward.js b/servers/express/basics/test/forward.js new file mode 100644 index 00000000..b2f5ff22 --- /dev/null +++ b/servers/express/basics/test/forward.js @@ -0,0 +1,18 @@ +const request = require('request') +const server = require('../app.js') +const tap = require('tap') + +// start the server +server.start() + +// test the /redirect route +const url = 'http://localhost:12000/a' +request(url, (err, res, body) => { + if(err) + tap.fail(err) + else + tap.match(body, /redirect/, 'response string has keyword "redirect" in it') + server.stop() +}) + + diff --git a/servers/express/basics/test/session.js b/servers/express/basics/test/session.js new file mode 100644 index 00000000..09666930 --- /dev/null +++ b/servers/express/basics/test/session.js @@ -0,0 +1,18 @@ +const request = require('request') +const server = require('../app.js') +const tap = require('tap') + +// start the server +server.start() + +// test the /session route +const url = 'http://localhost:12000/session' +request(url, (err, res, body) => { + if(err) + tap.fail(err) + else + tap.match(body, /visit/, 'response string has keyword "visit" in it') + server.stop() +}) + + diff --git a/servers/express/basics/test/time.js b/servers/express/basics/test/time.js new file mode 100644 index 00000000..68917b54 --- /dev/null +++ b/servers/express/basics/test/time.js @@ -0,0 +1,18 @@ +const request = require('request') +const server = require('../app.js') +const tap = require('tap') + +// start the server +server.start() + +// test the /time route +const url = 'http://localhost:12000/time' +request(url, (err, res, body) => { + if(err) + tap.fail(err) + else + tap.match(body, /GMT/, 'date string has GMT in it') + server.stop() +}) + + diff --git a/servers/express/basics/time.js b/servers/express/basics/time.js new file mode 100644 index 00000000..0ec34ee5 --- /dev/null +++ b/servers/express/basics/time.js @@ -0,0 +1,9 @@ +// An example that demonstrates +// a simple express route +// Return the current server time + +exports.setup = function(app) { + app.get('/time', (req, res) => { + res.end(new Date().toString()) + }) +} diff --git a/servers/express/basics/upload.js b/servers/express/basics/upload.js new file mode 100644 index 00000000..a392250f --- /dev/null +++ b/servers/express/basics/upload.js @@ -0,0 +1,20 @@ +var multer = require('multer') +var util = require('util') + + +exports.setup = function(app, express) { + + app.use('/upload', express.static('public')) + + var diskstore = multer.diskStorage({ + destination: function (req, file, cb) { + cb(null, './uploads') + } + }) + + var middleware = multer({ storage: diskstore}).single('upload') + + app.post('/upload', middleware, (req, res) => { + res.end(`file uploaded! Details:\n${util.inspect(req.file)}`) + }) +} diff --git a/servers/express/basics/uploads/8d11f6debe1418f9e5a37c3bb1b4e50d b/servers/express/basics/uploads/8d11f6debe1418f9e5a37c3bb1b4e50d new file mode 100644 index 00000000..973202de Binary files /dev/null and b/servers/express/basics/uploads/8d11f6debe1418f9e5a37c3bb1b4e50d differ