{"id":27992110,"url":"https://github.com/dirkjbosman/node-postgresql-unstructured","last_synced_at":"2026-04-19T13:32:47.068Z","repository":{"id":81074792,"uuid":"290146957","full_name":"dirkjbosman/node-postgresql-unstructured","owner":"dirkjbosman","description":"An (Unstructured) Express Node PostgreSQL App ","archived":false,"fork":false,"pushed_at":"2020-09-12T13:16:30.000Z","size":65,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-08T17:57:24.423Z","etag":null,"topics":["api","express","javascript","node","nodejs","postgresql","sql"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dirkjbosman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-25T07:35:35.000Z","updated_at":"2020-09-12T13:16:33.000Z","dependencies_parsed_at":null,"dependency_job_id":"ce8353be-e7bc-4335-a466-00347339e2ca","html_url":"https://github.com/dirkjbosman/node-postgresql-unstructured","commit_stats":null,"previous_names":["dirkjbosman/node-postgresql-unstructured"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dirkjbosman/node-postgresql-unstructured","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dirkjbosman%2Fnode-postgresql-unstructured","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dirkjbosman%2Fnode-postgresql-unstructured/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dirkjbosman%2Fnode-postgresql-unstructured/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dirkjbosman%2Fnode-postgresql-unstructured/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dirkjbosman","download_url":"https://codeload.github.com/dirkjbosman/node-postgresql-unstructured/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dirkjbosman%2Fnode-postgresql-unstructured/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32009141,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","express","javascript","node","nodejs","postgresql","sql"],"created_at":"2025-05-08T17:57:22.389Z","updated_at":"2026-04-19T13:32:47.046Z","avatar_url":"https://github.com/dirkjbosman.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# node-postgresql-unstructured\n\n#### Summary:\n\n- node express server, middleware and apis\n- postgresql relational database\n\n### Boilerplates:\n\n- [Part 1: node-postgresql-unstructured](https://github.com/dirkbosman/node-postgresql-unstructured)\n- [Part 2: node-postgresql-destructured](https://github.com/dirkbosman/node-postgresql-destructured)\n- [Part 3: node-postgresql-controllers](https://github.com/dirkbosman/node-postgresql-controllers)\n---\n- [Part 4a: node-mongodb-controllers](https://github.com/dirkbosman/node-mongodb-controllers)\n- Part 4b: Combine [node-mongodb-clientforserver](https://github.com/dirkbosman/node-mongodb-clientforserver) + [node-mongodb-controllers](https://github.com/dirkbosman/node-mongodb-controllers)\n\n# Clone Repo\n\n```\ngit clone https://github.com/dirkbosman/node-postgresql-unstructured.git\ncd node-postgresql-unstructured\nnpm i\nnpm start\n```\n\n# Manual Set-up\n\n## Environment \u0026 Libraries\n\nInstall the necessary libraries:\n\n```\nnpm init -y\nnpm i express\nnpm i nodemon --save-dev\nnpm i dotenv\n```\n\nAdd the following to package.json:\n\n```\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" \u0026\u0026 exit 1\",\n    \"start\": \"nodemon server.js\"\n  }\n```\n\nNote: we add nodemon only for development, and not for production, because it is unsafe.\n\n```\n  \"dependencies\": {\n    \"dotenv\": \"^8.2.0\",\n    \"express\": \"^4.17.1\"\n  },\n  \"devDependencies\": {\n    \"nodemon\": \"^2.0.4\"\n  }\n```\n\nFor production, you would configure start-prod in npm-scripts / in docker configurations.\n\n```\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" \u0026\u0026 exit 1\",\n    \"start-prod\": \"node server.js\"\n  }\n```\n\nYou can run the following in the terminal to start the server (via nodemon):\n`npm start`\n\n## Database (PostgreSQL)\n\nNavigate to https://api.elephantsql.com/console/ to create an account and a server instance to host your database.\n\nCreate your database and copy the information. You will need this latter details to connect via your application.\n\nCreate your database tables now:\n\n```\nCREATE TABLE users (\n   id  SERIAL PRIMARY KEY,\n   first_name varchar(255),\n   last_name varchar(255),\n   age int\n);\n\nCREATE TABLE orders (\n   id  SERIAL PRIMARY KEY,\n   price float,\n   date timestamp,\n   user_id int,\n   FOREIGN KEY (user_id) REFERENCES users(id)\n);\n\nINSERT INTO users (first_name, last_name, age) VALUES ('John', 'Doe', 18);\nINSERT INTO users (first_name, last_name, age) VALUES ('Bob', 'Dylan', 30);\nINSERT INTO users (first_name, last_name, age) VALUES ('Jane', 'Doe', 25);\n\nINSERT INTO orders (price,date, user_id) VALUES ( 18, '2001-01-01 00:00:00', 1);\nINSERT INTO orders (price,date, user_id) VALUES ( 18, '2001-01-02 04:00:00', 1);\nINSERT INTO orders (price,date, user_id) VALUES ( 18, '2001-01-03 05:00:00', 2);\nINSERT INTO orders (price,date, user_id) VALUES ( 18, '2001-01-04 06:00:00', 2);\n```\n\nTest whether you get an output under the `Browse`-tab:\n\n- `SELECT * FROM users;`\n- `SELECT * FROM orders;`\n\nInstall the PostgreSQL adapter in Node:\n`npm i pg`\n\nhttps://www.elephantsql.com/\nhttps://customer.elephantsql.com/instance\n\nYou can log in with your Github Account\n\nCreate a new instance\n\nAdd your connection details from your console's [settings](https://api.elephantsql.com/console/) in a `.env`- or `.env.production`-file, as well as add `.env`- or `.env.production` in your `.gitignore`-file. Note the way you use the .env file can depend on your OS, so replicate the syntax that worked for you.\n\nUsually:\n\n- PGUSER =\u003e Username\n- PGHOST =\u003e Server\n- PGPASSWORD =\u003e PW\n- PGDATABASE =\u003e Username\n- PGPORT =\u003e \u003c4-letters\u003e\n\n```\nPGUSER=\u003cvalue-same\u003e\nPGHOST=\u003cvalue\u003e\nPGPASSWORD=\u003cvalue\u003e\nPGDATABASE=\u003cvalue-same\u003e\nPGPORT=\u003cvalue\u003e\n```\n\n## Server \u0026 APIs Setup (Node \u0026 Express)\n\nRead:\n\n- https://expressjs.com/en/guide/routing.html\n- https://node-postgres.com\n- https://developer.mozilla.org/en-US/docs/Web/HTTP/Status\n- https://developer.mozilla.org/en-US/docs/Glossary/REST\n- https://developer.mozilla.org/en-US/docs/Web/API\n\nCreate routes for the _users_ on:\n\n- `GET` on `/` -\u003e To get all the users.\n- `GET` on `/:id` -\u003e To get one user (with the id).\n- `POST` on `/` -\u003e To create a new user.\n- `PUT` on `/:id` -\u003e To edit one user (with the id).\n- `DELETE` on `/:id` -\u003e To delete one user (with the id).\n\nCreate routes for the _orders_ on:\n\n- `GET` on `/` -\u003e To get all the orders.\n- `GET` on `/:id` -\u003e To get one order (with the id).\n- `POST` on `/` -\u003e To create a new order.\n- `PUT` on `/:id` -\u003e To edit one order (with the id).\n- `DELETE` on `/:id` -\u003e To delete one order (with the id).\n\nCreating the main file:\n\n```\n# express.js\n\nrequire('dotenv').config();\nconst express = require(\"express\");\nconst { Pool } = require('pg');\n\nconst app = express();\nconst pool = new Pool();\n\napp.get(\"/\", (req, res) =\u003e res.send(\"hello world\"));\n\napp.listen('3000', () =\u003e console.log('connected'));\n```\n\nNavigate to: `http://localhost:3000/`:\n`hello world`\n\nAdd a new route to server.js:\n\n```\napp.get(\"/users\", (req, res) =\u003e {\n  pool\n    .query(\"SELECT * FROM users;\")\n    .then((data) =\u003e res.json(data.rows))\n    .catch((e) =\u003e res.sendStatus(404));\n});\n```\n\nNavigate to: `http://localhost:3000/users`:\n`[{\"id\":1,\"first_name\":\"John\",\"last_name\":\"Doe\",\"age\":18},{\"id\":2,\"first_name\":\"Bob\",\"last_name\":\"Dylan\",\"age\":30},{\"id\":3,\"first_name\":\"Jane\",\"last_name\":\"Doe\",\"age\":25}]`\n\nAdd a new route to server.js.\n\n- Note: Add a prepared statement(s) \"[id]\" to protect against SQL injection:\n\n```\napp.get(\"/users/:id\", (req, res) =\u003e {\n  const { id } = req.params;\n  pool\n    .query(\"SELECT * FROM users WHERE id=$1;\", [id])\n    .then((data) =\u003e res.json(data.rows))\n    .catch((e) =\u003e res.sendStatus(404));\n});\n```\n\nNavigate to: `http://localhost:3000/users/1`:\n`[{\"id\":1,\"first_name\":\"John\",\"last_name\":\"Doe\",\"age\":18}]`\n\nNavigate to: `http://localhost:3000/users` vs `http://localhost:3000/users/4`:\n\n- It should give you an empty array, because no values exist in the DB for this id.\n  `[]`\n\n#### SQL Injection:\n\nThis is an SQL injection you can easily try as it does not involve a new query and does not kill your database\n\n```\napp.get(\"/users/:id\", (req, res) =\u003e {\n const { id } = req.params;\n pool\n   .query(`SELECT * FROM users WHERE id=${id}`)\n   .then(data =\u003e res.json(data.rows))\n   .catch(e =\u003e res.sendStatus(500));\n});\n```\n\nand your address would be: `http://localhost:3000/users/(SELECT%20MAX(id)%20FROM%20users)`, everything after `http://localhost:3000/users/` is saved under the `id`-param and then executed as a select-statement. The outcome should be: the user with the highest id. Note: the endpoint version in server.js uses prepared statements, so hitting the same url will output an error.\n\n#### SQL Prevention Demo \u0026 Protection:\n\n```\napp.get(\"/users/:id\", (req, res) =\u003e {\nconst { id } = req.params;\npool\n  .query(`SELECT * FROM users WHERE id=${id}`)\n  .then((data) =\u003e res.json(data.rows))\n  .catch((e) =\u003e res.sendStatus(500));\n});\n```\n\n#### Middleware:\n\n- Install the middleware:\n  `npm i body-parser`\n\n#### INSERT Record(s):\n\n```\napp.post(\"/users\", (req, res) =\u003e {\n  const { first_name, last_name, age } = req.body;\n\n  pool\n    .query(\"INSERT INTO users(first_name, last_name, age) values($1,$2, $3);\", [\n      first_name,\n      last_name,\n      age,\n    ])\n    .then((data) =\u003e res.status(201).json(data))\n    .catch((e) =\u003e res.sendStatus(500));\n});\n```\n\nTerminal:\n`curl -X POST -H \"Content-Type:application/json\" http://localhost:3000/users -d '{\"first_name\":\"Piet\", \"last_name\":\"Skyf\", \"age\":\"17\"}'`\n\n#### DELETE Record(s):\n\n```\napp.delete(\"/users/:id\", (req, res) =\u003e {\n const { id } = req.params;\n\n pool\n   .query('DELETE FROM users WHERE id=$1;', [id])\n   .then(data =\u003e res.status(201).json(data))\n   .catch(e =\u003e res.sendStatus(500));\n});\n```\n\nTerminal:\n\n- Note: You will not be able to delete a record (via curl) if you have a reference from one record to another table's record in the DB.\n  `curl -H \"Content-Type: application/json\" -X DELETE http://localhost:3000/users/3`\n\n#### UPDATE Record(s):\n\n```\napp.put(\"/users/:id\", (req, res) =\u003e {\n const { id } = req.params;\n const { name } = req.body;\n pool\n   .query('UPDATE users SET first_name=$1 WHERE id=$2;', [name, id])\n   .then(data =\u003e res.status(201).json(data))\n   .catch(e =\u003e res.sendStatus(500));\n});\n```\n\nTerminal:\n`curl -d '{\"name\": \"Pikachu\"}' -H \"Content-Type: application/json\" -X PUT http://localhost:3000/users/5`\n\n## Appendix\n\nTo look whether curl requests were successful, you can for example navigate to:\n\n- http://localhost:3000/users\n- http://localhost:3000/orders\n\nFurthermore, you can install the following Google Chrome extension to format JSON for you: `JSON Formatter`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdirkjbosman%2Fnode-postgresql-unstructured","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdirkjbosman%2Fnode-postgresql-unstructured","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdirkjbosman%2Fnode-postgresql-unstructured/lists"}