├── .editorconfig ├── .eslintignore ├── .gitattributes ├── .gitignore ├── .travis.yml ├── .vscode └── tasks.json ├── .yo-rc.json ├── LICENSE ├── README.md ├── __tests__ └── app.js ├── check-for-publish.sh ├── generators └── app │ ├── index.js │ └── templates │ ├── .vscode │ ├── launch.json │ ├── settings.json │ └── tasks.json │ ├── Dockerfile.all.projectName-api-base │ ├── Dockerfile.debug.projectName-api │ ├── Dockerfile.release.projectName-api │ ├── _gitignore │ ├── _package.json │ ├── docker-compose.debug.yml │ ├── docker-compose.yml │ ├── src │ ├── app │ │ ├── apicontrollers │ │ │ ├── HealthCheckApiController.ts │ │ │ └── IApiController.ts │ │ └── data │ │ │ └── DataProcess.ts │ ├── infrastructure │ │ ├── ApiServer.ts │ │ └── IInitializable.ts │ └── server.ts │ ├── tsconfig.json │ ├── tslint.json │ └── typings.json ├── package-lock.json ├── package.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | **/templates 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 10 4 | - 12 5 | cache: yarn 6 | before_install: 7 | - npm install -g yo 8 | - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- 9 | - export PATH="$HOME/.yarn/bin:$PATH" 10 | after_script: 'cat ./coverage/lcov.info | coveralls' 11 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "0.1.0", 5 | "tasks": [ 6 | { 7 | "taskName": "[yeoman test]", 8 | "command": "npm", 9 | "args": [ 10 | "test" 11 | ], 12 | "isShellCommand": true, 13 | "isBuildCommand": true, 14 | "showOutput": "never" 15 | }, 16 | { 17 | "taskName": "[yeoman check]", 18 | "command": "npm", 19 | "args": [ 20 | "run", 21 | "prepublish" 22 | ] 23 | }, 24 | { 25 | "taskName": "NCU List Updates", 26 | "command": "ncu", 27 | "args": [ 28 | ] 29 | }, 30 | { 31 | "taskName": "NCU Apply Updates", 32 | "command": "ncu", 33 | "args": [ 34 | "-u" 35 | ] 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-node": { 3 | "promptValues": { 4 | "authorName": "Luiz Carlos Faria", 5 | "authorEmail": "luizcarlosfaria@gmail.com", 6 | "authorUrl": "http://luizcarlosfaria.net/" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Luiz Carlos Faria (http://luizcarlosfaria.net/) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # generator-node-api-docker-1st-class-experience [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Coverage percentage][coveralls-image]][coveralls-url] [![Downloads][npm-downloads-week]][npm-url] [![Downloads][npm-downloads-month]][npm-url] [![Downloads][npm-downloads-year]][npm-url] [![Downloads][npm-downloads-all]][npm-url] 2 | 3 | [![Greenkeeper badge](https://badges.greenkeeper.io/luizcarlosfaria/generator-node-api-docker-1st-class-experience.svg)](https://greenkeeper.io/) 4 | > NodeJS + Typescript + TSLint + Restify + MongoDB + Docker, With VS Code Automation = VSCode TypeScript Live Debug with Containers 5 | 6 | ## Installation 7 | 8 | First, install [Yeoman](http://yeoman.io) and generator-node-api-docker-1st-class-experience using [npm](https://www.npmjs.com/) (we assume you have pre-installed [node.js](https://nodejs.org/)). 9 | 10 | ```bash 11 | npm install -g yo generator-node-api-docker-1st-class-experience 12 | ``` 13 | 14 | ## Then generate your new project: 15 | 16 | 1. Create a new folder. 17 | 18 | 2. Run ```yo node-api-docker-1st-class-experience``` 19 | 20 | 3. Open VSCode `code .` 21 | 22 | 4. Put a breakpoint at line 21 of ./src/server.ts 23 | 24 | 5. Just press F5 key (The first launch task uses docker to debug, you have other two options to debug in launch dropdown) 25 | 26 | ## The 1st class experience with NodeJS, Typescript, Docker 27 | 28 | * A NodeJS API with TypeScript, TSLint, Restify, MongoDB. 29 | * Using VSCode you will be able to: 30 | * Use VSCode to debug TypeScript based NodeJS application locally (using `Local debug` debug configuration). 31 | * Use VSCode to build and debug the TypeScript based NodeJS application behind the docker container with Docker Compose (using `Docker debug` debug configuration). 32 | * Use VSCode to build and debug with live reload of the TypeScript based NodeJS application behind the docker container with Docker Compose (using `[docker] build-and-watch` VSCode task and `Docker + watch debug` debug configuration). 33 | * With docker you will be able to: 34 | * v3 based docker-compose.yml. 35 | * The build is two-phase based, to get packages separately of application build. 36 | * Execute `docker-compose up` command to create a production ready deployment. 37 | * MongoDB container will be created side-by-side with your aplication, automatically, secured by authentication. 38 | * VSCode Integration 39 | * 3 debug options. 40 | * 5 VSCode tasks (including build task) to perform all necessary operations to manage, debug and build with docker. 41 | * TSLint with autofix enabled on VSCode and Build. 42 | * Use status-bar-tasks [Status Bar Tasks VSCode plugin][status-bar-tasks-url] to see all tasks on status bar or use `Tasks: Run Task` with pressing `Ctrl+p >` 43 | 44 | ## Notes 45 | * Local build will run in 2 seconds. 46 | * First docker build is a full build and will during 3 minutes or more (depending on your connection speed). 47 | * Every next build will run in seconds ( 48 | * Only changes in below files will demand a full build: 49 | * `package-lock.json` 50 | * `package.json` 51 | * `tsconfig.json` 52 | * `tslint.json` 53 | * `typings.json` 54 | 55 | ## License 56 | 57 | ![MIT][npm-license] © [Luiz Carlos Faria](http://gago.io/) ![made in brazil][brazil] 58 | 59 | 60 | [brazil]:http://www.goal.cc/content/images/flags/28.png 61 | [npm-image]: https://badge.fury.io/js/generator-node-api-docker-1st-class-experience.svg 62 | [npm-url]: https://npmjs.org/package/generator-node-api-docker-1st-class-experience 63 | [travis-image]: https://travis-ci.org/luizcarlosfaria/generator-node-api-docker-1st-class-experience.svg?branch=master 64 | [travis-url]: https://travis-ci.org/luizcarlosfaria/generator-node-api-docker-1st-class-experience 65 | [daviddm-image]: https://david-dm.org/luizcarlosfaria/generator-node-api-docker-1st-class-experience.svg?theme=shields.io 66 | [daviddm-url]: https://david-dm.org/luizcarlosfaria/generator-node-api-docker-1st-class-experience 67 | [coveralls-image]: https://coveralls.io/repos/luizcarlosfaria/generator-node-api-docker-1st-class-experience/badge.svg 68 | [coveralls-url]: https://coveralls.io/r/luizcarlosfaria/generator-node-api-docker-1st-class-experience 69 | [status-bar-tasks-url]:https://marketplace.visualstudio.com/items?itemName=GuardRex.status-bar-tasks 70 | [dependencies]:https://img.shields.io/david/luizcarlosfaria/generator-node-api-docker-1st-class-experience.svg 71 | 72 | 73 | 74 | [npm-downloads-all]:https://img.shields.io/npm/dt/generator-node-api-docker-1st-class-experience.svg 75 | [npm-downloads-week]:https://img.shields.io/npm/dw/generator-node-api-docker-1st-class-experience.svg 76 | [npm-downloads-month]:https://img.shields.io/npm/dm/generator-node-api-docker-1st-class-experience.svg 77 | [npm-downloads-year]:https://img.shields.io/npm/dy/generator-node-api-docker-1st-class-experience.svg 78 | [npm-license]:https://img.shields.io/npm/l/generator-node-api-docker-1st-class-experience.svg 79 | -------------------------------------------------------------------------------- /__tests__/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var assert = require('yeoman-assert'); 4 | var helpers = require('yeoman-test'); 5 | 6 | describe('generator-node-api-docker-1st-class-experience:app', () => { 7 | beforeAll(() => { 8 | return helpers.run(path.join(__dirname, '../generators/app')) 9 | .withPrompts({ 10 | projectName: 'teste_api', 11 | projectDescription: 'projectDescription', 12 | mongodbUsername: 'mongodbUsername', 13 | mongodbPassword: 'mongodbPassword', 14 | enableGit: false, 15 | openVSCode: false 16 | }); 17 | }); 18 | 19 | it('creates files', () => { 20 | assert.file([ 21 | 'docker-compose.debug.yml', 22 | 'docker-compose.yml', 23 | 'Dockerfile.all.teste_api-api-base', 24 | 'Dockerfile.debug.teste_api-api', 25 | 'Dockerfile.release.teste_api-api', 26 | 'package.json', 27 | 'tsconfig.json', 28 | 'tslint.json', 29 | 'typings.json', 30 | '.gitignore' 31 | ]); 32 | assert.fileContent('docker-compose.yml', 'mongodb_app: mongodb://mongodbUsername:mongodbPassword@mongo:27017/admin'); 33 | assert.fileContent('docker-compose.yml', 'MONGO_INITDB_ROOT_USERNAME: mongodbUsername'); 34 | assert.fileContent('docker-compose.yml', 'MONGO_INITDB_ROOT_PASSWORD: mongodbPassword'); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /check-for-publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf node_modules/ 4 | ncu -a 5 | npm install 6 | npm test 7 | npm run prepublish 8 | -------------------------------------------------------------------------------- /generators/app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const Generator = require('yeoman-generator'); 3 | const chalk = require('chalk'); 4 | const yosay = require('yosay'); 5 | const uuid = require('uuid/v4'); 6 | var replace = require('lodash.replace'); 7 | 8 | module.exports = class extends Generator { 9 | prompting() { 10 | // Have Yeoman greet the user. 11 | this.log(yosay( 12 | 'Welcome to ' + chalk.red('Node API 1st class experience with Docker and VS Code') + ' generator!' 13 | )); 14 | 15 | const prompts = [{ 16 | type: 'input', 17 | name: 'projectName', 18 | message: 'Your project name', 19 | default: this.escapeName(this.appname) // Default to current folder name 20 | }, { 21 | type: 'input', 22 | name: 'projectDescription', 23 | message: 'Project Description?' 24 | }, { 25 | type: 'input', 26 | name: 'mongodbUsername', 27 | message: 'MongoDB root username', 28 | default: 'app_mongo_user' 29 | }, { 30 | type: 'input', 31 | name: 'mongodbPassword', 32 | message: 'MongoDB root password', 33 | default: this.passwordGen() 34 | }, { 35 | type: 'confirm', 36 | name: 'enableGit', 37 | message: 'Do you want create a new GIT repo for this project?' 38 | }, { 39 | type: 'confirm', 40 | name: 'openVSCode', 41 | message: 'Do you want to open Visual Studio Code after project generation?' 42 | }]; 43 | 44 | return this.prompt(prompts).then(props => { 45 | // To access props later use this.props.someAnswer; 46 | props.projectName = this.escapeName(props.projectName); 47 | this.props = props; 48 | }); 49 | } 50 | 51 | writing() { 52 | this.fs.copyTpl( 53 | this.templatePath(''), 54 | this.destinationPath(''), 55 | this.props 56 | ); 57 | this.fs.copyTpl( 58 | this.templatePath('.vscode/'), 59 | this.destinationPath('.vscode/'), 60 | this.props 61 | ); 62 | this.fs.move(this.destinationPath('_gitignore'), this.destinationPath('.gitignore')); 63 | this.fs.move(this.destinationPath('_package.json'), this.destinationPath('package.json')); 64 | 65 | this.fs.move(this.destinationPath('Dockerfile.all.projectName-api-base'), this.destinationPath(`Dockerfile.all.${this.props.projectName}-api-base`)); 66 | this.fs.move(this.destinationPath('Dockerfile.debug.projectName-api'), this.destinationPath(`Dockerfile.debug.${this.props.projectName}-api`)); 67 | this.fs.move(this.destinationPath('Dockerfile.release.projectName-api'), this.destinationPath(`Dockerfile.release.${this.props.projectName}-api`)); 68 | } 69 | 70 | passwordGen() { 71 | const newPassword = replace(replace(replace(replace(uuid(), '-', ''), '-', ''), '-', ''), '-', ''); 72 | return newPassword; 73 | } 74 | 75 | escapeName(textToEscape) { 76 | if (textToEscape === undefined) { 77 | return textToEscape; 78 | } 79 | 80 | var escapedName = textToEscape.replace(/[^a-z0-9]/gi, '_').toLowerCase(); 81 | return escapedName; 82 | } 83 | 84 | install() { 85 | this.spawnCommandSync('npm', ['run', 'restore-global']); 86 | this.spawnCommandSync('npm', ['install', 'mongodb', 'restify', '--save']); 87 | this.spawnCommandSync('npm', ['install', '@types/mongodb', '@types/restify', '--save-dev']); 88 | this.spawnCommandSync('typings', ['install', 'body-parser', 'mongodb', '--save']); 89 | 90 | if (this.props.enableGit === true) { 91 | this.spawnCommandSync('git', ['init']); 92 | this.spawnCommandSync('git', ['add', '.']); 93 | this.spawnCommandSync('git', ['commit', '-m', 'node-api-docker-1st-class-experience baseline']); 94 | } 95 | 96 | this.spawnCommand('npm', ['run', 'build']); 97 | 98 | if (this.props.openVSCode === true) { 99 | this.spawnCommand('code', ['.']); 100 | } 101 | // This.installDependencies({bower: false}); 102 | } 103 | }; 104 | -------------------------------------------------------------------------------- /generators/app/templates/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "attach", 10 | "name": "Docker debug", 11 | "address": "127.0.0.1", 12 | "port": 9229, 13 | "protocol": "inspector", 14 | "localRoot": "${workspaceRoot}", 15 | "remoteRoot": "/app", 16 | "preLaunchTask":"[docker] build-and-start" 17 | }, 18 | { 19 | "type": "node", 20 | "request": "attach", 21 | "name": "Docker + watch debug", 22 | "address": "127.0.0.1", 23 | "port": 9229, 24 | "protocol": "inspector", 25 | "localRoot": "${workspaceRoot}", 26 | "remoteRoot": "/app" 27 | }, 28 | { 29 | "type": "node", 30 | "request": "launch", 31 | "name": "Local debug", 32 | "program": "${workspaceRoot}/dist/server.js", 33 | "cwd": "${workspaceRoot}", 34 | "protocol": "inspector", 35 | "env": { 36 | 37 | }, 38 | "preLaunchTask":"[local] build" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /generators/app/templates/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "search.exclude": { 4 | "**/node_modules": true, 5 | "**/bower_components": true, 6 | "**/dist": true 7 | }, 8 | "typescript.referencesCodeLens.enabled": true, 9 | "tslint.ignoreDefinitionFiles": false, 10 | "tslint.autoFixOnSave": true, 11 | "tslint.exclude": "**/node_modules/**/*" , 12 | "editor.tabSize": 4, 13 | "editor.insertSpaces": false 14 | } -------------------------------------------------------------------------------- /generators/app/templates/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "0.1.0", 5 | "tasks": [ 6 | { 7 | "taskName": "[local] build", 8 | "command": "npm", 9 | "args": [ 10 | "run", 11 | "build" 12 | ], 13 | "isShellCommand": true, 14 | "isBuildCommand": true, 15 | "showOutput": "never" 16 | }, 17 | { 18 | "taskName": "[docker] build-and-start", 19 | "command": "npm", 20 | "args": [ 21 | "run", 22 | "docker-run" 23 | ], 24 | "isShellCommand": true, 25 | "showOutput": "silent" 26 | }, 27 | { 28 | "taskName": "[docker] build-and-watch", 29 | "command": "npm", 30 | "args": [ 31 | "run", 32 | "docker-watch" 33 | ], 34 | "isShellCommand": true, 35 | "showOutput": "silent" 36 | }, 37 | 38 | 39 | 40 | { 41 | "taskName": "[docker] stop-and-remove", 42 | "command": "npm", 43 | "args": [ 44 | "run", 45 | "docker-stop" 46 | ], 47 | "isShellCommand": true, 48 | "showOutput": "always" 49 | }, 50 | { 51 | "taskName": "[docker] docker-cleanup", 52 | "command": "npm", 53 | "args": [ 54 | "run", 55 | "docker-cleanup" 56 | ], 57 | "isShellCommand": true, 58 | "showOutput": "always" 59 | } 60 | ] 61 | } -------------------------------------------------------------------------------- /generators/app/templates/Dockerfile.all.projectName-api-base: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | 3 | ADD ./package-lock.json /app/package-lock.json 4 | ADD ./package.json /app/package.json 5 | ADD ./tsconfig.json /app/tsconfig.json 6 | ADD ./tslint.json /app/tslint.json 7 | ADD ./typings.json /app/typings.json 8 | 9 | WORKDIR /app/ 10 | 11 | EXPOSE 3000 12 | 13 | RUN npm run restore-all -------------------------------------------------------------------------------- /generators/app/templates/Dockerfile.debug.projectName-api: -------------------------------------------------------------------------------- 1 | FROM <%- projectName %>-api-base 2 | 3 | #ADD ./dist /app/dist 4 | #ADD ./src /app/src 5 | 6 | EXPOSE 9229 7 | 8 | VOLUME /app/src 9 | VOLUME /app/dist 10 | 11 | ENTRYPOINT nodemon --legacy-watch --delay 0.4 --inspect=0.0.0.0:9229 ./dist/server.js -e js 12 | 13 | 14 | -------------------------------------------------------------------------------- /generators/app/templates/Dockerfile.release.projectName-api: -------------------------------------------------------------------------------- 1 | FROM <%- projectName %>-api-base 2 | 3 | ADD ./src /app/src 4 | 5 | RUN npm run build 6 | 7 | ENTRYPOINT nodemon ./dist/server.js 8 | 9 | 10 | -------------------------------------------------------------------------------- /generators/app/templates/_gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | typings 3 | dist 4 | -------------------------------------------------------------------------------- /generators/app/templates/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%- projectName %>", 3 | "version": "0.0.0", 4 | "description": "<%- projectDescription %>", 5 | "main": "./", 6 | "license": "ISC", 7 | "author": { 8 | "name": "your name", 9 | "email": "your email address", 10 | "url": "your website/blog" 11 | }, 12 | "scripts": { 13 | "restore-global": "npm install -g typescript tslint typings nodemon", 14 | "restore-local": "npm install && typings i", 15 | "restore-all": "npm run restore-global && npm run restore-local", 16 | "build": "npm run build-ts && npm run tslint && echo Build finished!", 17 | "build-ts": "tsc", 18 | "build-watch": "tsc -w", 19 | "tslint": "tslint -c tslint.json -p tsconfig.json", 20 | "docker-run": "npm run build && docker-compose -f docker-compose.yml -f docker-compose.debug.yml build && docker-compose -f docker-compose.yml -f docker-compose.debug.yml up -d --remove-orphans --build --force-recreate", 21 | "docker-watch": "npm run docker-run && npm run build-watch", 22 | "docker-stop": "docker-compose -f docker-compose.yml -f docker-compose.debug.yml down && echo Docker Compose Down finished!", 23 | "docker-stop-cleanup": "docker-compose -f docker-compose.yml -f docker-compose.debug.yml down -v --remove-orphans", 24 | "docker-cleanup": "npm run docker-stop-cleanup && docker rmi <%- projectName %>-api <%- projectName %>-api-livedebug <%- projectName %>-api-base || echo Cleanup finished!" 25 | }, 26 | "dependencies": { 27 | }, 28 | "devDependencies": { 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /generators/app/templates/docker-compose.debug.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | <%- projectName %>-api: 4 | build: 5 | dockerfile: ./Dockerfile.debug.<%- projectName %>-api 6 | image: <%- projectName %>-api-livedebug 7 | ports: 8 | - "9229:9229" 9 | volumes: 10 | - ./src:/app/src 11 | - ./dist:/app/dist 12 | -------------------------------------------------------------------------------- /generators/app/templates/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | <%- projectName %>-api-base: 4 | build: 5 | context: ./ 6 | dockerfile: ./Dockerfile.all.<%- projectName %>-api-base 7 | image: <%- projectName %>-api-base 8 | <%- projectName %>-api: 9 | build: 10 | context: ./ 11 | dockerfile: ./Dockerfile.release.<%- projectName %>-api 12 | image: <%- projectName %>-api 13 | depends_on: 14 | - <%- projectName %>-api-base 15 | - mongo 16 | links: 17 | - mongo:mongo 18 | networks: 19 | - <%- projectName %>-net 20 | ports: 21 | - "3000:3000" 22 | environment: 23 | mongodb_app: mongodb://<%- mongodbUsername %>:<%- mongodbPassword %>@mongo:27017/admin 24 | api_port: 3000 25 | mongo: 26 | image: mongo 27 | volumes: 28 | - db_data:/data/db 29 | restart: always 30 | command: --storageEngine wiredTiger 31 | ports: 32 | - "27017:27017" 33 | depends_on: 34 | - <%- projectName %>-api-base 35 | networks: 36 | - <%- projectName %>-net 37 | environment: 38 | MONGO_INITDB_ROOT_USERNAME: <%- mongodbUsername %> 39 | MONGO_INITDB_ROOT_PASSWORD: <%- mongodbPassword %> 40 | 41 | 42 | volumes: 43 | db_data: 44 | 45 | networks: 46 | <%- projectName %>-net: 47 | driver: bridge -------------------------------------------------------------------------------- /generators/app/templates/src/app/apicontrollers/HealthCheckApiController.ts: -------------------------------------------------------------------------------- 1 | import { Collection, Db, MongoClient } from "mongodb"; 2 | import * as restify from "restify"; 3 | import { DataProcess } from "./../data/DataProcess"; 4 | import { IApiController } from "./IApiController"; 5 | 6 | export class HealthCheckApiController implements IApiController { 7 | public register(server: restify.Server): void { 8 | 9 | server.get("/", async (req, res, next) => { 10 | // TEST DB 11 | const data = new DataProcess("db_feed"); 12 | await data.connect(); 13 | if (data.database !== undefined) { 14 | const collection: Collection = await data.database.collection("timeline"); 15 | await collection.insert({ 16 | Message: "generator-node-api-docker-1st-class-experience is a 1st class awesome experience with typescript, node, docker and vscode!", 17 | }); 18 | const result: any[] = await collection.find({}).toArray(); 19 | 20 | res.send([ 21 | { name: "api", status: "ok" }, 22 | { name: "mongodb", status: result.length > 0 ? "ok" : "no-data" }, 23 | ]); 24 | } 25 | next(); 26 | }); 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /generators/app/templates/src/app/apicontrollers/IApiController.ts: -------------------------------------------------------------------------------- 1 | import * as restify from "restify"; 2 | 3 | export interface IApiController { 4 | register(server: restify.Server): void; 5 | } 6 | -------------------------------------------------------------------------------- /generators/app/templates/src/app/data/DataProcess.ts: -------------------------------------------------------------------------------- 1 | import { Collection, Db, MongoClient, Mongos } from "mongodb"; 2 | 3 | export class DataProcess { 4 | 5 | public database?: Db; 6 | 7 | constructor(public databaseName: string) { 8 | 9 | } 10 | 11 | public async connect(): Promise { 12 | const connectionString: string = process.env.mongodb_app || ""; 13 | const mongoClient = await MongoClient.connect(connectionString); 14 | this.database = mongoClient.db(this.databaseName); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /generators/app/templates/src/infrastructure/ApiServer.ts: -------------------------------------------------------------------------------- 1 | import * as restify from "restify"; 2 | import { IApiController } from "./../app/apicontrollers/IApiController"; 3 | import { IInitializable } from "./IInitializable"; 4 | 5 | export class ApiServer implements IInitializable { 6 | 7 | public name: string = "ApiServer"; 8 | 9 | public restifyServer?: restify.Server; 10 | 11 | constructor(public apiControllers: IApiController[]) { } 12 | 13 | public Initialize(): Promise { 14 | this.restifyServer = restify.createServer(); 15 | // this.restifyServer.use(restify.acceptParser(this.restifyServer.acceptable)); 16 | // this.restifyServer.use(restify.authorizationParser()); 17 | // this.restifyServer.use(restify.dateParser()); 18 | // this.restifyServer.use(restify.queryParser()); 19 | // this.restifyServer.use(restify.jsonp()); 20 | // this.restifyServer.use(restify.gzipResponse()); 21 | // this.restifyServer.use(restify.bodyParser()); 22 | // this.restifyServer.use(restify.CORS()); 23 | /*this.restifyServer.use(restify.throttle({ 24 | burst: 1, 25 | ip: true, 26 | overrides: { 27 | "127.0.0.1": { 28 | burst: 0, 29 | rate: 0, // unlimited 30 | }, 31 | }, 32 | rate: 1, 33 | }));*/ 34 | 35 | this.apiControllers.forEach((apiController) => { 36 | if (this.restifyServer !== undefined) { 37 | apiController.register(this.restifyServer); 38 | } 39 | }); 40 | 41 | console.log("rest server starting..."); 42 | 43 | return new Promise((resolve, reject) => { 44 | if (this.restifyServer !== undefined) { 45 | this.restifyServer.listen(process.env.api_port, () => { 46 | if (this.restifyServer !== undefined) { 47 | console.log("%s is online on %s", this.restifyServer.name, this.restifyServer.url); 48 | } 49 | resolve(); 50 | }); 51 | } 52 | 53 | }); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /generators/app/templates/src/infrastructure/IInitializable.ts: -------------------------------------------------------------------------------- 1 |  2 | export interface IInitializable { 3 | name: string; 4 | Initialize(): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /generators/app/templates/src/server.ts: -------------------------------------------------------------------------------- 1 | import * as os from "os"; 2 | import { HealthCheckApiController } from "./app/apicontrollers/HealthCheckApiController"; 3 | import { ApiServer } from "./infrastructure/ApiServer"; 4 | import { IInitializable } from "./infrastructure/IInitializable"; 5 | 6 | const servers: IInitializable[] = new Array(); 7 | servers.push(new ApiServer([ 8 | new HealthCheckApiController(), 9 | ])); 10 | 11 | const initAll = async (server: IInitializable) => { 12 | console.log("%s Inicializando...", server.name); 13 | await server.Initialize(); 14 | console.log("%s inicializado!", server.name); 15 | }; 16 | 17 | servers.forEach(initAll); 18 | 19 | setInterval(() => { 20 | 21 | console.log(`Debugging a TypeScript NodeJS@${process.version} API on ${os.hostname()} (${process.platform}/${process.arch})`); 22 | 23 | }, 3000); 24 | -------------------------------------------------------------------------------- /generators/app/templates/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "ES6", 5 | /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ 6 | "module": "commonjs", 7 | /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'. */ 8 | // "lib": [], /* Specify library files to be included in the compilation: */ 9 | // "allowJs": true, /* Allow javascript files to be compiled. */ 10 | // "checkJs": true, /* Report errors in .js files. */ 11 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 12 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 13 | "sourceMap": true, 14 | /* Generates corresponding '.map' file. */ 15 | //"outFile": "./server.js", 16 | /* Concatenate and emit output to single file. */ 17 | "outDir": "./dist", 18 | /* Redirect output structure to the directory. */ 19 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 20 | "removeComments": true, 21 | /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, 29 | /* Enable all strict type-checking options. */ 30 | "noImplicitAny": true, 31 | /* Raise error on expressions and declarations with an implied 'any' type. */ 32 | "strictNullChecks": true, 33 | /* Enable strict null checks. */ 34 | "noImplicitThis": true, 35 | /* Raise error on 'this' expressions with an implied 'any' type. */ 36 | "alwaysStrict": true, 37 | /* Parse in strict mode and emit "use strict" for each source file. */ 38 | 39 | /* Additional Checks */ 40 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 41 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 42 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 43 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 44 | 45 | /* Module Resolution Options */ 46 | "moduleResolution": "node", 47 | /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 48 | "baseUrl": "./", 49 | /* Base directory to resolve non-absolute module names. */ 50 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 51 | "paths": { 52 | "*": [ 53 | "node_modules/*", 54 | "src/types/*" 55 | ] 56 | } 57 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 58 | // "typeRoots": [], /* List of folders to include type definitions from. */ 59 | //"types": [], /* Type declaration files to be included in compilation. */ 60 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 61 | 62 | /* Source Map Options */ 63 | // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 64 | // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ 65 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 66 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 67 | 68 | /* Experimental Options */ 69 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 70 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 71 | }, 72 | "include": [ 73 | "src/**/*" 74 | ] 75 | } -------------------------------------------------------------------------------- /generators/app/templates/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "class-name": true, 9 | "no-console": [true, "debug", "error"], 10 | "comment-format": [ 11 | true, 12 | "check-space" 13 | ], 14 | "indent": [ 15 | true, 16 | "spaces", 17 | 2 18 | ], 19 | "one-line": [ 20 | true, 21 | "check-open-brace", 22 | "check-whitespace" 23 | ], 24 | "no-var-keyword": true, 25 | "quotemark": [ 26 | true, 27 | "double", 28 | "avoid-escape" 29 | ], 30 | "semicolon": [ 31 | true, 32 | "always", 33 | "ignore-bound-class-methods" 34 | ], 35 | "whitespace": [ 36 | true, 37 | "check-branch", 38 | "check-decl", 39 | "check-operator", 40 | "check-module", 41 | "check-separator", 42 | "check-type" 43 | ], 44 | "typedef-whitespace": [ 45 | true, 46 | { 47 | "call-signature": "nospace", 48 | "index-signature": "nospace", 49 | "parameter": "nospace", 50 | "property-declaration": "nospace", 51 | "variable-declaration": "nospace" 52 | }, 53 | { 54 | "call-signature": "onespace", 55 | "index-signature": "onespace", 56 | "parameter": "onespace", 57 | "property-declaration": "onespace", 58 | "variable-declaration": "onespace" 59 | } 60 | ], 61 | "no-internal-module": true, 62 | "no-trailing-whitespace": true, 63 | "no-null-keyword": true, 64 | "prefer-const": true, 65 | "jsdoc-format": true, 66 | "max-line-length": [true, 200] 67 | }, 68 | "rulesDirectory": [] 69 | } -------------------------------------------------------------------------------- /generators/app/templates/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%- projectName %>", 3 | "dependencies": { 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-node-api-docker-1st-class-experience", 3 | "version": "1.0.18", 4 | "description": "NodeJS + Typescript + TSLint + Restify + MongoDB + Docker, With VS Code Automation = TypeScript Live Debug with Containers", 5 | "homepage": "https://github.com/luizcarlosfaria/generator-node-api-docker-1st-class-experience", 6 | "author": { 7 | "name": "Luiz Carlos Faria", 8 | "email": "luizcarlosfaria@gmail.com", 9 | "url": "https://gago.io/blog/projetos/yeoman-generator-node-api-docker-1st-class-experience/" 10 | }, 11 | "files": [ 12 | "generators" 13 | ], 14 | "main": "generators/index.js", 15 | "keywords": [ 16 | "docker", 17 | "nodejs", 18 | "node", 19 | "mongo", 20 | "mongodb", 21 | "restify", 22 | "vscode-debugging", 23 | "node-vscode-container-debugging", 24 | "yeoman-generator" 25 | ], 26 | "devDependencies": { 27 | "coveralls": "^3.0.4", 28 | "eslint": "^6.0.0", 29 | "eslint-config-xo-space": "^0.21.0", 30 | "jest": "^24.8.0", 31 | "jest-cli": "^24.8.0", 32 | "yeoman-assert": "^3.1.1", 33 | "yeoman-test": "^2.0.0" 34 | }, 35 | "dependencies": { 36 | "chalk": "^2.4.2", 37 | "hoek": "^6.1.3", 38 | "lodash.replace": "^4.1.4", 39 | "underscore.string": "^3.3.5", 40 | "uuid": "^3.3.2", 41 | "yeoman-generator": "^4.0.1", 42 | "yo": "^2.0.6", 43 | "yosay": "^2.0.2" 44 | }, 45 | "jest": { 46 | "testEnvironment": "node" 47 | }, 48 | "scripts": { 49 | "prepublish": "npm audit --audit-level high", 50 | "pretest": "eslint . --fix", 51 | "test": "jest" 52 | }, 53 | "eslintConfig": { 54 | "extends": "xo-space", 55 | "env": { 56 | "jest": true, 57 | "node": true 58 | } 59 | }, 60 | "repository": "luizcarlosfaria/generator-node-api-docker-1st-class-experience", 61 | "license": "MIT" 62 | } 63 | --------------------------------------------------------------------------------