├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── api-gateway └── index.js ├── delivery-service └── index.js ├── development.Dockerfile ├── docker-compose.prod.yml ├── docker-compose.yml ├── food.json ├── order-service └── index.js ├── package-lock.json ├── package.json ├── restaurants-service └── index.js └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | .history 61 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | 3 | WORKDIR /src 4 | ADD package.json package-lock.json ./ 5 | RUN npm install 6 | 7 | ADD . . 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Armagan Amcalar 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Accessible Mcroservices with Node.js and Docker 2 | 3 | An example microservices implementation with Node.js and Docker 4 | 5 | ## Requirements 6 | Make sure you have the latest Docker and docker-compose installed. You may also want to have PM2 installed globally via `npm i -g pm2`. 7 | 8 | ## Setup 9 | Clone the repository: 10 | ``` 11 | git clone git@github.com:dashersw/microservices-workshop.git 12 | ``` 13 | 14 | ## Quickstart 15 | ### Start the application 16 | ``` 17 | cd microservices-workshop 18 | docker-compose up 19 | ``` 20 | 21 | This runs the app in development mode and any changes to the microservices will live-reload. 22 | 23 | ### Test example request 24 | ``` 25 | node test.js 26 | ``` 27 | 28 | ## Starting with PM2 29 | Another approach for development is to use PM2 as a process monitor. You can start the app with; 30 | ``` 31 | pm2 start food 32 | ``` 33 | 34 | ## Production builds 35 | Run the following for a production setup. The main difference with the test version is live-reloading — The production version doesn't live-reload any changes and will require you to re-build your images. 36 | 37 | ``` 38 | docker-compose -f docker-compose.prod.yml up 39 | ``` 40 | -------------------------------------------------------------------------------- /api-gateway/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const bodyParser = require('body-parser') 3 | const cote = require('cote') 4 | const axios = require('axios') 5 | 6 | const app = express() 7 | 8 | app.use(bodyParser.json()) 9 | 10 | const restaurantsRequester = new cote.Requester({ name: 'restaurants requester', key: 'restaurants' }) 11 | 12 | const orderRequester = new cote.Requester({ name: 'order requester', key: 'orders' }) 13 | 14 | const deliveryRequester = new cote.Requester({ name: 'delivery requester', key: 'deliveries' }) 15 | 16 | app.get('/restaurants', async (req, res) => { 17 | const restaurants = await restaurantsRequester.send({ type: 'list' }) 18 | res.send(restaurants); 19 | }) 20 | 21 | app.post('/order', async (req, res) => { 22 | const order = await orderRequester.send({ type: 'create order', order: req.body }) 23 | const delivery = await deliveryRequester.send({ type: 'create delivery', order }) 24 | 25 | res.send({ order, delivery }) 26 | }) 27 | 28 | app.listen(3000, () => console.log('listening')) 29 | -------------------------------------------------------------------------------- /delivery-service/index.js: -------------------------------------------------------------------------------- 1 | const cote = require('cote') 2 | 3 | const deliveryResponder = new cote.Responder({ name: 'delivery responder', key: 'deliveries' }) 4 | deliveryResponder.on('*', req => req.type && console.log(req)) 5 | 6 | const deliveries = [] 7 | let idCounter = 0 8 | 9 | deliveryResponder.on('create delivery', req => { 10 | const delivery = { id: idCounter++, orderId: req.order.id, eta: 30, status: 'pending' } 11 | 12 | deliveries.push(delivery) 13 | return Promise.resolve(delivery) 14 | }) 15 | -------------------------------------------------------------------------------- /development.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | 3 | WORKDIR /app 4 | VOLUME /src 5 | 6 | RUN npm install -g nodemon 7 | 8 | ADD package.json package-lock.json ./ 9 | RUN npm install 10 | 11 | CMD ["nodemon", "src"] 12 | -------------------------------------------------------------------------------- /docker-compose.prod.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | lb: 4 | image: dockercloud/haproxy 5 | links: 6 | - api-gateway 7 | volumes: 8 | - /var/run/docker.sock:/var/run/docker.sock 9 | ports: 10 | - 80:80 11 | - 443:443 12 | restart: on-failure 13 | 14 | api-gateway: 15 | build: . 16 | image: microservices-workshop/api-gateway:production 17 | restart: on-failure 18 | environment: 19 | - VIRTUAL_HOST=api-gateway.app.com 20 | ports: 21 | - 3000:3000 22 | command: node api-gateway 23 | 24 | delivery-service: 25 | build: . 26 | image: microservices-workshop/delivery-service:production 27 | restart: on-failure 28 | command: node delivery-service 29 | 30 | order-service: 31 | build: . 32 | image: microservices-workshop/order-service:production 33 | restart: on-failure 34 | command: node order-service 35 | 36 | restaurants-service: 37 | build: . 38 | image: microservices-workshop/restaurants-service:production 39 | restart: on-failure 40 | command: node restaurants-service 41 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | lb: 4 | image: dockercloud/haproxy 5 | links: 6 | - api-gateway 7 | volumes: 8 | - /var/run/docker.sock:/var/run/docker.sock 9 | ports: 10 | - 80:80 11 | - 443:443 12 | restart: on-failure 13 | 14 | api-gateway: 15 | build: 16 | context: . 17 | dockerfile: development.Dockerfile 18 | image: microservices-workshop/api-gateway:dev 19 | restart: on-failure 20 | environment: 21 | - VIRTUAL_HOST=api-gateway.app.com 22 | ports: 23 | - 3000:3000 24 | volumes: 25 | - ./api-gateway:/app/src 26 | 27 | delivery-service: 28 | build: 29 | context: . 30 | dockerfile: development.Dockerfile 31 | image: microservices-workshop/delivery-service:dev 32 | restart: on-failure 33 | volumes: 34 | - ./delivery-service:/app/src 35 | 36 | order-service: 37 | build: 38 | context: . 39 | dockerfile: development.Dockerfile 40 | image: microservices-workshop/order-service:dev 41 | restart: on-failure 42 | volumes: 43 | - ./order-service:/app/src 44 | 45 | restaurants-service: 46 | build: 47 | context: . 48 | dockerfile: development.Dockerfile 49 | image: microservices-workshop/restaurants-service:dev 50 | restart: on-failure 51 | volumes: 52 | - ./restaurants-service:/app/src 53 | -------------------------------------------------------------------------------- /food.json: -------------------------------------------------------------------------------- 1 | { 2 | "apps": [ 3 | { 4 | "name" : "api-gateway", 5 | "script" : "api-gateway/index.js", 6 | "watch" : "api-gateway/index.js" 7 | }, 8 | { 9 | "name" : "restaurants-service", 10 | "script" : "restaurants-service/index.js", 11 | "watch" : "restaurants-service/index.js" 12 | }, 13 | { 14 | "name" : "order-service", 15 | "script" : "order-service/index.js", 16 | "watch" : "order-service/index.js" 17 | }, 18 | { 19 | "name" : "delivery-service", 20 | "script" : "delivery-service/index.js", 21 | "watch" : "delivery-service/index.js" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /order-service/index.js: -------------------------------------------------------------------------------- 1 | const cote = require('cote') 2 | 3 | const orderResponder = new cote.Responder({ name: 'order responder', key: 'orders' }) 4 | orderResponder.on('*', req => req.type && console.log(req)) 5 | 6 | const orders = [] 7 | let idCounter = 0 8 | 9 | orderResponder.on('create order', req => { 10 | const order = { id: idCounter++, ...req.order, status: 'preparing' } 11 | 12 | orders.push(order) 13 | return Promise.resolve(order) 14 | }) 15 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "microservices-workshop", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@dashersw/axon": { 8 | "version": "2.0.5", 9 | "resolved": "https://registry.npmjs.org/@dashersw/axon/-/axon-2.0.5.tgz", 10 | "integrity": "sha512-e7az6UOh/1JqLvzg2GPhP3n47QMQal3Qg2a2497JwY7dlbSKUg4dQmnRyKWNjFz0FHjranUjKvX6J6NAV3Sm/Q==", 11 | "requires": { 12 | "amp": "0.3.1", 13 | "amp-message": "0.1.2", 14 | "configurable": "0.0.1", 15 | "debug": "2.6.9", 16 | "escape-regexp": "0.0.1" 17 | } 18 | }, 19 | "@dashersw/node-discover": { 20 | "version": "0.8.2", 21 | "resolved": "https://registry.npmjs.org/@dashersw/node-discover/-/node-discover-0.8.2.tgz", 22 | "integrity": "sha512-oU8qAQX7SVfx9gkgsJP9lHlifh2wDtMtEfHnVvTGmyWgakSR5OviAp6ibBXdB/zk2/Z3LaBuEkS+mcov2u4zKw==", 23 | "requires": { 24 | "node-uuid": "1.4.8", 25 | "redis": "2.8.0" 26 | }, 27 | "dependencies": { 28 | "node-uuid": { 29 | "version": "1.4.8", 30 | "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", 31 | "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" 32 | } 33 | } 34 | }, 35 | "accepts": { 36 | "version": "1.3.5", 37 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", 38 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", 39 | "requires": { 40 | "mime-types": "2.1.18", 41 | "negotiator": "0.6.1" 42 | } 43 | }, 44 | "after": { 45 | "version": "0.8.2", 46 | "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", 47 | "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" 48 | }, 49 | "amp": { 50 | "version": "0.3.1", 51 | "resolved": "https://registry.npmjs.org/amp/-/amp-0.3.1.tgz", 52 | "integrity": "sha1-at+NWKdPNh6CwfqNOJwHnhOfxH0=" 53 | }, 54 | "amp-message": { 55 | "version": "0.1.2", 56 | "resolved": "https://registry.npmjs.org/amp-message/-/amp-message-0.1.2.tgz", 57 | "integrity": "sha1-p48cmJlQh602GSpBKY5NtJ49/EU=", 58 | "requires": { 59 | "amp": "0.3.1" 60 | } 61 | }, 62 | "array-flatten": { 63 | "version": "1.1.1", 64 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 65 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 66 | }, 67 | "arraybuffer.slice": { 68 | "version": "0.0.7", 69 | "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", 70 | "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" 71 | }, 72 | "async": { 73 | "version": "1.5.2", 74 | "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", 75 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" 76 | }, 77 | "async-limiter": { 78 | "version": "1.0.0", 79 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", 80 | "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" 81 | }, 82 | "axios": { 83 | "version": "0.18.0", 84 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", 85 | "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", 86 | "dev": true, 87 | "requires": { 88 | "follow-redirects": "1.5.0", 89 | "is-buffer": "1.1.6" 90 | } 91 | }, 92 | "backo2": { 93 | "version": "1.0.2", 94 | "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", 95 | "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" 96 | }, 97 | "base64-arraybuffer": { 98 | "version": "0.1.5", 99 | "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", 100 | "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" 101 | }, 102 | "base64id": { 103 | "version": "1.0.0", 104 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", 105 | "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" 106 | }, 107 | "better-assert": { 108 | "version": "1.0.2", 109 | "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", 110 | "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", 111 | "requires": { 112 | "callsite": "1.0.0" 113 | } 114 | }, 115 | "blob": { 116 | "version": "0.0.4", 117 | "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", 118 | "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" 119 | }, 120 | "body-parser": { 121 | "version": "1.18.3", 122 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", 123 | "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", 124 | "requires": { 125 | "bytes": "3.0.0", 126 | "content-type": "1.0.4", 127 | "debug": "2.6.9", 128 | "depd": "1.1.2", 129 | "http-errors": "1.6.3", 130 | "iconv-lite": "0.4.23", 131 | "on-finished": "2.3.0", 132 | "qs": "6.5.2", 133 | "raw-body": "2.3.3", 134 | "type-is": "1.6.16" 135 | } 136 | }, 137 | "bytes": { 138 | "version": "3.0.0", 139 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 140 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 141 | }, 142 | "callsite": { 143 | "version": "1.0.0", 144 | "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", 145 | "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" 146 | }, 147 | "charm": { 148 | "version": "1.0.2", 149 | "resolved": "https://registry.npmjs.org/charm/-/charm-1.0.2.tgz", 150 | "integrity": "sha1-it02cVOm2aWBMxBSxAkJkdqZXjU=", 151 | "requires": { 152 | "inherits": "2.0.3" 153 | } 154 | }, 155 | "colors": { 156 | "version": "1.1.2", 157 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", 158 | "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=" 159 | }, 160 | "component-bind": { 161 | "version": "1.0.0", 162 | "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", 163 | "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" 164 | }, 165 | "component-emitter": { 166 | "version": "1.2.1", 167 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 168 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" 169 | }, 170 | "component-inherit": { 171 | "version": "0.0.3", 172 | "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", 173 | "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" 174 | }, 175 | "configurable": { 176 | "version": "0.0.1", 177 | "resolved": "https://registry.npmjs.org/configurable/-/configurable-0.0.1.tgz", 178 | "integrity": "sha1-R9dbcntRtOuEwdra/j+CQDE4M7E=" 179 | }, 180 | "content-disposition": { 181 | "version": "0.5.2", 182 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 183 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 184 | }, 185 | "content-type": { 186 | "version": "1.0.4", 187 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 188 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 189 | }, 190 | "cookie": { 191 | "version": "0.3.1", 192 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 193 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 194 | }, 195 | "cookie-signature": { 196 | "version": "1.0.6", 197 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 198 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 199 | }, 200 | "cote": { 201 | "version": "0.16.2", 202 | "resolved": "https://registry.npmjs.org/cote/-/cote-0.16.2.tgz", 203 | "integrity": "sha512-AGMTHbQr+VwGTa4cJn+p0F10bExwTyQXTP0SwvbbECsLh46xSagPMOW8CDDIe+yAkYNNcghUqy4iogcu7dAyLw==", 204 | "requires": { 205 | "@dashersw/axon": "2.0.5", 206 | "@dashersw/node-discover": "0.8.2", 207 | "charm": "1.0.2", 208 | "colors": "1.1.2", 209 | "eventemitter2": "4.1.2", 210 | "lodash": "4.17.5", 211 | "portfinder": "1.0.13", 212 | "socket.io": "2.0.4", 213 | "uuid": "3.2.1" 214 | } 215 | }, 216 | "debug": { 217 | "version": "2.6.9", 218 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 219 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 220 | "requires": { 221 | "ms": "2.0.0" 222 | } 223 | }, 224 | "depd": { 225 | "version": "1.1.2", 226 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 227 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 228 | }, 229 | "destroy": { 230 | "version": "1.0.4", 231 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 232 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 233 | }, 234 | "double-ended-queue": { 235 | "version": "2.1.0-0", 236 | "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", 237 | "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=" 238 | }, 239 | "ee-first": { 240 | "version": "1.1.1", 241 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 242 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 243 | }, 244 | "encodeurl": { 245 | "version": "1.0.2", 246 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 247 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 248 | }, 249 | "engine.io": { 250 | "version": "3.1.5", 251 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.5.tgz", 252 | "integrity": "sha512-D06ivJkYxyRrcEe0bTpNnBQNgP9d3xog+qZlLbui8EsMr/DouQpf5o9FzJnWYHEYE0YsFHllUv2R1dkgYZXHcA==", 253 | "requires": { 254 | "accepts": "1.3.5", 255 | "base64id": "1.0.0", 256 | "cookie": "0.3.1", 257 | "debug": "3.1.0", 258 | "engine.io-parser": "2.1.2", 259 | "uws": "9.14.0", 260 | "ws": "3.3.3" 261 | }, 262 | "dependencies": { 263 | "debug": { 264 | "version": "3.1.0", 265 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 266 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 267 | "requires": { 268 | "ms": "2.0.0" 269 | } 270 | } 271 | } 272 | }, 273 | "engine.io-client": { 274 | "version": "3.1.6", 275 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.6.tgz", 276 | "integrity": "sha512-hnuHsFluXnsKOndS4Hv6SvUrgdYx1pk2NqfaDMW+GWdgfU3+/V25Cj7I8a0x92idSpa5PIhJRKxPvp9mnoLsfg==", 277 | "requires": { 278 | "component-emitter": "1.2.1", 279 | "component-inherit": "0.0.3", 280 | "debug": "3.1.0", 281 | "engine.io-parser": "2.1.2", 282 | "has-cors": "1.1.0", 283 | "indexof": "0.0.1", 284 | "parseqs": "0.0.5", 285 | "parseuri": "0.0.5", 286 | "ws": "3.3.3", 287 | "xmlhttprequest-ssl": "1.5.5", 288 | "yeast": "0.1.2" 289 | }, 290 | "dependencies": { 291 | "debug": { 292 | "version": "3.1.0", 293 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 294 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 295 | "requires": { 296 | "ms": "2.0.0" 297 | } 298 | } 299 | } 300 | }, 301 | "engine.io-parser": { 302 | "version": "2.1.2", 303 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", 304 | "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", 305 | "requires": { 306 | "after": "0.8.2", 307 | "arraybuffer.slice": "0.0.7", 308 | "base64-arraybuffer": "0.1.5", 309 | "blob": "0.0.4", 310 | "has-binary2": "1.0.3" 311 | } 312 | }, 313 | "escape-html": { 314 | "version": "1.0.3", 315 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 316 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 317 | }, 318 | "escape-regexp": { 319 | "version": "0.0.1", 320 | "resolved": "https://registry.npmjs.org/escape-regexp/-/escape-regexp-0.0.1.tgz", 321 | "integrity": "sha1-9EvaEtRbvfnLf4Yu5+SCez3TIlQ=" 322 | }, 323 | "etag": { 324 | "version": "1.8.1", 325 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 326 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 327 | }, 328 | "eventemitter2": { 329 | "version": "4.1.2", 330 | "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-4.1.2.tgz", 331 | "integrity": "sha1-DhqEd6+CGm7zmVsxG/dMI6UkfxU=" 332 | }, 333 | "express": { 334 | "version": "4.16.3", 335 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", 336 | "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", 337 | "requires": { 338 | "accepts": "1.3.5", 339 | "array-flatten": "1.1.1", 340 | "body-parser": "1.18.2", 341 | "content-disposition": "0.5.2", 342 | "content-type": "1.0.4", 343 | "cookie": "0.3.1", 344 | "cookie-signature": "1.0.6", 345 | "debug": "2.6.9", 346 | "depd": "1.1.2", 347 | "encodeurl": "1.0.2", 348 | "escape-html": "1.0.3", 349 | "etag": "1.8.1", 350 | "finalhandler": "1.1.1", 351 | "fresh": "0.5.2", 352 | "merge-descriptors": "1.0.1", 353 | "methods": "1.1.2", 354 | "on-finished": "2.3.0", 355 | "parseurl": "1.3.2", 356 | "path-to-regexp": "0.1.7", 357 | "proxy-addr": "2.0.3", 358 | "qs": "6.5.1", 359 | "range-parser": "1.2.0", 360 | "safe-buffer": "5.1.1", 361 | "send": "0.16.2", 362 | "serve-static": "1.13.2", 363 | "setprototypeof": "1.1.0", 364 | "statuses": "1.4.0", 365 | "type-is": "1.6.16", 366 | "utils-merge": "1.0.1", 367 | "vary": "1.1.2" 368 | }, 369 | "dependencies": { 370 | "body-parser": { 371 | "version": "1.18.2", 372 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", 373 | "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", 374 | "requires": { 375 | "bytes": "3.0.0", 376 | "content-type": "1.0.4", 377 | "debug": "2.6.9", 378 | "depd": "1.1.2", 379 | "http-errors": "1.6.3", 380 | "iconv-lite": "0.4.19", 381 | "on-finished": "2.3.0", 382 | "qs": "6.5.1", 383 | "raw-body": "2.3.2", 384 | "type-is": "1.6.16" 385 | } 386 | }, 387 | "iconv-lite": { 388 | "version": "0.4.19", 389 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 390 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" 391 | }, 392 | "qs": { 393 | "version": "6.5.1", 394 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 395 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" 396 | }, 397 | "raw-body": { 398 | "version": "2.3.2", 399 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", 400 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", 401 | "requires": { 402 | "bytes": "3.0.0", 403 | "http-errors": "1.6.2", 404 | "iconv-lite": "0.4.19", 405 | "unpipe": "1.0.0" 406 | }, 407 | "dependencies": { 408 | "depd": { 409 | "version": "1.1.1", 410 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 411 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" 412 | }, 413 | "http-errors": { 414 | "version": "1.6.2", 415 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 416 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", 417 | "requires": { 418 | "depd": "1.1.1", 419 | "inherits": "2.0.3", 420 | "setprototypeof": "1.0.3", 421 | "statuses": "1.4.0" 422 | } 423 | }, 424 | "setprototypeof": { 425 | "version": "1.0.3", 426 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", 427 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" 428 | } 429 | } 430 | }, 431 | "safe-buffer": { 432 | "version": "5.1.1", 433 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 434 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 435 | }, 436 | "statuses": { 437 | "version": "1.4.0", 438 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 439 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 440 | } 441 | } 442 | }, 443 | "finalhandler": { 444 | "version": "1.1.1", 445 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", 446 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", 447 | "requires": { 448 | "debug": "2.6.9", 449 | "encodeurl": "1.0.2", 450 | "escape-html": "1.0.3", 451 | "on-finished": "2.3.0", 452 | "parseurl": "1.3.2", 453 | "statuses": "1.4.0", 454 | "unpipe": "1.0.0" 455 | }, 456 | "dependencies": { 457 | "statuses": { 458 | "version": "1.4.0", 459 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 460 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 461 | } 462 | } 463 | }, 464 | "follow-redirects": { 465 | "version": "1.5.0", 466 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.0.tgz", 467 | "integrity": "sha512-fdrt472/9qQ6Kgjvb935ig6vJCuofpBUD14f9Vb+SLlm7xIe4Qva5gey8EKtv8lp7ahE1wilg3xL1znpVGtZIA==", 468 | "dev": true, 469 | "requires": { 470 | "debug": "3.1.0" 471 | }, 472 | "dependencies": { 473 | "debug": { 474 | "version": "3.1.0", 475 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 476 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 477 | "dev": true, 478 | "requires": { 479 | "ms": "2.0.0" 480 | } 481 | } 482 | } 483 | }, 484 | "forwarded": { 485 | "version": "0.1.2", 486 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 487 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 488 | }, 489 | "fresh": { 490 | "version": "0.5.2", 491 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 492 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 493 | }, 494 | "has-binary2": { 495 | "version": "1.0.3", 496 | "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", 497 | "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", 498 | "requires": { 499 | "isarray": "2.0.1" 500 | } 501 | }, 502 | "has-cors": { 503 | "version": "1.1.0", 504 | "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", 505 | "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" 506 | }, 507 | "http-errors": { 508 | "version": "1.6.3", 509 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 510 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 511 | "requires": { 512 | "depd": "1.1.2", 513 | "inherits": "2.0.3", 514 | "setprototypeof": "1.1.0", 515 | "statuses": "1.5.0" 516 | } 517 | }, 518 | "iconv-lite": { 519 | "version": "0.4.23", 520 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", 521 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", 522 | "requires": { 523 | "safer-buffer": "2.1.2" 524 | } 525 | }, 526 | "indexof": { 527 | "version": "0.0.1", 528 | "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", 529 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" 530 | }, 531 | "inherits": { 532 | "version": "2.0.3", 533 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 534 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 535 | }, 536 | "ipaddr.js": { 537 | "version": "1.6.0", 538 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", 539 | "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=" 540 | }, 541 | "is-buffer": { 542 | "version": "1.1.6", 543 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 544 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", 545 | "dev": true 546 | }, 547 | "isarray": { 548 | "version": "2.0.1", 549 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", 550 | "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" 551 | }, 552 | "lodash": { 553 | "version": "4.17.5", 554 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", 555 | "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" 556 | }, 557 | "media-typer": { 558 | "version": "0.3.0", 559 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 560 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 561 | }, 562 | "merge-descriptors": { 563 | "version": "1.0.1", 564 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 565 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 566 | }, 567 | "methods": { 568 | "version": "1.1.2", 569 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 570 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 571 | }, 572 | "mime": { 573 | "version": "1.4.1", 574 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 575 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 576 | }, 577 | "mime-db": { 578 | "version": "1.33.0", 579 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", 580 | "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" 581 | }, 582 | "mime-types": { 583 | "version": "2.1.18", 584 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", 585 | "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", 586 | "requires": { 587 | "mime-db": "1.33.0" 588 | } 589 | }, 590 | "minimist": { 591 | "version": "0.0.8", 592 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 593 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" 594 | }, 595 | "mkdirp": { 596 | "version": "0.5.1", 597 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 598 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 599 | "requires": { 600 | "minimist": "0.0.8" 601 | } 602 | }, 603 | "ms": { 604 | "version": "2.0.0", 605 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 606 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 607 | }, 608 | "negotiator": { 609 | "version": "0.6.1", 610 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 611 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 612 | }, 613 | "object-component": { 614 | "version": "0.0.3", 615 | "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", 616 | "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" 617 | }, 618 | "on-finished": { 619 | "version": "2.3.0", 620 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 621 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 622 | "requires": { 623 | "ee-first": "1.1.1" 624 | } 625 | }, 626 | "parseqs": { 627 | "version": "0.0.5", 628 | "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", 629 | "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", 630 | "requires": { 631 | "better-assert": "1.0.2" 632 | } 633 | }, 634 | "parseuri": { 635 | "version": "0.0.5", 636 | "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", 637 | "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", 638 | "requires": { 639 | "better-assert": "1.0.2" 640 | } 641 | }, 642 | "parseurl": { 643 | "version": "1.3.2", 644 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 645 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 646 | }, 647 | "path-to-regexp": { 648 | "version": "0.1.7", 649 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 650 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 651 | }, 652 | "portfinder": { 653 | "version": "1.0.13", 654 | "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz", 655 | "integrity": "sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=", 656 | "requires": { 657 | "async": "1.5.2", 658 | "debug": "2.6.9", 659 | "mkdirp": "0.5.1" 660 | } 661 | }, 662 | "proxy-addr": { 663 | "version": "2.0.3", 664 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", 665 | "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", 666 | "requires": { 667 | "forwarded": "0.1.2", 668 | "ipaddr.js": "1.6.0" 669 | } 670 | }, 671 | "qs": { 672 | "version": "6.5.2", 673 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 674 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 675 | }, 676 | "range-parser": { 677 | "version": "1.2.0", 678 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 679 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 680 | }, 681 | "raw-body": { 682 | "version": "2.3.3", 683 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", 684 | "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", 685 | "requires": { 686 | "bytes": "3.0.0", 687 | "http-errors": "1.6.3", 688 | "iconv-lite": "0.4.23", 689 | "unpipe": "1.0.0" 690 | } 691 | }, 692 | "redis": { 693 | "version": "2.8.0", 694 | "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", 695 | "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", 696 | "requires": { 697 | "double-ended-queue": "2.1.0-0", 698 | "redis-commands": "1.3.5", 699 | "redis-parser": "2.6.0" 700 | } 701 | }, 702 | "redis-commands": { 703 | "version": "1.3.5", 704 | "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.5.tgz", 705 | "integrity": "sha512-foGF8u6MXGFF++1TZVC6icGXuMYPftKXt1FBT2vrfU9ZATNtZJ8duRC5d1lEfE8hyVe3jhelHGB91oB7I6qLsA==" 706 | }, 707 | "redis-parser": { 708 | "version": "2.6.0", 709 | "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", 710 | "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=" 711 | }, 712 | "safe-buffer": { 713 | "version": "5.1.2", 714 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 715 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 716 | }, 717 | "safer-buffer": { 718 | "version": "2.1.2", 719 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 720 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 721 | }, 722 | "send": { 723 | "version": "0.16.2", 724 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 725 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 726 | "requires": { 727 | "debug": "2.6.9", 728 | "depd": "1.1.2", 729 | "destroy": "1.0.4", 730 | "encodeurl": "1.0.2", 731 | "escape-html": "1.0.3", 732 | "etag": "1.8.1", 733 | "fresh": "0.5.2", 734 | "http-errors": "1.6.3", 735 | "mime": "1.4.1", 736 | "ms": "2.0.0", 737 | "on-finished": "2.3.0", 738 | "range-parser": "1.2.0", 739 | "statuses": "1.4.0" 740 | }, 741 | "dependencies": { 742 | "statuses": { 743 | "version": "1.4.0", 744 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 745 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 746 | } 747 | } 748 | }, 749 | "serve-static": { 750 | "version": "1.13.2", 751 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", 752 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", 753 | "requires": { 754 | "encodeurl": "1.0.2", 755 | "escape-html": "1.0.3", 756 | "parseurl": "1.3.2", 757 | "send": "0.16.2" 758 | } 759 | }, 760 | "setprototypeof": { 761 | "version": "1.1.0", 762 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 763 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 764 | }, 765 | "socket.io": { 766 | "version": "2.0.4", 767 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.0.4.tgz", 768 | "integrity": "sha1-waRZDO/4fs8TxyZS8Eb3FrKeYBQ=", 769 | "requires": { 770 | "debug": "2.6.9", 771 | "engine.io": "3.1.5", 772 | "socket.io-adapter": "1.1.1", 773 | "socket.io-client": "2.0.4", 774 | "socket.io-parser": "3.1.3" 775 | } 776 | }, 777 | "socket.io-adapter": { 778 | "version": "1.1.1", 779 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", 780 | "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" 781 | }, 782 | "socket.io-client": { 783 | "version": "2.0.4", 784 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.0.4.tgz", 785 | "integrity": "sha1-CRilUkBtxeVAs4Dc2Xr8SmQzL44=", 786 | "requires": { 787 | "backo2": "1.0.2", 788 | "base64-arraybuffer": "0.1.5", 789 | "component-bind": "1.0.0", 790 | "component-emitter": "1.2.1", 791 | "debug": "2.6.9", 792 | "engine.io-client": "3.1.6", 793 | "has-cors": "1.1.0", 794 | "indexof": "0.0.1", 795 | "object-component": "0.0.3", 796 | "parseqs": "0.0.5", 797 | "parseuri": "0.0.5", 798 | "socket.io-parser": "3.1.3", 799 | "to-array": "0.1.4" 800 | } 801 | }, 802 | "socket.io-parser": { 803 | "version": "3.1.3", 804 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.1.3.tgz", 805 | "integrity": "sha512-g0a2HPqLguqAczs3dMECuA1RgoGFPyvDqcbaDEdCWY9g59kdUAz3YRmaJBNKXflrHNwB7Q12Gkf/0CZXfdHR7g==", 806 | "requires": { 807 | "component-emitter": "1.2.1", 808 | "debug": "3.1.0", 809 | "has-binary2": "1.0.3", 810 | "isarray": "2.0.1" 811 | }, 812 | "dependencies": { 813 | "debug": { 814 | "version": "3.1.0", 815 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 816 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 817 | "requires": { 818 | "ms": "2.0.0" 819 | } 820 | } 821 | } 822 | }, 823 | "statuses": { 824 | "version": "1.5.0", 825 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 826 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 827 | }, 828 | "to-array": { 829 | "version": "0.1.4", 830 | "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", 831 | "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" 832 | }, 833 | "type-is": { 834 | "version": "1.6.16", 835 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", 836 | "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", 837 | "requires": { 838 | "media-typer": "0.3.0", 839 | "mime-types": "2.1.18" 840 | } 841 | }, 842 | "ultron": { 843 | "version": "1.1.1", 844 | "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", 845 | "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" 846 | }, 847 | "unpipe": { 848 | "version": "1.0.0", 849 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 850 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 851 | }, 852 | "utils-merge": { 853 | "version": "1.0.1", 854 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 855 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 856 | }, 857 | "uuid": { 858 | "version": "3.2.1", 859 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", 860 | "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" 861 | }, 862 | "uws": { 863 | "version": "9.14.0", 864 | "resolved": "https://registry.npmjs.org/uws/-/uws-9.14.0.tgz", 865 | "integrity": "sha512-HNMztPP5A1sKuVFmdZ6BPVpBQd5bUjNC8EFMFiICK+oho/OQsAJy5hnIx4btMHiOk8j04f/DbIlqnEZ9d72dqg==", 866 | "optional": true 867 | }, 868 | "vary": { 869 | "version": "1.1.2", 870 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 871 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 872 | }, 873 | "ws": { 874 | "version": "3.3.3", 875 | "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", 876 | "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", 877 | "requires": { 878 | "async-limiter": "1.0.0", 879 | "safe-buffer": "5.1.2", 880 | "ultron": "1.1.1" 881 | } 882 | }, 883 | "xmlhttprequest-ssl": { 884 | "version": "1.5.5", 885 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", 886 | "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" 887 | }, 888 | "yeast": { 889 | "version": "0.1.2", 890 | "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", 891 | "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" 892 | } 893 | } 894 | } 895 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "microservices-workshop", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/dashersw/microservices-workshop.git" 9 | }, 10 | "author": "Armagan Amcalar ", 11 | "license": "MIT", 12 | "bugs": { 13 | "url": "https://github.com/dashersw/microservices-workshop/issues" 14 | }, 15 | "homepage": "https://github.com/dashersw/microservices-workshop#readme", 16 | "dependencies": { 17 | "body-parser": "^1.18.3", 18 | "cote": "^0.16.2", 19 | "express": "^4.16.3" 20 | }, 21 | "devDependencies": { 22 | "axios": "^0.18.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /restaurants-service/index.js: -------------------------------------------------------------------------------- 1 | const cote = require('cote') 2 | 3 | const restaurantsResponder = new cote.Responder({ name: 'restaurants responder', key: 'restaurants' }) 4 | restaurantsResponder.on('*', req => req.type && console.log(req)) 5 | 6 | const restaurants = [{ 7 | id: 0, 8 | name: 'Italian Restaurant', 9 | menu: [{ 10 | id: 0, 11 | name: 'Pizza', 12 | price: 14 13 | }, { 14 | id: 1, 15 | name: 'Pasta', 16 | price: 12 17 | }] 18 | }, { 19 | id: 1, 20 | name: 'American Restaurant', 21 | menu: [{ 22 | id: 0, 23 | name: 'Hamburger', 24 | price: 10 25 | }, { 26 | id: 1, 27 | name: 'Hot dog', 28 | price: 10 29 | }] 30 | }] 31 | 32 | restaurantsResponder.on(req => req.type && console.log(req)) 33 | 34 | restaurantsResponder.on('list', req => Promise.resolve(restaurants)) 35 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios') 2 | 3 | async function main() { 4 | const restaurants = await axios.get('http://localhost:3000/restaurants') 5 | console.log(restaurants.data) 6 | 7 | const orderRequest = { 8 | restaurantId: 1, 9 | menuId: 1, 10 | address: 'Wall Street 3, 68443' 11 | } 12 | 13 | const order = await axios.post('http://localhost:3000/order', orderRequest) 14 | console.log(order.data) 15 | } 16 | 17 | main() 18 | --------------------------------------------------------------------------------