Repository navigation
Expand file tree
/
Copy pathcontent.json
More file actions
1 lines (1 loc) · 43.1 KB
/
Copy pathcontent.json
File metadata and controls
1 lines (1 loc) · 43.1 KB
1
{"meta":{"title":"Moret Consultancy","subtitle":"Freelance Developer","description":"Freelance Software Developer. Experienced Full Stack Developer with a focus on web and a passion for agile/scrum and DevOps. Broad interest in new technologies and always looking to improve myself.","author":"Luuk Moret","url":"http://moretconsultancy.com"},"pages":[{"title":"About me","date":"2016-09-06T11:52:26.876Z","updated":"2016-09-06T11:52:26.870Z","comments":true,"path":"about/index.html","permalink":"http://moretconsultancy.com/about/index.html","excerpt":"","text":"Freelance software developer. Only interested in contract jobs, not permanent positions. Email: jobs@moretconsultancy.com Experienced Full Stack Developer with a focus on web and a passion for agile/scrum and DevOps. Broad interest in new technologies and always looking to improve myself. Technologies I’m currently using: Agile/Scrum AWS Azure ASP.NET (MVC, WebAPI) AngularJS Bamboo C# Continuous Integration Continuous Delivery CSS3 DevOps Docker ECMAScript 6 Git HTML5 Javascript Microservices MongoDB MSSQL Server .NET Core NGINX Node.js Octopus Deploy Redis SASS TeamCity"},{"title":"Tags","date":"2016-08-29T09:08:52.942Z","updated":"2016-08-22T08:34:10.997Z","comments":true,"path":"tags/index.html","permalink":"http://moretconsultancy.com/tags/index.html","excerpt":"","text":""},{"title":"Categories","date":"2016-08-29T09:08:52.935Z","updated":"2016-08-22T08:34:10.987Z","comments":true,"path":"categories/index.html","permalink":"http://moretconsultancy.com/categories/index.html","excerpt":"","text":""}],"posts":[{"title":"How to create a modular RESTfull API with Node.js, Express and ECMAScript 6 Part 2","slug":"node-api-express-es6-part2","date":"2016-08-21T15:54:50.000Z","updated":"2016-08-22T09:23:47.411Z","comments":true,"path":"2016/08/21/node-api-express-es6-part2/","link":"","permalink":"http://moretconsultancy.com/2016/08/21/node-api-express-es6-part2/","excerpt":"This is part 2 of building a RESTful API with Node.js, Express and ECMAScript 6 using a module approach. Be sure to read part 1 first. Go to https://github.com/LuukMoret/blog-node-api-express-es6-part2 to see the finished code. Now that the project setup is done we can start writing our own modules.","text":"This is part 2 of building a RESTful API with Node.js, Express and ECMAScript 6 using a module approach. Be sure to read part 1 first. Go to https://github.com/LuukMoret/blog-node-api-express-es6-part2 to see the finished code. Now that the project setup is done we can start writing our own modules. Create dummies moduleCreate dummies folder inside the app foldermkdir app/dummies Create controller file dummies.controller.js inside app/dummies, this will handle the routing of the module. Add the following content:'use strict'; const express = require('express');const router = express.Router(); const dummiesService = require('./dummies.service'); router.get('/dummies', (req, res) => { dummiesService.getDummies() .then((response) => { res.send(response); }) .catch((response) => { res.status(response.statusCode).send(response.error); });}); module.exports = router; Update middleware/routes.js file by adding the newly created route. Replace the file with the following content:'use strict'; const winston = require('winston'); // https://www.npmjs.com/package/winston const dummiesRoute = require('../app/dummies/dummies.controller'); exports.register = (app) => { app.use(dummiesRoute); winston.info('app - routes: dummies loaded');}; Create service file dummies.service.js inside app/dummies, this will contain the (business) logic of the module. Add the following content:'use strict'; const dummiesRepository = require('./dummies.repository');const Dummies = require('./dummies.model'); exports.getDummies = () => { return new Promise((resolve, reject) => { dummiesRepository.getDummiesData() .then((response) => { // business logic const dummies = response.map((dummies) => new Dummies(dummies)); resolve(dummies); }) .catch((response) => { reject(response); }); });}; Create model file dummies.model.js inside app/dummies, this will handle data transformation. Add the following content:'use strict'; class Dummies { constructor(dummiesResponse) { this.id = dummiesResponse.id; this.name = dummiesResponse.login; }} module.exports = Dummies; Create repository file dummies.repository.js inside app/dummies, this will handle the repository calls (in this case git api call for demo purposes). Add the following content:'use strict'; const rp = require('request-promise'); exports.getDummiesData = () => { const options = { uri: 'https://api.github.com/users', headers: { 'User-Agent': 'Request-Promise' }, json: true // Automatically parses the JSON string in the response }; return rp(options) .then((response) => { return response; }) .catch((response) => { throw response; });}; We can test the application now. Run npm start and navigate with a browser to http://localhost:3100/dummies and you should see a json response from the node application. Now that we have written our dummies module it is time to write some unit and integration tests. Create controller spec file dummies.controller.spec.js inside app/dummies with the following content:'use strict'; const app = require('../../app');const server = app.listen();const winston = require('winston');const supertest = require('supertest').agent(server);const sinon = require('sinon');require('sinon-as-promised'); const dummiesService = require('./dummies.service'); let dummiesServiceStub; before(() => { try { winston.remove(winston.transports.Console); } catch (error) { }}); after(() => { server.close();}); afterEach(() => { if (dummiesServiceStub) { dummiesServiceStub.restore(); }}); describe('unit: dummies.controller - when getting dummies', () => { it('it should resolve and return dummies', () => { // arrange const dummies = [ {id: 1, login: 'dummy1'}, {id: 2, login: 'dummy2'}, {id: 3, login: 'dummy3'} ]; dummiesServiceStub = sinon .stub(dummiesService, 'getDummies') .resolves(dummies); // act + assert return supertest .get('/dummies') .expect(200, dummies); }); it('it should reject and return an error message', () => { // arrange dummiesServiceStub = sinon .stub(dummiesService, 'getDummies') .rejects({statusCode: 500, error: {error: 'error'}}); // act + assert return supertest .get('/dummies') .expect(500, {error: 'error'}); });}); Create service spec file dummies.service.spec.js inside app/dummies with the following content:'use strict'; const chai = require('chai');const expect = chai.expect;const sinon = require('sinon');require('sinon-as-promised'); const dummiesService = require('./dummies.service');const dummiesRepository = require('./dummies.repository'); let dummiesRepositoryStub; afterEach(() => { if (dummiesRepositoryStub) { dummiesRepositoryStub.restore(); }}); describe('unit: dummies.service - when getting dummies data', () => { it('it should resolve and return dummies data', () => { // arrange const dummiesResponse = [ {id: 1, login: 'dummy1', additionalData: 'data'}, {id: 2, login: 'dummy2', additionalData: 'data'}, {id: 3, login: 'dummy3', additionalData: 'data'} ]; const dummiesTransformedModel = [ {id: 1, name: 'dummy1'}, {id: 2, name: 'dummy2'}, {id: 3, name: 'dummy3'} ]; dummiesRepositoryStub = sinon .stub(dummiesRepository, 'getDummiesData') .resolves(dummiesResponse); // act + assert return dummiesService.getDummies() .then((response) => { expect(dummiesRepositoryStub.called).to.equal(true); expect(response).to.deep.equal(dummiesTransformedModel); }); }); it('it should reject the request and return an error message', () => { // arrange dummiesRepositoryStub = sinon .stub(dummiesRepository, 'getDummiesData') .rejects({error: 'error'}); // act + assert return dummiesService.getDummies() .catch((response) => { expect(dummiesRepositoryStub.called).to.equal(true); expect(response).to.deep.equal({error: 'error'}); }); });}); Create repository spec file dummies.repository.spec.js inside app/dummies with the following content:'use strict'; const chai = require('chai');const expect = chai.expect;const nock = require('nock'); const dummiesRepository = require('./dummies.repository'); afterEach(() => { nock.cleanAll();}); describe('unit: dummies.repository - when getting dummies data', () => { it('it should resolve and return dummies data', () => { // arrange const dummiesResponse = [ {id: 1, login: 'dummy1', additionalData: 'data'}, {id: 2, login: 'dummy2', additionalData: 'data'}, {id: 3, login: 'dummy3', additionalData: 'data'} ]; nock('https://api.github.com') .get('/users') .reply(200, dummiesResponse); // act + assert return dummiesRepository.getDummiesData() .then((response) => { expect(response).to.deep.equal(dummiesResponse); }); }); it('it should reject and return an error message', () => { // arrange nock('https://api.github.com') .get('/users') .replyWithError({'message': 'something awful happened', 'code': 'AWFUL_ERROR'}); // act + assert return dummiesRepository.getDummiesData() .catch((response) => { expect(response.error).to.deep.equal({'message': 'something awful happened', 'code': 'AWFUL_ERROR'}); }); });}); Create integration file dummies.integration.js inside app/dummies with the following content:'use strict'; const app = require('../../bin/www');const server = app.listen();const supertest = require('supertest').agent(server);const winston = require('winston');const nock = require('nock'); before(() => { try { winston.remove(winston.transports.Console); } catch (error) { }}); after(() => { server.close();}); afterEach(() => { nock.cleanAll();}); describe('integration: dummies.integration.js - when getting dummies', () => { const dummiesResponse = [ {id: 1, login: 'dummy'}, {id: 2, login: 'dummy2'} ]; const dummiesTransformationModel = [ {id: 1, name: 'dummy'}, {id: 2, name: 'dummy2'} ]; it('it should return dummies', () => { nock('https://api.github.com') .get('/users') .reply(200, dummiesResponse); return supertest .get('/dummies') .expect(200, dummiesTransformationModel); }); it('it should return not found', () => { nock('https://api.github.com') .get('/users') .reply(404); return supertest .get('/dummies') .expect(404); }); it('it should return error', () => { nock('https://api.github.com') .get('/users') .reply(500, {'message': 'something awful happened', 'code': 'AWFUL_ERROR'}); return supertest .get('/dummies') .expect(500, {'message': 'something awful happened', 'code': 'AWFUL_ERROR'}); });}); We are now able to run npm test and all unit tests and integration tests will kick off. A nice coverage report for the unit and integration tests will be generate in de /coverage folder. That’s it for this blog post! I will try to create a Yeoman template for this in the future. Feel free to leave feedback and comments or have any questions about this.","categories":[{"name":"Tutorials","slug":"Tutorials","permalink":"http://moretconsultancy.com/categories/Tutorials/"}],"tags":[{"name":"API","slug":"API","permalink":"http://moretconsultancy.com/tags/API/"},{"name":"REST","slug":"REST","permalink":"http://moretconsultancy.com/tags/REST/"},{"name":"Node","slug":"Node","permalink":"http://moretconsultancy.com/tags/Node/"},{"name":"Express","slug":"Express","permalink":"http://moretconsultancy.com/tags/Express/"},{"name":"ECMAScript","slug":"ECMAScript","permalink":"http://moretconsultancy.com/tags/ECMAScript/"}],"keywords":[{"name":"Tutorials","slug":"Tutorials","permalink":"http://moretconsultancy.com/categories/Tutorials/"}]},{"title":"How to create a modular RESTfull API with Node.js, Express and ECMAScript 6 Part 1","slug":"node-api-express-es6-part1","date":"2016-08-20T17:27:56.000Z","updated":"2016-08-22T09:52:12.595Z","comments":true,"path":"2016/08/20/node-api-express-es6-part1/","link":"","permalink":"http://moretconsultancy.com/2016/08/20/node-api-express-es6-part1/","excerpt":"In this 2 part blog post I will explain how to get started with building a RESTful API with Node.js, Express and ECMAScript 6 using a module approach. Go to https://github.com/LuukMoret/blog-node-api-express-es6-part1 to see the finished code. Node.jsNode.js is an asynchronous event driven JavaScript runtime, designed to build scalable network applications. Node.js can handle many connections concurrently in contrast to today’s more common concurrency model where OS threads are employed. Thread-based networking is relatively inefficient and very difficult to use. Furthermore, users of Node are free from worries of dead-locking the process, since there are no locks. Almost no function in Node directly performs I/O, so the process never blocks. Because nothing blocks, scalable systems are very reasonable to develop in Node. You can read more about Blocking vs Non-Blocking here. ExpressExpress is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. There are alternatives like Koa and Hapi but Express is definitely the most widely used web framework for node.js today. ECMAScript 6ECMAScript is a subset of JavaScript. JavaScript is basically ECMAScript at it’s core but builds upon it. Languages such as ActionScript, JavaScript, JScript all use ECMAScript as its core. ECMAScript 6, also known as ECMAScript 2015, is the latest version of the ECMAScript standard. ES6 is a significant update to the language, and the first update to the language since ES5 was standardized in 2009. Read more about these new features here. There is also a fantastic JavaScript Style Guide from Airbnb. If you want to enforce these rules in your project, consider using the airbnb eslint npm package found here . With the above technologies explained we can start writing our node api!","text":"In this 2 part blog post I will explain how to get started with building a RESTful API with Node.js, Express and ECMAScript 6 using a module approach. Go to https://github.com/LuukMoret/blog-node-api-express-es6-part1 to see the finished code. Node.jsNode.js is an asynchronous event driven JavaScript runtime, designed to build scalable network applications. Node.js can handle many connections concurrently in contrast to today’s more common concurrency model where OS threads are employed. Thread-based networking is relatively inefficient and very difficult to use. Furthermore, users of Node are free from worries of dead-locking the process, since there are no locks. Almost no function in Node directly performs I/O, so the process never blocks. Because nothing blocks, scalable systems are very reasonable to develop in Node. You can read more about Blocking vs Non-Blocking here. ExpressExpress is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. There are alternatives like Koa and Hapi but Express is definitely the most widely used web framework for node.js today. ECMAScript 6ECMAScript is a subset of JavaScript. JavaScript is basically ECMAScript at it’s core but builds upon it. Languages such as ActionScript, JavaScript, JScript all use ECMAScript as its core. ECMAScript 6, also known as ECMAScript 2015, is the latest version of the ECMAScript standard. ES6 is a significant update to the language, and the first update to the language since ES5 was standardized in 2009. Read more about these new features here. There is also a fantastic JavaScript Style Guide from Airbnb. If you want to enforce these rules in your project, consider using the airbnb eslint npm package found here . With the above technologies explained we can start writing our node api! Prerequisites Node.js 6 or higher should be installed. Git should be installed. Project setupStart by creating a folder and cd into it:mkdir mynodeapi && cd mynodeapi Install the official express generator:npm install express-generator -g Run the express generator:express -e --git -e defaults to ejs engine instead of jade as (usually) won’t be needing this with an api. We will remove these files later.--git will add a .gitignore file.Install the necessary npm packages:npm install Create middleware folder and app folder:mkdir middleware app Delete routes folder, views and public folders:rm -rf routes views public Remove unused dependencies:npm uninstall --save ejs Install runtime dependenciesnpm install --save compression cors helmet lodash longjohn nconf request request-debug request-promise winston Short explanation of each dependency: compression - adds gzip compression. cors - adds cors support. helmet - Helmet helps you secure your Express apps by setting various HTTP headers. It’s not a silver bullet, but it can help! lodash - Lodash makes JavaScript easier by taking the hassle out of working with arrays, numbers, objects, strings, etc. nconf - Hierarchical node.js configuration with files, environment variables, command-line arguments, and atomic object merging. longjohn - Long stack traces for node.js with configurable call trace length. request-debug - an easy way to monitor HTTP(S) requests performed by the request module, and their responses from external servers. request-promise - adds a Bluebird-powered .then(…) method to Request call objects. winston - a simple and universal logging library with support for multiple transports. Install compile time dependenciesnpm install --save-dev chai eslint eslint-config-standard eslint-plugin-promise eslint-plugin-standard eslint-watch istanbul mocha nock nodemon sinon sinon-as-promised supertest Short explanation of each dependency: chai - BDD/TDD assertion library for node.js and the browser. Test framework agnostic. eslint - a tool for identifying and reporting on patterns found in ECMAScript/JavaScript code. eslint-config-standard - module needed for eslint-watch eslint-plugin-promise - module needed for eslint-watch eslint-plugin-standard - module needed for eslint-watch eslint-watch - a simple command line tool that wraps Eslint. Eslint Watch provides file watching and command line improvements to the currently existing Eslint command line interface. istanbul - JS code coverage tool that computes statement, line, function and branch coverage with module loader hooks to transparently add coverage when running tests. mocha - simple, flexible, test framework nock - an HTTP mocking and expectations library for Node.js nodemon - nodemon will watch the files in the directory in which nodemon was started, and if any files change, nodemon will automatically estart your node application. sinon - standalone and test framework agnostic JavaScript test spies, stubs and mocks. sinon - as-promised -sinon with promises supertest - the motivation with this module is to provide a high-level abstraction for testing HTTP, while still allowing you to drop down to the lower-level API provided by super-agent. Configure ESLintESLint is a pluggable linting utility for JavaScript. We can use this to enforce code styling rules. Create the following files in the project directory to configure ESLint:.eslintignore with the following content: /public/**/*.js/coverage/**/*.js .eslintrc.yml with the following content:extends: standardplugins: - standardparserOptions: ecmaversion: 6env: node: true es6: true mocha: truerules: semi: - error - always quotes: - error - single curly: error space-before-function-paren: off You can adjust these options as needed. Add NPM TasksUpdate the scripts section with the following npm tasks in the package.json file: start - start the application and watch for file changes test - kicks off build process build - run lint, tests and coverage lint - run lint lint:watch - run lint continuously and watch for file changes test:single - run tests unit-tests - run unit tests unit-tests:watch - run unit-tests continuously and watch for file changes integration-tests - run integration tests coverage - run coverage for all tests coverage-unit-tests - run coverage for unit tests coverage-integration-tests - run coverage for integration tests \"start\": \"npm install && nodemon ./bin/www\",\"test\": \"npm run build\",\"build\": \"npm install && npm run lint && npm run test:single && npm run coverage\",\"lint\": \"esw .\",\"lint:watch\": \"esw . -w\",\"test:single\": \"npm run unit-tests && npm run integration-tests\",\"unit-tests\": \"mocha --check-leaks --harmony app/**/*.spec.js\",\"unit-tests:watch\": \"mocha --check-leaks --harmony app/**/*.spec.js -w\",\"integration-tests\": \"mocha --check-leaks --harmony app/**/*.integration.js\",\"coverage\": \"npm run coverage-unit-tests && npm run coverage-integration-tests\",\"coverage-unit-tests\": \"istanbul cover --root app --dir ./coverage/unit -x **/**/*.integration.js -x **/**/*.spec.js ./node_modules/mocha/bin/_mocha -- --check-leaks --harmony --grep unit app/**/*.js\",\"coverage-integration-tests\": \"istanbul cover --root app --dir ./coverage/integration -x **/**/*.integration.js -x **/**/*.spec.js ./node_modules/mocha/bin/_mocha -- --check-leaks --harmony --grep integration app/**/*.js\" npm start and npm test can be run as is, the other tasks need to include the run keyword.npm run build for example. Create additional filesCreate config.json to store configurable properties with the following content:{ \"application\": { \"port\": 3100, \"local\": \"true\" }, \"logging\": { \"level\": \"info\" }} Create middleware/configs.js to bootstrap nconf with the following content:'use strict'; const winston = require('winston'); // https://www.npmjs.com/package/winstonconst nconf = require('nconf'); // https://www.npmjs.com/package/nconfconst path = require('path'); // https://www.npmjs.com/package/path exports.register = () => { let rootPath = path.join(__dirname, '../'); let configFile = 'config.json'; // 1. any overrides nconf.overrides({}); // 2. `process.env` // 3. `process.argv` nconf.env() .argv(); // 4. Values in `config.json` nconf.file(rootPath + configFile); // 5. Any default values nconf.defaults({ application: { port: 3100 } }); // Log current configuration winston.info('app - config: logging: ', nconf.get('logging')); winston.info('app - config: config file loaded from: ', rootPath + configFile); winston.info('app - config: application:', nconf.get('application')); winston.info('app - config: nconf loaded');}; Create middleware/handlers.js to configure default http handlers with the following content:'use strict'; const winston = require('winston'); // https://www.npmjs.com/package/winston exports.register = (app) => { registerDefaultHandler(app); winston.info('app - handlers: default handler loaded'); registerNotFoundHandler(app); winston.info('app - handlers: not found handler loaded'); registerErrorHandler(app); winston.info('app - handlers: error handler loaded');}; function registerDefaultHandler(app) { app.get('/', (req, res) => { res.send(''); });} function registerNotFoundHandler(app) { app.use((req, res, next) => { let err = new Error('Not Found'); err.status = 404; next(err); });} /** * development error handler, will print stacktrace * production error handler, no stack traces leaked to user * @param app */function registerErrorHandler(app) { if (app.get('env') === 'development') { app.use((err, req, res, next) => { res.status(err.status || 500) .send({message: err.message, error: err}); }); } app.use((err, req, res, next) => { res.status(err.status || 500) .send(err.message); });} Create middleware/routes.js, this will contain the routes of each module. Add the following content:'use strict'; exports.register = (app) => { }; Create middleware/utils.js with the following content:'use strict'; const winston = require('winston'); // https://www.npmjs.com/package/winstonconst morgan = require('morgan'); // https://www.npmjs.com/package/morganconst cookieParser = require('cookie-parser'); // https://www.npmjs.com/package/cookie-parserconst bodyParser = require('body-parser'); // https://www.npmjs.com/package/body-parserconst cors = require('cors'); // https://www.npmjs.com/package/corsconst helmet = require('helmet'); // https://www.npmjs.com/package/helmetconst nconf = require('nconf'); // https://www.npmjs.com/package/nconfconst compression = require('compression'); // https://www.npmjs.com/package/compressionconst rp = require('request-promise'); // https://www.npmjs.com/package/request-promise exports.register = (app) => { let verboseLogging = (nconf.get('logging:level') === 'debug'); let local = (nconf.get('application:local') === 'true'); if (verboseLogging || local) { winston.info('app - utils: debug logging enabled loaded'); app.use(morgan('dev')); try { winston.remove(winston.transports.Console); } catch (error) { } winston.add(winston.transports.Console, {'timestamp': true}); winston.info('app - utils: morgan dev loaded'); require('longjohn'); // https://www.npmjs.com/package/longjohn winston.info('app - utils: longjohn loaded'); if (verboseLogging || !local) { require('request-debug')(rp); // https://www.npmjs.com/package/request-debug winston.info('app - utils: request-debug loaded'); } } else { app.use(morgan('combined')); winston.info('app - utils: morgan combined loaded'); } app.use(compression()); winston.info('app - utils: gzip compression loaded'); app.use(cookieParser()); winston.info('app - utils: cookieparser loaded'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: false})); winston.info('app - utils: bodyparser loaded'); app.use(cors()); winston.info('app - utils: cors loaded'); app.options('*', cors()); winston.info('app - utils: cors preflight loaded'); app.use(helmet()); winston.info('app - utils: helmet loaded');}; Update the app.js file, which will bootstrap the middleware components. Replace the entire file with the following content:'use strict'; const winston = require('winston');const nconf = require('nconf'); winston.info('app: configs loading');const configs = require('./middleware/configs');configs.register();winston.info('app: configs loaded'); winston.info('app loading'); winston.info('app: express loading');const express = require('express');let app = express();winston.info('app: express loaded'); winston.info('app: utils loading');const utils = require('./middleware/utils');utils.register(app);winston.info('app: utils loaded'); winston.info('app: routes loading');const routes = require('./middleware/routes');routes.register(app);winston.info('app: routes loaded'); winston.info('app: handlers loading');const handlers = require('./middleware/handlers');handlers.register(app);winston.info('app: handlers loaded'); winston.info('app loaded'); winston.level = nconf.get('logging:level'); module.exports = app; Update the bin/www file, the entry point of the application. Replace the entire file with the following content:#!/usr/bin/env node'use strict'; /** * Module dependencies. */ const nconf = require('nconf');const app = require('../app');const debug = require('debug')('source:server');const http = require('http');const winston = require('winston'); winston.info('http loading');const port = normalizePort(nconf.get('application:port'));const server = http.createServer(app);app.set('port', port);server.listen(port);server.on('error', onError);server.on('listening', onListening);winston.info('http loaded'); winston.info('node application started and listening on port', port); /** * Normalize a port into a number, string, or false. */function normalizePort(val) { let port = parseInt(val, 10); if (isNaN(port)) { // named pipe return val; } if (port >= 0) { // port number return port; } return false;} /** * Event listener for HTTP server \"error\" event. */function onError(error) { if (error.syscall !== 'listen') { throw error; } let bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port; // handle specific listen errors with friendly messages switch (error.code) { case 'EACCES': console.error(bind + ' requires elevated privileges'); process.exit(1); break; case 'EADDRINUSE': console.error(bind + ' is already in use'); process.exit(1); break; default: throw error; }} /** * Event listener for HTTP server \"listening\" event. */function onListening() { let addr = server.address(); let bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; debug('Listening on ' + bind);} module.exports = server; Run npm start to start the application. You should be able to navigate to http://localhost:3100/ now (which will serve an empty page). That’s it! The project setup is now done! We will discuss writing modules in part 2.","categories":[{"name":"Tutorials","slug":"Tutorials","permalink":"http://moretconsultancy.com/categories/Tutorials/"}],"tags":[{"name":"API","slug":"API","permalink":"http://moretconsultancy.com/tags/API/"},{"name":"REST","slug":"REST","permalink":"http://moretconsultancy.com/tags/REST/"},{"name":"Node","slug":"Node","permalink":"http://moretconsultancy.com/tags/Node/"},{"name":"Express","slug":"Express","permalink":"http://moretconsultancy.com/tags/Express/"},{"name":"ECMAScript","slug":"ECMAScript","permalink":"http://moretconsultancy.com/tags/ECMAScript/"}],"keywords":[{"name":"Tutorials","slug":"Tutorials","permalink":"http://moretconsultancy.com/categories/Tutorials/"}]},{"title":"Getting started with ASP.NET 5 and Docker","slug":"asp-net-5-with-docker","date":"2015-12-08T21:54:02.000Z","updated":"2016-08-22T08:34:10.890Z","comments":true,"path":"2015/12/08/asp-net-5-with-docker/","link":"","permalink":"http://moretconsultancy.com/2015/12/08/asp-net-5-with-docker/","excerpt":"In this short tutorial I will explain how to get started with an ASP.NET 5 WebAPI application and how to deploy this in a Docker Container. ASP.NET 5 is an open source web framework for building modern web applications that can be developed and run on Windows, Linux and the Mac. It includes the MVC 6 framework, which now combines the features of MVC and Web API into a single web programming framework. ASP.NET 5 will also be the basis for SignalR 3 - enabling you to add real time functionality to cloud connected applications. ASP.NET 5 is built on the .NET Core runtime, but it can also be run on the full .NET Framework for maximum compatibility. Some of the improvements of ASP.NET 5: Build and run cross-platform ASP.NET apps on Windows, Mac and Linux Built on .NET Core, which supports true side-by-side app versioning New tooling that simplifies modern Web development Single aligned web stack for Web UI and Web APIs Cloud-ready environment-based configuration Integrated support for creating and using NuGet packages Built-in support for dependency injection Ability to host on IIS or self-host in your own process Docker is a platform for developers and sysadmins to develop, ship, and run applications. Docker lets you quickly assemble applications from components and eliminates the friction that can come when shipping code. Docker lets you get your code tested and deployed into production as fast as possible. Some of the benefits of Docker: Easily build new containers, enable rapid iteration of your applications, and increase the visibility of changes. This helps everyone in your organization understand how an application works and how it is built. Docker containers are lightweight and fast! Containers have sub-second launch times, reducing the cycle time of development, testing, and deployment. Docker containers run (almost) everywhere. You can deploy containers on desktops, physical servers, virtual machines, into data centers, and up to public and private clouds. Since Docker runs on so many platforms, it’s easy to move your applications around. You can easily move an application from a testing environment into the cloud and back whenever you need. Docker’s lightweight containers also make scaling up and down fast and easy. You can quickly launch more containers when needed and then shut them down easily when they’re no longer needed. Docker containers don’t need a hypervisor, so you can pack more of them onto your hosts. This means you get more value out of every server and can potentially reduce what you spend on equipment and licenses. As Docker speeds up your work flow, it gets easier to make lots of small changes instead of huge, big bang updates. Smaller changes mean reduced risk and more uptime.","text":"In this short tutorial I will explain how to get started with an ASP.NET 5 WebAPI application and how to deploy this in a Docker Container. ASP.NET 5 is an open source web framework for building modern web applications that can be developed and run on Windows, Linux and the Mac. It includes the MVC 6 framework, which now combines the features of MVC and Web API into a single web programming framework. ASP.NET 5 will also be the basis for SignalR 3 - enabling you to add real time functionality to cloud connected applications. ASP.NET 5 is built on the .NET Core runtime, but it can also be run on the full .NET Framework for maximum compatibility. Some of the improvements of ASP.NET 5: Build and run cross-platform ASP.NET apps on Windows, Mac and Linux Built on .NET Core, which supports true side-by-side app versioning New tooling that simplifies modern Web development Single aligned web stack for Web UI and Web APIs Cloud-ready environment-based configuration Integrated support for creating and using NuGet packages Built-in support for dependency injection Ability to host on IIS or self-host in your own process Docker is a platform for developers and sysadmins to develop, ship, and run applications. Docker lets you quickly assemble applications from components and eliminates the friction that can come when shipping code. Docker lets you get your code tested and deployed into production as fast as possible. Some of the benefits of Docker: Easily build new containers, enable rapid iteration of your applications, and increase the visibility of changes. This helps everyone in your organization understand how an application works and how it is built. Docker containers are lightweight and fast! Containers have sub-second launch times, reducing the cycle time of development, testing, and deployment. Docker containers run (almost) everywhere. You can deploy containers on desktops, physical servers, virtual machines, into data centers, and up to public and private clouds. Since Docker runs on so many platforms, it’s easy to move your applications around. You can easily move an application from a testing environment into the cloud and back whenever you need. Docker’s lightweight containers also make scaling up and down fast and easy. You can quickly launch more containers when needed and then shut them down easily when they’re no longer needed. Docker containers don’t need a hypervisor, so you can pack more of them onto your hosts. This means you get more value out of every server and can potentially reduce what you spend on equipment and licenses. As Docker speeds up your work flow, it gets easier to make lots of small changes instead of huge, big bang updates. Smaller changes mean reduced risk and more uptime. PrerequisitesThe following tools and frameworks will be used during this tutorial: ASP.NET 5 RC - https://github.com/aspnet/homeASP.NET 5 is a new open-source, cross-platform, high performance and lightweight framework for building Web Applications using .NET. Docker Toolbox - https://www.docker.com/docker-toolboxThe Docker Toolbox is an installer to quickly and easily install and setup a Docker environment on your computer. Available for both Windows and Mac, the Toolbox installs Docker Client, Machine, Compose, Kitematic and VirtualBox. Yeoman - http://yeoman.io/Yeoman is an open source client-side development stack, consisting of tools and frameworks intended to help developers quickly build high quality web applications. Note: During this tutorial I will be using a Windows machine but this should also work for OS X or Linux. We will start by installing the dnvm. This is the new .NET Version Manager, a set of command line utilities to update and configure which .NET Runtime to use. Fire up a cmd prompt and run the following command: @powershell -NoProfile -ExecutionPolicy unrestricted -Command "&{$Branch='dev';$wc=New-Object System.Net.WebClient;$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;$wc.Proxy.Credentials=[System.Net.CredentialCache]::DefaultNetworkCredentials;Invoke-Expression ($wc.DownloadString('https://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.ps1'))}" This will download the DNVM script and put it in your user profile. You can check the location of DNVM by running the following command in a cmd prompt: where dnvm Now run dnvm and install the dnx when prompted. Next, download and install the Docker Toolbox for Windows. Be sure to check Docker Client, Docker Machine, Docker Compose and VirtualBox. You can optionally check Docker Kitematic. Lastly, we install Yeoman by running the following command: npm install -g yo and install the Yeoman generator for ASP.NET 5 projects by running npm install -g generator-aspnet. Note: You need to have Node.js installed on your system to be able install node packages Creating the applicationWe are now ready to create our application! Start by executing yo aspnet and select the option Web API Application. After the application is completed cd into the newly created folder and run dnu restore. This will install any missing NuGet packages. You can optionally run dnu build which will compile the application, but this step is optional as it will automatically build the application when you run it. We can run the application by executing dnx web. The application will, by default, run at http://localhost:5000. When you navigate to http://localhost:5000/api/values you should see the JSON response ["value1","value2"]. Now that we have the application running, we can deploy it in a container so we can easily share it with other people, or fire it up in an continuous integration workflow to perform automated tests. Creating the Docker containerDockerfileDocker can build images automatically by reading the instructions from a Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Using docker build we can create an automated build that executes several command-line instructions in succession. A Dockerfile should already by created when you scaffolded the project with Yeoman. Open this file and replace the content with the following code: FROM microsoft/aspnet:1.0.0-rc1-final-coreclr COPY . /demo WORKDIR /demo RUN ["dnu", "restore"] EXPOSE 5000 ENTRYPOINT ["dnx", "web"] FROM will pull the microsoft/aspnet image from Docker Hub (which is based on Debian “jessie”). COPY will copy everything from the current directory to a folder called demo in the container. WORKDIR changes the working directory to this folder and execute dnu restore. EXPOSE informs Docker that the container listens on the specified network ports at runtime. EXPOSE does not make the ports of the container accessible to the host. To do that, you must use either the -p flag to publish a range of ports or the -P flag to publish all of the exposed ports. You can expose one port number and publish it externally under another number. This is mostly used as a documentation mechanism Finally, open the file project.json and replace the code block "commands": { "web": "Microsoft.AspNet.Server.Kestrel" }, with "commands": { "web": "Microsoft.AspNet.Server.Kestrel --server.urls http://*:5000" }, The important part is the *, otherwise the Kestrel web server, A web server for ASP.NET 5 based on libuv, will only listen for localhost and we want it to listen everywhere. DockerNow we are ready to create our container. Start the Docker Quickstart Terminal. There should be a shortcut on your desktop when you installed the Docker Toolbox. Navigate to the folder that contains the Dockerfile. cd C:/demo/WebAPIApplication Run the following command docker build -t demo . This will create an image based on the Dockerfile. When the image is done building, we can run the container with the following commanddocker run --name=demo -d -p 5000:5000 demo --name=demo will be the name of the container.-d runs the container in detached mode.-p will map the port of the Docker Host to the port of the container.demo refers to the demo image we just created with the docker build command. Now that the container is running, we can access it through the Docker Host. To get the IP address of the docker host, run the following command. docker-machine ip default. The default IP address should be 192.168.99.100. The application with the JSON response endpoint should now be accessible at http://192.168.99.100:5000/api/values. The ASP.NET WebAPI application is now running inside a Docker Container based on a Docker Host running Linux. DockerNow that the container is running, we can access it through the Docker Host. To get the IP address of the docker host, run the following command. docker-machine ip default. The default IP address should be 192.168.99.100. The application with the JSON response endpoint should now be accessible at http://192.168.99.100:5000/api/values. To stop the container simply run docker stop demo and to start it again run docker start demo. Closing notesThese are just the basics to get up and running with ASP.NET 5 and Docker containers. I encourage you to take a look at the new structure and features of ASP.NET 5 and explore the different Docker commands available. Visit the following sites to read more about these topics: http://docs.docker.com/windows/started/ https://github.com/aspnet/home/ https://code.visualstudio.com/Docs/runtimes/ASPnet5 http://blogs.msdn.com/b/webdev/archive/2015/01/14/running-asp-net-5-applications-in-linux-containers-with-docker.aspx http://www.hanselman.com/blog/BrainstormingDevelopmentWorkflowsWithDockerKitematicVirtualBoxAzureASPNETAndVisualStudio.aspx http://weblogs.asp.net/scottgu/introducing-asp-net-5 https://docs.docker.com/engine/misc/","categories":[{"name":"Tutorials","slug":"Tutorials","permalink":"http://moretconsultancy.com/categories/Tutorials/"}],"tags":[{"name":"ASPNET","slug":"ASPNET","permalink":"http://moretconsultancy.com/tags/ASPNET/"},{"name":"Docker","slug":"Docker","permalink":"http://moretconsultancy.com/tags/Docker/"},{"name":"WebAPI","slug":"WebAPI","permalink":"http://moretconsultancy.com/tags/WebAPI/"},{"name":"API","slug":"API","permalink":"http://moretconsultancy.com/tags/API/"},{"name":"REST","slug":"REST","permalink":"http://moretconsultancy.com/tags/REST/"},{"name":"Yeoman","slug":"Yeoman","permalink":"http://moretconsultancy.com/tags/Yeoman/"}],"keywords":[{"name":"Tutorials","slug":"Tutorials","permalink":"http://moretconsultancy.com/categories/Tutorials/"}]}]}