├── .dockerignore ├── .gitignore ├── Dockerfile ├── docker-compose.yml ├── package.json ├── run.sh ├── README.md └── index.js /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | lib/ 3 | package-lock.json -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10-alpine 2 | 3 | RUN mkdir -p /src 4 | 5 | COPY package.json src/package.json 6 | 7 | WORKDIR /src 8 | 9 | RUN npm install --only=production --silent 10 | 11 | COPY . /src 12 | 13 | CMD npm start -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | api-heroes-postgres: 4 | container_name: api-heroes-postgres 5 | build: . 6 | ports: 7 | - 3000:3000 8 | environment: 9 | POSTGRES_HOST: postgres:mysecretpassword@postgres:5432 10 | PORT: 3000 11 | 12 | depends_on: 13 | - postgres 14 | links: 15 | - postgres 16 | 17 | postgres: 18 | container_name: postgres 19 | restart: always 20 | image: postgres 21 | ports: 22 | - 5432:5432 23 | environment: 24 | POSTGRES_PASSWORD: mysecretpassword 25 | POSTGRES_DB: heroes -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docker-registry", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "npx pm2-docker index.js", 8 | "testAll": "sh run.sh" 9 | }, 10 | "keywords": [], 11 | "author": "erickwendel", 12 | "license": "ISC", 13 | "dependencies": { 14 | "hapi": "18.1.0", 15 | "hapi-swagger": "9.4.2", 16 | "inert": "5.1.3", 17 | "joi": "14.3.1", 18 | "pg": "7.10.0", 19 | "pg-hstore": "2.3.2", 20 | "pm2": "3.5.0", 21 | "sequelize": "5.6.1", 22 | "vision": "5.4.4" 23 | }, 24 | "devDependencies": {} 25 | } 26 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | HOST=localhost:3000 2 | 3 | echo '\n\n creating Chapolin' 4 | CREATE=$( 5 | curl --silent -X POST \ 6 | --header "Content-Type: application/json" \ 7 | --data-binary '{"name":"Chapolin","power":"Strength"}' \ 8 | $HOST/heroes 9 | ) 10 | 11 | echo $CREATE | jq 12 | 13 | ID=$(echo $CREATE | jq .id) 14 | 15 | echo "\n\n requesting chapolin $ID" 16 | curl --silent $HOST/heroes/$ID | jq 17 | 18 | echo '\n\n requesting all heroes' 19 | curl --silent $HOST/heroes | jq 20 | 21 | echo "\n\n updating chapolin $ID" 22 | curl --silent -X PUT \ 23 | --header "Content-Type: application/json" \ 24 | --data-binary '{"name":"Batman","power":"Rich"}' \ 25 | $HOST/heroes/$ID \ 26 | | jq 27 | 28 | echo "\n\n requesting id: $ID" 29 | curl --silent $HOST/heroes/$ID | jq 30 | 31 | echo "\n\n removing id: $ID" 32 | curl --silent -X DELETE \ 33 | --header "Content-Type: application/json" \ 34 | $HOST/heroes/$ID \ 35 | | jq 36 | 37 | echo '\n\n requesting all heroes' 38 | curl --silent $HOST/heroes | jq 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Node.js with Postgres Example 2 | 3 | Swagger Page of that application 7 | 8 | ### Requirements 9 | 10 | * Node.js v8+ or Docker and Docker Compose 11 | * Postgres running on local instance or Docker 12 | 13 | ### Running on localMachine 14 | 15 | * Install dependencies - `npm i` 16 | * Run project - `npm start` 17 | 18 | ### OR: Docker 19 | 20 | * `docker-compose up` 21 | 22 | ### OR: Alternatives on pulling from Docker hub 23 | 24 | * Docker hub image: [erickwendel/nodejs-with-postgres-api-example](https://hub.docker.com/r/erickwendel/nodejs-with-postgres-api-example/) 25 | 26 | ```shell 27 | docker run -d -p 5432:5432 --name postgres \ 28 | --env POSTGRES_PASSWORD=mysecretpassword \ 29 | --env POSTGRES_DB=heroes\ 30 | postgres 31 | ``` 32 | 33 | ```shell 34 | docker run -p 3000:3000 \ 35 | --link postgres:postgres \ 36 | -e POSTGRES_HOST=postgres:mysecretpassword@postgres:5432 \ 37 | -e POSTGRES_DB=heroes \ 38 | -e POSTGRES_SSL=false \ 39 | erickwendel/nodejs-with-postgres-api-example:latest 40 | ``` 41 | 42 | ### Viewing 43 | 44 | * Go to swagger page - `localhost:3000/documentation` 45 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const Joi = require('joi') 2 | const Sequelize = require('sequelize') 3 | const Hapi = require('hapi'); 4 | const Inert = require("inert"); 5 | const Vision = require("vision"); 6 | const HapiSwagger = require("hapi-swagger"); 7 | const port = process.env.PORT || 3000; 8 | const server = new Hapi.Server( 9 | { 10 | port 11 | } 12 | ); 13 | 14 | const failAction = async (request, h, err) => { 15 | console.error('err', err) 16 | throw err; 17 | } 18 | 19 | (async () => { 20 | if (!process.env.POSTGRES_HOST) { 21 | throw Error( 22 | "process.env.POSTGRES_HOST must be a: user:pass@ipService:port ", 23 | ); 24 | } 25 | const sequelize = new Sequelize( 26 | `postgres://${process.env.POSTGRES_HOST}/${process.env.POSTGRES_DB || "heroes"}`, 27 | { 28 | ssl: process.env.POSTGRES_SSL, 29 | dialectOptions: { 30 | ssl: process.env.POSTGRES_SSL, 31 | }, 32 | } 33 | ); 34 | await sequelize.authenticate(); 35 | console.log("postgres is running"); 36 | 37 | const Hero = sequelize.define("hero", { 38 | name: Sequelize.STRING, 39 | power: Sequelize.STRING, 40 | }); 41 | 42 | await Hero.sync({ force: true }); 43 | 44 | await server.register([ 45 | Inert, 46 | Vision, 47 | { 48 | plugin: HapiSwagger, 49 | options: { 50 | info: { 51 | title: "Node.js with Postgres Example - Erick Wendel", 52 | version: "1.0", 53 | }, 54 | } 55 | }, 56 | ]); 57 | 58 | server.route([ 59 | { 60 | method: "GET", 61 | path: "/heroes", 62 | handler: () => { 63 | return Hero.findAll(); 64 | }, 65 | config: { 66 | description: "List All heroes", 67 | notes: "heroes from database", 68 | tags: ["api"], 69 | }, 70 | }, 71 | { 72 | method: "GET", 73 | path: "/heroes/{id}", 74 | handler: (req) => { 75 | return Hero.findAll({ where: { id: req.params.id } }); 76 | }, 77 | config: { 78 | description: "Get a hero", 79 | notes: "heroes from database", 80 | tags: ["api"], 81 | }, 82 | }, 83 | { 84 | method: "POST", 85 | path: "/heroes", 86 | config: { 87 | handler: (req) => { 88 | const { payload } = req; 89 | return Hero.create(payload); 90 | }, 91 | description: "Create a hero", 92 | notes: "create a hero", 93 | tags: ["api"], 94 | validate: { 95 | failAction, 96 | 97 | payload: { 98 | name: Joi.string().required(), 99 | power: Joi.string().required(), 100 | }, 101 | }, 102 | }, 103 | }, 104 | { 105 | method: "PUT", 106 | path: "/heroes/{id}", 107 | config: { 108 | handler: (req) => { 109 | const { payload } = req; 110 | return Hero.update(payload, { where: { id: req.params.id } }); 111 | }, 112 | description: "Create a hero", 113 | notes: "create a hero", 114 | tags: ["api"], 115 | validate: { 116 | failAction, 117 | params: { 118 | id: Joi.string().required(), 119 | }, 120 | payload: { 121 | name: Joi.string(), 122 | power: Joi.string(), 123 | }, 124 | }, 125 | }, 126 | }, 127 | 128 | { 129 | method: "DELETE", 130 | path: "/heroes/{id}", 131 | config: { 132 | handler: (req) => { 133 | return Hero.destroy({ where: { id: req.params.id } }); 134 | }, 135 | description: "Delete a hero", 136 | notes: "Delete a hero", 137 | tags: ["api"], 138 | validate: { 139 | failAction, 140 | params: { 141 | id: Joi.string().required(), 142 | }, 143 | }, 144 | }, 145 | }, 146 | ]); 147 | 148 | await server.start(); 149 | console.log("server running at", server.info.port); 150 | })(); 151 | --------------------------------------------------------------------------------