├── .gitignore ├── LICENSE ├── README.md ├── index.js ├── package-lock.json ├── package.json └── queries.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tania Rascia 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 | # RESTful API with Node.js, Express, and Postgres 2 | 3 | Create, read, update, delete in a Node.js app with an Express server and Postgres database. 4 | 5 | ### [Read the tutorial](https://blog.logrocket.com/setting-up-a-restful-api-with-node-js-and-postgresql-d96d6fc892d8/) 6 | 7 | ## Database 8 | 9 | ```bash 10 | brew install postgresql 11 | brew services start postgresql 12 | psql postgres 13 | ``` 14 | 15 | ```sql 16 | CREATE ROLE me WITH LOGIN PASSWORD 'password'; 17 | ALTER ROLE me CREATEDB; 18 | CREATE DATABASE api; 19 | GRANT ALL PRIVILEGES ON DATABASE api TO me; 20 | ``` 21 | 22 | ```bash 23 | psql -d api -U me 24 | ``` 25 | 26 | ```sql 27 | CREATE TABLE users ( 28 | ID SERIAL PRIMARY KEY, 29 | name VARCHAR(30), 30 | email VARCHAR(30) 31 | ); 32 | 33 | INSERT INTO users (name, email) 34 | VALUES ('Jerry', 'jerry@example.com'), ('George', 'george@example.com'); 35 | ``` 36 | 37 | ## Installation 38 | 39 | ```bash 40 | git clone git@github.com:taniarascia/node-api-postgres 41 | cd node-api-postgres 42 | npm install 43 | node index.js 44 | ``` 45 | 46 | ## Commands 47 | 48 | - GET: `curl http://localhost:3000/users` 49 | - POST: `curl --data "name=Jerry&email=jerry@example.com" http://localhost:3000/users` 50 | - PUT: `curl -X PUT -d "name=George" -d "email=george@example.com" http://localhost:3000/users/1` 51 | - DELETE: `curl -X "DELETE" http://localhost:3000/users/1` 52 | 53 | ## Author 54 | 55 | - [Tania Rascia](https://www.taniarascia.com) 56 | 57 | ## License 58 | 59 | This project is open source and available under the [MIT License](LICENSE). 60 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const bodyParser = require('body-parser') 3 | const app = express() 4 | const db = require('./queries') 5 | const port = 3000 6 | 7 | app.use(bodyParser.json()) 8 | app.use( 9 | bodyParser.urlencoded({ 10 | extended: true, 11 | }) 12 | ) 13 | 14 | app.get('/', (request, response) => { 15 | response.json({ info: 'Node.js, Express, and Postgres API' }) 16 | }) 17 | 18 | 19 | app.get('/users', db.getUsers) 20 | app.get('/users/:id', db.getUserById) 21 | app.post('/users', db.createUser) 22 | app.put('/users/:id', db.updateUser) 23 | app.delete('/users/:id', db.deleteUser) 24 | 25 | app.listen(port, () => { 26 | console.log(`App running on port ${port}.`) 27 | }) 28 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pgapp", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.5", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", 10 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", 11 | "requires": { 12 | "mime-types": "~2.1.18", 13 | "negotiator": "0.6.1" 14 | } 15 | }, 16 | "array-flatten": { 17 | "version": "1.1.1", 18 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 19 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 20 | }, 21 | "body-parser": { 22 | "version": "1.18.2", 23 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", 24 | "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", 25 | "requires": { 26 | "bytes": "3.0.0", 27 | "content-type": "~1.0.4", 28 | "debug": "2.6.9", 29 | "depd": "~1.1.1", 30 | "http-errors": "~1.6.2", 31 | "iconv-lite": "0.4.19", 32 | "on-finished": "~2.3.0", 33 | "qs": "6.5.1", 34 | "raw-body": "2.3.2", 35 | "type-is": "~1.6.15" 36 | } 37 | }, 38 | "buffer-writer": { 39 | "version": "1.0.1", 40 | "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-1.0.1.tgz", 41 | "integrity": "sha1-Iqk2kB4wKa/NdUfrRIfOtpejvwg=" 42 | }, 43 | "bytes": { 44 | "version": "3.0.0", 45 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 46 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 47 | }, 48 | "content-disposition": { 49 | "version": "0.5.2", 50 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 51 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 52 | }, 53 | "content-type": { 54 | "version": "1.0.4", 55 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 56 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 57 | }, 58 | "cookie": { 59 | "version": "0.3.1", 60 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 61 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 62 | }, 63 | "cookie-signature": { 64 | "version": "1.0.6", 65 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 66 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 67 | }, 68 | "debug": { 69 | "version": "2.6.9", 70 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 71 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 72 | "requires": { 73 | "ms": "2.0.0" 74 | } 75 | }, 76 | "depd": { 77 | "version": "1.1.2", 78 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 79 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 80 | }, 81 | "destroy": { 82 | "version": "1.0.4", 83 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 84 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 85 | }, 86 | "ee-first": { 87 | "version": "1.1.1", 88 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 89 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 90 | }, 91 | "encodeurl": { 92 | "version": "1.0.2", 93 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 94 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 95 | }, 96 | "escape-html": { 97 | "version": "1.0.3", 98 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 99 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 100 | }, 101 | "etag": { 102 | "version": "1.8.1", 103 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 104 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 105 | }, 106 | "express": { 107 | "version": "4.16.3", 108 | "resolved": "http://registry.npmjs.org/express/-/express-4.16.3.tgz", 109 | "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", 110 | "requires": { 111 | "accepts": "~1.3.5", 112 | "array-flatten": "1.1.1", 113 | "body-parser": "1.18.2", 114 | "content-disposition": "0.5.2", 115 | "content-type": "~1.0.4", 116 | "cookie": "0.3.1", 117 | "cookie-signature": "1.0.6", 118 | "debug": "2.6.9", 119 | "depd": "~1.1.2", 120 | "encodeurl": "~1.0.2", 121 | "escape-html": "~1.0.3", 122 | "etag": "~1.8.1", 123 | "finalhandler": "1.1.1", 124 | "fresh": "0.5.2", 125 | "merge-descriptors": "1.0.1", 126 | "methods": "~1.1.2", 127 | "on-finished": "~2.3.0", 128 | "parseurl": "~1.3.2", 129 | "path-to-regexp": "0.1.7", 130 | "proxy-addr": "~2.0.3", 131 | "qs": "6.5.1", 132 | "range-parser": "~1.2.0", 133 | "safe-buffer": "5.1.1", 134 | "send": "0.16.2", 135 | "serve-static": "1.13.2", 136 | "setprototypeof": "1.1.0", 137 | "statuses": "~1.4.0", 138 | "type-is": "~1.6.16", 139 | "utils-merge": "1.0.1", 140 | "vary": "~1.1.2" 141 | } 142 | }, 143 | "finalhandler": { 144 | "version": "1.1.1", 145 | "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", 146 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", 147 | "requires": { 148 | "debug": "2.6.9", 149 | "encodeurl": "~1.0.2", 150 | "escape-html": "~1.0.3", 151 | "on-finished": "~2.3.0", 152 | "parseurl": "~1.3.2", 153 | "statuses": "~1.4.0", 154 | "unpipe": "~1.0.0" 155 | } 156 | }, 157 | "forwarded": { 158 | "version": "0.1.2", 159 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 160 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 161 | }, 162 | "fresh": { 163 | "version": "0.5.2", 164 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 165 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 166 | }, 167 | "http-errors": { 168 | "version": "1.6.3", 169 | "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 170 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 171 | "requires": { 172 | "depd": "~1.1.2", 173 | "inherits": "2.0.3", 174 | "setprototypeof": "1.1.0", 175 | "statuses": ">= 1.4.0 < 2" 176 | } 177 | }, 178 | "iconv-lite": { 179 | "version": "0.4.19", 180 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 181 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" 182 | }, 183 | "inherits": { 184 | "version": "2.0.3", 185 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 186 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 187 | }, 188 | "ipaddr.js": { 189 | "version": "1.8.0", 190 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", 191 | "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" 192 | }, 193 | "media-typer": { 194 | "version": "0.3.0", 195 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 196 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 197 | }, 198 | "merge-descriptors": { 199 | "version": "1.0.1", 200 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 201 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 202 | }, 203 | "methods": { 204 | "version": "1.1.2", 205 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 206 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 207 | }, 208 | "mime": { 209 | "version": "1.4.1", 210 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 211 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 212 | }, 213 | "mime-db": { 214 | "version": "1.36.0", 215 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", 216 | "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" 217 | }, 218 | "mime-types": { 219 | "version": "2.1.20", 220 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", 221 | "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", 222 | "requires": { 223 | "mime-db": "~1.36.0" 224 | } 225 | }, 226 | "ms": { 227 | "version": "2.0.0", 228 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 229 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 230 | }, 231 | "negotiator": { 232 | "version": "0.6.1", 233 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 234 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 235 | }, 236 | "on-finished": { 237 | "version": "2.3.0", 238 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 239 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 240 | "requires": { 241 | "ee-first": "1.1.1" 242 | } 243 | }, 244 | "packet-reader": { 245 | "version": "0.3.1", 246 | "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-0.3.1.tgz", 247 | "integrity": "sha1-zWLmCvjX/qinBexP+ZCHHEaHHyc=" 248 | }, 249 | "parseurl": { 250 | "version": "1.3.2", 251 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 252 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 253 | }, 254 | "path-to-regexp": { 255 | "version": "0.1.7", 256 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 257 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 258 | }, 259 | "pg": { 260 | "version": "7.4.3", 261 | "resolved": "https://registry.npmjs.org/pg/-/pg-7.4.3.tgz", 262 | "integrity": "sha1-97b5P1NA7MJZavu5ShPj1rYJg0s=", 263 | "requires": { 264 | "buffer-writer": "1.0.1", 265 | "packet-reader": "0.3.1", 266 | "pg-connection-string": "0.1.3", 267 | "pg-pool": "~2.0.3", 268 | "pg-types": "~1.12.1", 269 | "pgpass": "1.x", 270 | "semver": "4.3.2" 271 | } 272 | }, 273 | "pg-connection-string": { 274 | "version": "0.1.3", 275 | "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz", 276 | "integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc=" 277 | }, 278 | "pg-pool": { 279 | "version": "2.0.3", 280 | "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.3.tgz", 281 | "integrity": "sha1-wCIDLIlJ8xKk+R+2QJzgQHa+Mlc=" 282 | }, 283 | "pg-types": { 284 | "version": "1.12.1", 285 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.12.1.tgz", 286 | "integrity": "sha1-1kCH45A7WP+q0nnnWVxSIIoUw9I=", 287 | "requires": { 288 | "postgres-array": "~1.0.0", 289 | "postgres-bytea": "~1.0.0", 290 | "postgres-date": "~1.0.0", 291 | "postgres-interval": "^1.1.0" 292 | } 293 | }, 294 | "pgpass": { 295 | "version": "1.0.2", 296 | "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz", 297 | "integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=", 298 | "requires": { 299 | "split": "^1.0.0" 300 | } 301 | }, 302 | "postgres-array": { 303 | "version": "1.0.3", 304 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.3.tgz", 305 | "integrity": "sha512-5wClXrAP0+78mcsNX3/ithQ5exKvCyK5lr5NEEEeGwwM6NJdQgzIJBVxLvRW+huFpX92F2QnZ5CcokH0VhK2qQ==" 306 | }, 307 | "postgres-bytea": { 308 | "version": "1.0.0", 309 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", 310 | "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" 311 | }, 312 | "postgres-date": { 313 | "version": "1.0.3", 314 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.3.tgz", 315 | "integrity": "sha1-4tiXAu/bJY/52c7g/pG9BpdSV6g=" 316 | }, 317 | "postgres-interval": { 318 | "version": "1.1.2", 319 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.1.2.tgz", 320 | "integrity": "sha512-fC3xNHeTskCxL1dC8KOtxXt7YeFmlbTYtn7ul8MkVERuTmf7pI4DrkAxcw3kh1fQ9uz4wQmd03a1mRiXUZChfQ==", 321 | "requires": { 322 | "xtend": "^4.0.0" 323 | } 324 | }, 325 | "proxy-addr": { 326 | "version": "2.0.4", 327 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", 328 | "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", 329 | "requires": { 330 | "forwarded": "~0.1.2", 331 | "ipaddr.js": "1.8.0" 332 | } 333 | }, 334 | "qs": { 335 | "version": "6.5.1", 336 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 337 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" 338 | }, 339 | "range-parser": { 340 | "version": "1.2.0", 341 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 342 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 343 | }, 344 | "raw-body": { 345 | "version": "2.3.2", 346 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", 347 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", 348 | "requires": { 349 | "bytes": "3.0.0", 350 | "http-errors": "1.6.2", 351 | "iconv-lite": "0.4.19", 352 | "unpipe": "1.0.0" 353 | }, 354 | "dependencies": { 355 | "depd": { 356 | "version": "1.1.1", 357 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 358 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" 359 | }, 360 | "http-errors": { 361 | "version": "1.6.2", 362 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 363 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", 364 | "requires": { 365 | "depd": "1.1.1", 366 | "inherits": "2.0.3", 367 | "setprototypeof": "1.0.3", 368 | "statuses": ">= 1.3.1 < 2" 369 | } 370 | }, 371 | "setprototypeof": { 372 | "version": "1.0.3", 373 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", 374 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" 375 | } 376 | } 377 | }, 378 | "safe-buffer": { 379 | "version": "5.1.1", 380 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 381 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 382 | }, 383 | "semver": { 384 | "version": "4.3.2", 385 | "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz", 386 | "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=" 387 | }, 388 | "send": { 389 | "version": "0.16.2", 390 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 391 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 392 | "requires": { 393 | "debug": "2.6.9", 394 | "depd": "~1.1.2", 395 | "destroy": "~1.0.4", 396 | "encodeurl": "~1.0.2", 397 | "escape-html": "~1.0.3", 398 | "etag": "~1.8.1", 399 | "fresh": "0.5.2", 400 | "http-errors": "~1.6.2", 401 | "mime": "1.4.1", 402 | "ms": "2.0.0", 403 | "on-finished": "~2.3.0", 404 | "range-parser": "~1.2.0", 405 | "statuses": "~1.4.0" 406 | } 407 | }, 408 | "serve-static": { 409 | "version": "1.13.2", 410 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", 411 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", 412 | "requires": { 413 | "encodeurl": "~1.0.2", 414 | "escape-html": "~1.0.3", 415 | "parseurl": "~1.3.2", 416 | "send": "0.16.2" 417 | } 418 | }, 419 | "setprototypeof": { 420 | "version": "1.1.0", 421 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 422 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 423 | }, 424 | "split": { 425 | "version": "1.0.1", 426 | "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", 427 | "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", 428 | "requires": { 429 | "through": "2" 430 | } 431 | }, 432 | "statuses": { 433 | "version": "1.4.0", 434 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 435 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 436 | }, 437 | "through": { 438 | "version": "2.3.8", 439 | "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", 440 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" 441 | }, 442 | "type-is": { 443 | "version": "1.6.16", 444 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", 445 | "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", 446 | "requires": { 447 | "media-typer": "0.3.0", 448 | "mime-types": "~2.1.18" 449 | } 450 | }, 451 | "unpipe": { 452 | "version": "1.0.0", 453 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 454 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 455 | }, 456 | "utils-merge": { 457 | "version": "1.0.1", 458 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 459 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 460 | }, 461 | "vary": { 462 | "version": "1.1.2", 463 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 464 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 465 | }, 466 | "xtend": { 467 | "version": "4.0.1", 468 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 469 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" 470 | } 471 | } 472 | } 473 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-postgres", 3 | "version": "1.0.0", 4 | "description": "RESTful API with Node.js, Express, and PostgreSQL", 5 | "main": "index.js", 6 | "license": "MIT", 7 | "dependencies": { 8 | "express": "^4.16.3", 9 | "pg": "^7.4.3" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /queries.js: -------------------------------------------------------------------------------- 1 | const Pool = require('pg').Pool 2 | const pool = new Pool({ 3 | user: 'me', 4 | host: 'localhost', 5 | database: 'api', 6 | password: 'password', 7 | port: 5432, 8 | }) 9 | 10 | const getUsers = (request, response) => { 11 | pool.query('SELECT * FROM users ORDER BY id ASC', (error, results) => { 12 | if (error) { 13 | throw error 14 | } 15 | response.status(200).json(results.rows) 16 | }) 17 | } 18 | 19 | const getUserById = (request, response) => { 20 | const id = parseInt(request.params.id) 21 | 22 | pool.query('SELECT * FROM users WHERE id = $1', [id], (error, results) => { 23 | if (error) { 24 | throw error 25 | } 26 | response.status(200).json(results.rows) 27 | }) 28 | } 29 | 30 | const createUser = (request, response) => { 31 | const { name, email } = request.body 32 | 33 | pool.query('INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *', [name, email], (error, results) => { 34 | if (error) { 35 | throw error 36 | } else if (!Array.isArray(results.rows) || results.rows.length < 1) { 37 | throw error 38 | } 39 | response.status(201).send(`User added with ID: ${results.rows[0].id}`) 40 | }) 41 | } 42 | 43 | const updateUser = (request, response) => { 44 | const id = parseInt(request.params.id) 45 | const { name, email } = request.body 46 | 47 | pool.query( 48 | 'UPDATE users SET name = $1, email = $2 WHERE id = $3 RETURNING *', 49 | [name, email, id], 50 | (error, results) => { 51 | if (error) { 52 | throw error 53 | } 54 | if (typeof results.rows == 'undefined') { 55 | response.status(404).send(`Resource not found`); 56 | } else if (Array.isArray(results.rows) && results.rows.length < 1) { 57 | response.status(404).send(`User not found`); 58 | } else { 59 | response.status(200).send(`User modified with ID: ${results.rows[0].id}`) 60 | } 61 | 62 | } 63 | ) 64 | } 65 | 66 | const deleteUser = (request, response) => { 67 | const id = parseInt(request.params.id) 68 | 69 | pool.query('DELETE FROM users WHERE id = $1', [id], (error, results) => { 70 | if (error) { 71 | throw error 72 | } 73 | response.status(200).send(`User deleted with ID: ${id}`) 74 | }) 75 | } 76 | 77 | module.exports = { 78 | getUsers, 79 | getUserById, 80 | createUser, 81 | updateUser, 82 | deleteUser, 83 | } 84 | --------------------------------------------------------------------------------