From 8fa53167fc90989ca095846b3186b54971b53401 Mon Sep 17 00:00:00 2001 From: JOANNABUUMA1 Date: Wed, 26 Jun 2024 16:57:49 +0100 Subject: [PATCH 1/6] initial set up, .env and db openning --- README.md | 61 ++++++++++++++++++++++++------------------ package-lock.json | 67 +++++++++++------------------------------------ src/data/db.js | 15 +++++++++++ 3 files changed, 65 insertions(+), 78 deletions(-) create mode 100644 src/data/db.js diff --git a/README.md b/README.md index c4fc73be..281223b5 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,9 @@ In this workshop we're going to look at how to use express with a postgres database. ## Learning Objectives -* Explain how REST API methods interact with a relational database -* Implement a REST API backed by a database using express and postgres + +- Explain how REST API methods interact with a relational database +- Implement a REST API backed by a database using express and postgres ## Setup @@ -20,16 +21,16 @@ For this exercise we will also need to configure our database: 6. Copy the SQL from the files in the `sql/` directory and run them in TablePlus -* create-books.sql -* create-pets.sql -* insert-books.sql -* insert-pets.sql +- create-books.sql +- create-pets.sql +- insert-books.sql +- insert-pets.sql 7. Copy the URL of your instance -8. Create a file `.env` in the __root directory__ of your project. It should be right next to the `.env.example` file. It should contain a single line, which contains the *environment variable* used to specify the url from the instance created above. See the example file for reference. +8. Create a file `.env` in the **root directory** of your project. It should be right next to the `.env.example` file. It should contain a single line, which contains the _environment variable_ used to specify the url from the instance created above. See the example file for reference. -7. Type `npm start`, which starts a development server that will reload whenever you make any changes to source files. +9. Type `npm start`, which starts a development server that will reload whenever you make any changes to source files. All being well, you will have a terminal window that looks like the following: @@ -38,60 +39,68 @@ All being well, you will have a terminal window that looks like the following: _Figure 2: The terminal window where the express server is running successfully_ ## Interacting with the Database + To interact with the database we will use the [node-postgres](https://node-postgres.com/) library. We will use the [query](https://node-postgres.com/features/queries) method to send SQL queries to the database sever and receive responses. The `db/index.js` file establishes the connection to the database. Your instructor will walk through this with you. ## Demo + Your instructor will demonstrate implementing some of the books API, now using a real database. You will complete the API spec implementation ## Instructions + - Implement the [API spec](https://boolean-uk.github.io/api-express-database/standard) ## Tests Run the following commands from your project directory to run the test suites: + ```sh -$ npm test # standard criteria -$ npm run test-extensions # extension criteria +npm test # standard criteria +npm run test-extensions # extension criteria ``` You can also focus on one test at a time - use the [jest docs](https://jestjs.io/docs/cli) to help filter which tests to run. We recommend you run tests manually with the option `--forceExit`. For example, for the following test: + ```js it("will list all books", async () => { - const response = await supertest(app).get("/books") + const response = await supertest(app).get("/books"); - expect(response.status).toEqual(200) - expect(response.body.books).not.toEqual(undefined) - expect(response.body.books.length).toEqual(2) - const expectedBooks = [book1, book2] + expect(response.status).toEqual(200); + expect(response.body.books).not.toEqual(undefined); + expect(response.body.books.length).toEqual(2); + const expectedBooks = [book1, book2]; response.body.books.forEach((retrievedBook, index) => { - expect(retrievedBook.title).toEqual(expectedBooks[index].title) - }) -}) + expect(retrievedBook.title).toEqual(expectedBooks[index].title); + }); +}); ``` Here are two ways to run it. + ```sh -$ npx jest -t "will list all books" --forceExit -$ npx jest test/api/routes/books.spec.js --forceExit # remember to add the 'f' before it() +npx jest -t "will list all books" --forceExit +npx jest test/api/routes/books.spec.js --forceExit # remember to add the 'f' before it() ``` ## Extension 1 + - Implement the [extension API spec](https://boolean-uk.github.io/api-express-database/extension) -- This API spec has some of the same endpoints as the Standard Criteria API spec, but they are **in addition to / build - on top of** that one. +- This API spec has some of the same endpoints as the Standard Criteria API spec, but they are **in addition to / build + on top of** that one. ## Extension 2 + So far we've been including all our database code directly in our route handlers. In a real application, this is considered bad practice. It would become difficult to maintain as the code base grows, and we are also mixing concerns. We have routing code, request/response handling and database access all in a single function. This leads to tight coupling and low cohesion. -It is better practice to split your code into different *layers*. This helps keep our code decoupled. Rather than your route handler implementing all your logic, you can introduce controller functions that handle your routes as well as specific functions for calling the database. There is no single "correct" approach, but here are some examples: +It is better practice to split your code into different _layers_. This helps keep our code decoupled. Rather than your route handler implementing all your logic, you can introduce controller functions that handle your routes as well as specific functions for calling the database. There is no single "correct" approach, but here are some examples: -* [MDN Express controllers and routes](https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes) -* [Express REST API structure](https://www.coreycleary.me/project-structure-for-an-express-rest-api-when-there-is-no-standard-way) +- [MDN Express controllers and routes](https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes) +- [Express REST API structure](https://www.coreycleary.me/project-structure-for-an-express-rest-api-when-there-is-no-standard-way) There is also an example boolean repository that provides a suggested structure: -* [API Express Architecture](https://github.com/boolean-uk/api-express-architecture-example) +- [API Express Architecture](https://github.com/boolean-uk/api-express-architecture-example) Update your implementation to match the structure of the above repo. Controllers functions should handle your requests and responses, and repository functions should handle your database access. diff --git a/package-lock.json b/package-lock.json index 37ccdff8..f08df953 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1441,12 +1441,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1740,9 +1740,9 @@ "dev": true }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -2024,16 +2024,16 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -2064,43 +2064,6 @@ "node": ">= 0.10.0" } }, - "node_modules/express/node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/express/node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/faker": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", @@ -2128,9 +2091,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" diff --git a/src/data/db.js b/src/data/db.js new file mode 100644 index 00000000..dd5c3ec6 --- /dev/null +++ b/src/data/db.js @@ -0,0 +1,15 @@ +const { Pool } = require("pg"); + +const { PGHOST, PGDATABASE, PGUSER, PGPASSWORD } = process.env; + +const db = new Pool({ + host: PGHOST, + database: PGDATABASE, + username: PGUSER, + password: PGPASSWORD, + ssl: { + require: true, + }, +}); + +module.exports = db; From 2f4f0cdb4749d088ad153e091dca4b6368b1d451 Mon Sep 17 00:00:00 2001 From: JOANNABUUMA1 Date: Wed, 26 Jun 2024 17:03:56 +0100 Subject: [PATCH 2/6] template for the books router --- src/data/books.js | 13 ++++++ src/routers/books.js | 97 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 src/data/books.js diff --git a/src/data/books.js b/src/data/books.js new file mode 100644 index 00000000..4b5e44d9 --- /dev/null +++ b/src/data/books.js @@ -0,0 +1,13 @@ +const all = () => {}; +const getById = (id) => {}; +const create = (book) => {}; +const update = (book) => {}; +const remove = (book) => {}; + +module.exports = { + all, + getById, + create, + update, + remove, +}; diff --git a/src/routers/books.js b/src/routers/books.js index 1551dd87..3b29043a 100644 --- a/src/routers/books.js +++ b/src/routers/books.js @@ -1,9 +1,96 @@ -const express = require('express') -const router = express.Router() +const express = require("express"); +const router = express.Router(); const db = require("../../db"); +const db_books = require("../data/books"); -router.get('/', async (req, res) => { +router.get("/", async (req, res) => {}); -}) +module.exports = router; -module.exports = router +const all = (req, res) => { + const books = db_books.all(); + res.status(200).json({ books: books }); +}; + +const get = (req, res) => { + const id = Number(req.params.id); + const found = db_books.getById(id); + + if (!found) { + res.status(404).send({ error: "A book the provided ID does not exist" }); + throw new NotFoundError("A book the provided ID does not exist"); + } + + res.status(200).json({ book: found }); +}; + +const create = (req, res) => { + const newBook = req.body; + if (!newBook.title || !newBook.author || !newBook.type) { + res.status(400).send({ error: `Missing fields in request body` }); + throw new MissingFieldError(`Missing fields in request body`); + } + + if (books.find((book) => book.title === newBook.title)) { + res + .status(409) + .send({ error: `A book with the provided title already exists` }); + throw new MissingFieldError( + `A book with the provided title already exists` + ); + } + newBook.id = bookID; + books.push(newBook); + bookID++; + res.status(201).json({ book: newBook }); +}; + +const update = (req, res) => { + const id = Number(req.params.id); + const updates = req.body; + + if (!updates.title || !updates.author || !updates.type) { + res.status(400).send({ error: `Missing fields in request body` }); + throw new MissingFieldError(`Missing fields in the request body`); + } + + const found = books.find((book) => book.id === id); + if (!found) { + res.status(404).send({ error: `A book the provided ID does not exist` }); + throw new NotFoundError(`A book with the provided ID does not exist`); + } + + if (books.find((book) => book.title === updates.title)) { + res + .status(409) + .send({ error: `A book with the provided title already exists` }); + throw new MissingFieldError( + `A book with the provided title already exists` + ); + } + + const index = books.indexOf(found); + const updated = { ...found, ...updates }; + res.status(200).json({ book: updated }); +}; + +const remove = (req, res) => { + const id = Number(req.params.id); + const found = books.find((book) => book.id === id); + if (!found) { + res.status(404).send({ error: `A book the provided ID does not exist` }); + throw new NotFoundError(`Book with the provided ID does not exist`); + } + + const index = books.indexOf(found); + books.splice(index, 1); + res.status(200).json({ book: found }); +}; + +module.exports = { + all, + get, + create, + update, + remove, +}; \ No newline at end of file From 4cdfd9572f6227d611ae752f9921be4e6717beb8 Mon Sep 17 00:00:00 2001 From: JOANNABUUMA1 Date: Wed, 26 Jun 2024 18:02:06 +0100 Subject: [PATCH 3/6] fixing bugs and connecting the database --- src/data/books.js | 55 +++++++++++++++++++++++++--- src/data/db.js | 34 ++++++++++------- src/data/pets.js | 0 src/routers/books.js | 87 +++++++++----------------------------------- src/server.js | 1 + 5 files changed, 90 insertions(+), 87 deletions(-) create mode 100644 src/data/pets.js diff --git a/src/data/books.js b/src/data/books.js index 4b5e44d9..0db73657 100644 --- a/src/data/books.js +++ b/src/data/books.js @@ -1,8 +1,53 @@ -const all = () => {}; -const getById = (id) => {}; -const create = (book) => {}; -const update = (book) => {}; -const remove = (book) => {}; +const db = require("./db.js"); + +const all = async () => { + const result = await db.query("SELECT * FROM books"); + return result.rows; +}; + +const getById = async (id) => { + const result = await db.query("SELECT * FROM books WHERE id = $1", [id]); + return result.rows[0]; +}; + +const create = async (book) => { + const result = await db.execute( + "INSERT INTO books (title, type, author, topic, publication_date, pages) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *", + [ + book.title, + book.type, + book.author, + book.topic, + book.publication_date, + book.pages, + ] + ); + return result.rows[0]; +}; + +const update = async (id, updates) => { + const result = await db.execute( + "UPDATE books SET title = $1, type = $2, author = $3, topic = $4, publication_date = $5, pages = $6 where id = $7 RETURNING *", + [ + updates.title, + updates.type, + updates.author, + updates.topic, + updates.publication_date, + updates.pages, + id, + ] + ); + return result.rows[0]; +}; + +const remove = async (id) => { + const result = await db.execute( + "DELETE FROM books WHERE id = $1 RETURNING *", + [id] + ); + return result.rows[0]; +}; module.exports = { all, diff --git a/src/data/db.js b/src/data/db.js index dd5c3ec6..308f4880 100644 --- a/src/data/db.js +++ b/src/data/db.js @@ -1,15 +1,23 @@ -const { Pool } = require("pg"); - -const { PGHOST, PGDATABASE, PGUSER, PGPASSWORD } = process.env; - -const db = new Pool({ - host: PGHOST, - database: PGDATABASE, - username: PGUSER, - password: PGPASSWORD, - ssl: { - require: true, - }, -}); +const { Client } = require("pg"); +require('dotenv').config(); + +const { HOST, PORT, DATABASE, USERNAME, PASSWORD, DATABASE_URL } = process.env; + +//const db = new Pool({ + //host: PGHOST, + //database: PGDATABASE, + //username: PGUSER, + //password: PGPASSWORD, +//}); + +const db = new Client(DATABASE_URL); + +const init = async () => { + await db.connect(); +}; +init() + + + module.exports = db; diff --git a/src/data/pets.js b/src/data/pets.js new file mode 100644 index 00000000..e69de29b diff --git a/src/routers/books.js b/src/routers/books.js index 3b29043a..851ceb92 100644 --- a/src/routers/books.js +++ b/src/routers/books.js @@ -1,96 +1,45 @@ const express = require("express"); const router = express.Router(); -const db = require("../../db"); -const db_books = require("../data/books"); +const db = require("../data/books.js"); -router.get("/", async (req, res) => {}); - -module.exports = router; - -const all = (req, res) => { - const books = db_books.all(); +router.get("/", async (req, res) => { + const books = await db.all(); res.status(200).json({ books: books }); -}; +}); -const get = (req, res) => { +router.get("/:id", async (req, res) => { const id = Number(req.params.id); - const found = db_books.getById(id); - - if (!found) { - res.status(404).send({ error: "A book the provided ID does not exist" }); - throw new NotFoundError("A book the provided ID does not exist"); - } - - res.status(200).json({ book: found }); -}; + const book = await db.getById(id); + res.status(200).json({ book: book }); +}); -const create = (req, res) => { +router.post("/", async (req, res) => { const newBook = req.body; if (!newBook.title || !newBook.author || !newBook.type) { res.status(400).send({ error: `Missing fields in request body` }); - throw new MissingFieldError(`Missing fields in request body`); } - if (books.find((book) => book.title === newBook.title)) { - res - .status(409) - .send({ error: `A book with the provided title already exists` }); - throw new MissingFieldError( - `A book with the provided title already exists` - ); - } - newBook.id = bookID; - books.push(newBook); - bookID++; - res.status(201).json({ book: newBook }); -}; + const book = await db.create(newBook); + res.status(201).json({ book: book }); +}); -const update = (req, res) => { +router.put("/:id", async (req, res) => { const id = Number(req.params.id); const updates = req.body; if (!updates.title || !updates.author || !updates.type) { res.status(400).send({ error: `Missing fields in request body` }); - throw new MissingFieldError(`Missing fields in the request body`); - } - - const found = books.find((book) => book.id === id); - if (!found) { - res.status(404).send({ error: `A book the provided ID does not exist` }); - throw new NotFoundError(`A book with the provided ID does not exist`); - } - - if (books.find((book) => book.title === updates.title)) { - res - .status(409) - .send({ error: `A book with the provided title already exists` }); - throw new MissingFieldError( - `A book with the provided title already exists` - ); } const index = books.indexOf(found); const updated = { ...found, ...updates }; res.status(200).json({ book: updated }); -}; +}); -const remove = (req, res) => { +router.delete("/:id", async (req, res) => { const id = Number(req.params.id); - const found = books.find((book) => book.id === id); - if (!found) { - res.status(404).send({ error: `A book the provided ID does not exist` }); - throw new NotFoundError(`Book with the provided ID does not exist`); - } - - const index = books.indexOf(found); - books.splice(index, 1); + const result = await db.remove(id); res.status(200).json({ book: found }); -}; +}); -module.exports = { - all, - get, - create, - update, - remove, -}; \ No newline at end of file +module.exports = router; diff --git a/src/server.js b/src/server.js index dac55e5d..8109417b 100644 --- a/src/server.js +++ b/src/server.js @@ -1,6 +1,7 @@ const express = require("express"); const morgan = require("morgan"); const cors = require("cors"); +require('dotenv').config(); const app = express(); From 972f4616dfb0c8c74d47349bf2e16720f65ead7a Mon Sep 17 00:00:00 2001 From: JOANNABUUMA1 Date: Wed, 26 Jun 2024 18:12:12 +0100 Subject: [PATCH 4/6] pet repo creation --- src/data/pets.js | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/data/pets.js b/src/data/pets.js index e69de29b..4f454b9d 100644 --- a/src/data/pets.js +++ b/src/data/pets.js @@ -0,0 +1,49 @@ +const db = require("./db.js"); + +const all = async () => { + const result = await db.query("SELECT * FROM pets"); + return result.rows; +}; + +const getById = async (id) => { + const result = await db.query("SELECT * FROM pets WHERE id = $1", [id]); + return result.rows[0]; +}; + +const create = async (pet) => { + const result = await db.query( + "INSERT INTO pets (name, age, type, breed, has_microchip) VALUES ($1, $2, $3, $4, $5) RETURNING *", + [pet.name, pet.age, pet.type, pet.breed, pet.has_microchip] + ); + return result.rows[0]; +}; + +const update = async (id, updates) => { + const result = await db.query( + "UPDATE pets SET name = $1, age = $2, type = $3, breed = $4, has_microchip = $5 where id = $6 RETURNING *", + [ + updates.name, + updates.age, + updates.type, + updates.breed, + updates.has_microchip, + id, + ] + ); + return result.rows[0]; +}; + +const remove = async (id) => { + const result = await db.query("DELETE FROM pets WHERE id = $1 RETURNING *", [ + id, + ]); + return result.rows[0]; +}; + +module.exports = { + all, + getById, + create, + update, + remove, +}; From 13b3702fd1c245cebb4e814283fa179166b236ea Mon Sep 17 00:00:00 2001 From: JOANNABUUMA1 Date: Wed, 26 Jun 2024 18:29:13 +0100 Subject: [PATCH 5/6] pets router creation --- src/data/books.js | 1 + src/routers/pets.js | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/server.js | 2 ++ 3 files changed, 48 insertions(+) create mode 100644 src/routers/pets.js diff --git a/src/data/books.js b/src/data/books.js index 0db73657..fac46fdc 100644 --- a/src/data/books.js +++ b/src/data/books.js @@ -1,5 +1,6 @@ const db = require("./db.js"); + const all = async () => { const result = await db.query("SELECT * FROM books"); return result.rows; diff --git a/src/routers/pets.js b/src/routers/pets.js new file mode 100644 index 00000000..4f24bb07 --- /dev/null +++ b/src/routers/pets.js @@ -0,0 +1,45 @@ +const express = require("express"); +const router = express.Router(); +const db = require("../data/pets.js"); + +router.get("/", async (req, res) => { + const pets = await db.all(); + res.status(200).json({ pets: pets }); +}); + +router.get("/:id", async (req, res) => { + const id = Number(req.params.id); + const pet = await db.getById(id); + res.status(200).json({ pet: pet }); +}); + +router.post("/", async (req, res) => { + const newBook = req.body; + if (!newBook.title || !newBook.author || !newBook.type) { + res.status(400).send({ error: `Missing fields in request body` }); + } + + const pet = await db.create(newBook); + res.status(201).json({ pet: pet }); +}); + +router.put("/:id", async (req, res) => { + const id = Number(req.params.id); + const updates = req.body; + + if (!updates.title || !updates.author || !updates.type) { + res.status(400).send({ error: `Missing fields in request body` }); + } + + const index = pets.indexOf(found); + const updated = { ...found, ...updates }; + res.status(200).json({ pet: updated }); +}); + +router.delete("/:id", async (req, res) => { + const id = Number(req.params.id); + const result = await db.remove(id); + res.status(200).json({ pet: found }); +}); + +module.exports = router; diff --git a/src/server.js b/src/server.js index 8109417b..a652c970 100644 --- a/src/server.js +++ b/src/server.js @@ -11,7 +11,9 @@ app.use(express.json()); //TODO: Implement books and pets APIs using Express Modular Routers const booksRouter = require('./routers/books.js') +const petsRouter = require('./routers/pets.js') app.use('/books', booksRouter) +app.use('/pets', petsRouter) module.exports = app From 8a318d6196bf13079832f17054797974ea2097b9 Mon Sep 17 00:00:00 2001 From: JOANNABUUMA1 Date: Wed, 26 Jun 2024 18:51:45 +0100 Subject: [PATCH 6/6] core complete --- db/index.js | 2 +- src/data/books.js | 8 ++++---- src/routers/books.js | 9 +++++---- src/routers/pets.js | 29 +++++++++++++++++++++-------- src/server.js | 1 - 5 files changed, 31 insertions(+), 18 deletions(-) diff --git a/db/index.js b/db/index.js index af723442..be94a422 100644 --- a/db/index.js +++ b/db/index.js @@ -11,7 +11,7 @@ const client = { // on the contents of our env file // Create a new connection to the database using the Client // object provided by the postgres node module - const dbClient = new Client(process.env.PGURL) + const dbClient = new Client(process.env.DATABASE_URL) // connect a connection await dbClient.connect() // execute the query diff --git a/src/data/books.js b/src/data/books.js index fac46fdc..e1f6ea27 100644 --- a/src/data/books.js +++ b/src/data/books.js @@ -12,7 +12,7 @@ const getById = async (id) => { }; const create = async (book) => { - const result = await db.execute( + const result = await db.query( "INSERT INTO books (title, type, author, topic, publication_date, pages) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *", [ book.title, @@ -27,10 +27,10 @@ const create = async (book) => { }; const update = async (id, updates) => { - const result = await db.execute( + const result = await db.query( "UPDATE books SET title = $1, type = $2, author = $3, topic = $4, publication_date = $5, pages = $6 where id = $7 RETURNING *", [ - updates.title, + updates.name, updates.type, updates.author, updates.topic, @@ -43,7 +43,7 @@ const update = async (id, updates) => { }; const remove = async (id) => { - const result = await db.execute( + const result = await db.query( "DELETE FROM books WHERE id = $1 RETURNING *", [id] ); diff --git a/src/routers/books.js b/src/routers/books.js index 851ceb92..6d38371c 100644 --- a/src/routers/books.js +++ b/src/routers/books.js @@ -17,6 +17,7 @@ router.post("/", async (req, res) => { const newBook = req.body; if (!newBook.title || !newBook.author || !newBook.type) { res.status(400).send({ error: `Missing fields in request body` }); + return; } const book = await db.create(newBook); @@ -29,17 +30,17 @@ router.put("/:id", async (req, res) => { if (!updates.title || !updates.author || !updates.type) { res.status(400).send({ error: `Missing fields in request body` }); + return; } - const index = books.indexOf(found); - const updated = { ...found, ...updates }; - res.status(200).json({ book: updated }); + const updated = db.update(updates); + res.status(201).json({ book: updated }); }); router.delete("/:id", async (req, res) => { const id = Number(req.params.id); const result = await db.remove(id); - res.status(200).json({ book: found }); + res.status(201).json({ book: result }); }); module.exports = router; diff --git a/src/routers/pets.js b/src/routers/pets.js index 4f24bb07..23a76232 100644 --- a/src/routers/pets.js +++ b/src/routers/pets.js @@ -14,12 +14,19 @@ router.get("/:id", async (req, res) => { }); router.post("/", async (req, res) => { - const newBook = req.body; - if (!newBook.title || !newBook.author || !newBook.type) { + const newPet = req.body; + if ( + !newPet.name || + !newPet.age || + !newPet.type || + !newPet.breed || + !newPet.has_microchip + ) { res.status(400).send({ error: `Missing fields in request body` }); + return; } - const pet = await db.create(newBook); + const pet = await db.create(newPet); res.status(201).json({ pet: pet }); }); @@ -27,19 +34,25 @@ router.put("/:id", async (req, res) => { const id = Number(req.params.id); const updates = req.body; - if (!updates.title || !updates.author || !updates.type) { + if ( + !updates.name || + !updates.age || + !updates.type || + !updates.breed || + !updates.has_microchip + ) { res.status(400).send({ error: `Missing fields in request body` }); + return; } - const index = pets.indexOf(found); - const updated = { ...found, ...updates }; - res.status(200).json({ pet: updated }); + const updated = db.update(updates); + res.status(201).json({ pet: updated }); }); router.delete("/:id", async (req, res) => { const id = Number(req.params.id); const result = await db.remove(id); - res.status(200).json({ pet: found }); + res.status(201).json({ pet: result }); }); module.exports = router; diff --git a/src/server.js b/src/server.js index a652c970..233ceb88 100644 --- a/src/server.js +++ b/src/server.js @@ -1,7 +1,6 @@ const express = require("express"); const morgan = require("morgan"); const cors = require("cors"); -require('dotenv').config(); const app = express();