From 925a927906dcb69120ba9016aafe85cb71d72991 Mon Sep 17 00:00:00 2001 From: Thomas Jensen Date: Wed, 31 Jul 2024 15:10:11 +0200 Subject: [PATCH 1/2] Completed core (except DELETE) --- package-lock.json | 62 +++++++++++++++++++++++++++++------------------ src/server.js | 60 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 93 insertions(+), 29 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3fb12fd..2733919 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1410,12 +1410,13 @@ } }, "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==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -1423,7 +1424,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -1442,11 +1443,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==", + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1503,6 +1505,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -1719,6 +1722,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1730,9 +1734,10 @@ "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==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2032,16 +2037,17 @@ } }, "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==", + "license": "MIT", "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", @@ -2094,9 +2100,10 @@ } }, "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==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2412,6 +2419,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -2545,6 +2553,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -3432,6 +3441,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4013,9 +4023,10 @@ } }, "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==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -4121,7 +4132,8 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/semver": { "version": "6.3.1", @@ -4562,6 +4574,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -4613,6 +4626,7 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" diff --git a/src/server.js b/src/server.js index 30f0ce3..4d4adff 100644 --- a/src/server.js +++ b/src/server.js @@ -1,13 +1,63 @@ -const express = require("express") -const morgan = require("morgan") -const cors = require("cors") +const express = require('express') +const morgan = require('morgan') +const cors = require('cors') +const contacts = require('../data/contacts') + const app = express() -app.use(morgan("dev")) +app.use(morgan('dev')) app.use(cors()) app.use(express.json()) -// write your app code here +app.get('/contacts', (req, res) => { + res.status(200).json({ contacts: contacts }) +}) + +app.get('/contacts/:id', (req, res) => { + const id = parseInt(req.params.id) + + const contact = contacts.find((contact) => { + return contact.id === id + }) + + res.status(200).json({ contact: contact }) +}) + +let nextContactId = 3 + +app.post('/contacts', (req, res) => { + const contact = req.body + contact.id = nextContactId + + nextContactId++ + + contacts.push(contact) + res.status(201).json({ contact }) +}) + +app.put('/contacts/:id', (req, res) => { + const id = parseInt(req.params.id) + const updatedContact = req.body + + const index = contacts.findIndex((contact) => { + return contact.id === id + }) + + contacts[index] = { + ...updatedContact, + id: id, + } + + res.status(200).json({ contact: contacts[index] }) +}) + +app.delete('/contacts/:id', (req, res) => { + const id = parseInt(req.params.id) + + const deletedContact = contacts.find((contact) => contact.id === id) + contacts = contacts.filter((contact) => contact.id !== id) + res.status(200).json({ contact: deletedContact }) +}) module.exports = app From 3d7f541dde0166afeb820e638b8b56a2ae956570 Mon Sep 17 00:00:00 2001 From: Thomas Jensen Date: Sun, 4 Aug 2024 14:59:58 +0200 Subject: [PATCH 2/2] Completed Core --- src/server.js | 4 +- test/api/standard/contacts.spec.js | 204 ++++++++++++++--------------- 2 files changed, 101 insertions(+), 107 deletions(-) diff --git a/src/server.js b/src/server.js index 4d4adff..02e601b 100644 --- a/src/server.js +++ b/src/server.js @@ -54,8 +54,8 @@ app.put('/contacts/:id', (req, res) => { app.delete('/contacts/:id', (req, res) => { const id = parseInt(req.params.id) - const deletedContact = contacts.find((contact) => contact.id === id) - contacts = contacts.filter((contact) => contact.id !== id) + const contactIndex = contacts.findIndex((contact) => contact.id === id) + const [deletedContact] = contacts.splice(contactIndex, 1) res.status(200).json({ contact: deletedContact }) }) diff --git a/test/api/standard/contacts.spec.js b/test/api/standard/contacts.spec.js index 4c430a8..5f246bc 100644 --- a/test/api/standard/contacts.spec.js +++ b/test/api/standard/contacts.spec.js @@ -1,135 +1,129 @@ const supertest = require('supertest') describe('Address Book API', () => { - let app, createTestFormData, updateTestFormData - - beforeEach(() => { - app = require('../../../src/server.js') - createTestFormData = require('../../fixtures/contacts/createTestFormData.js') - updateTestFormData = require('../../fixtures/contacts/updateTestFormData.js') - }) - - describe('GET /contacts', () => { - it('returns default contacts', async () => { - const response = await supertest(app).get('/contacts') - - expect(response.status).toEqual(200) - expect(response.body.contacts).not.toEqual(undefined) - expect(response.body.contacts.length).toEqual(2) - - const [contact1, contact2] = response.body.contacts - expect(contact1.firstName).toEqual("John") - expect(contact1.lastName).toEqual("Carmack") - expect(contact2.firstName).toEqual("Grace") - expect(contact2.lastName).toEqual("Hopper") + let app, createTestFormData, updateTestFormData + + beforeEach(() => { + app = require('../../../src/server.js') + createTestFormData = require('../../fixtures/contacts/createTestFormData.js') + updateTestFormData = require('../../fixtures/contacts/updateTestFormData.js') }) - }) - describe('GET /contacts/:id', () => { - it('returns contact, id 2', async () => { - const response = await supertest(app).get('/contacts/2') + describe('GET /contacts', () => { + it('returns default contacts', async () => { + const response = await supertest(app).get('/contacts') - expect(response.status).toEqual(200) - expect(response.body.contact).not.toEqual(undefined) + expect(response.status).toEqual(200) + expect(response.body.contacts).not.toEqual(undefined) + expect(response.body.contacts.length).toEqual(2) - const contact = response.body.contact - expect(contact.id).toEqual(2) - expect(contact.firstName).toEqual("Grace") - expect(contact.lastName).toEqual("Hopper") + const [contact1, contact2] = response.body.contacts + expect(contact1.firstName).toEqual('John') + expect(contact1.lastName).toEqual('Carmack') + expect(contact2.firstName).toEqual('Grace') + expect(contact2.lastName).toEqual('Hopper') + }) }) - }) - describe('POST /contacts', () => { - it('returns created contact', async () => { - const response = await supertest(app) - .post('/contacts') - .send(createTestFormData) + describe('GET /contacts/:id', () => { + it('returns contact, id 2', async () => { + const response = await supertest(app).get('/contacts/2') - expect(response.status).toEqual(201) - expect(response.body.contact).not.toEqual(undefined) + expect(response.status).toEqual(200) + expect(response.body.contact).not.toEqual(undefined) - const contact = response.body.contact - expect(contact.id).toEqual(3) - expect(contact.firstName).toEqual(createTestFormData.firstName) - expect(contact.lastName).toEqual(createTestFormData.lastName) + const contact = response.body.contact + expect(contact.id).toEqual(2) + expect(contact.firstName).toEqual('Grace') + expect(contact.lastName).toEqual('Hopper') + }) }) - it('adds contact to data store', async () => { - await supertest(app) - .post('/contacts') - .send(createTestFormData) + describe('POST /contacts', () => { + it('returns created contact', async () => { + const response = await supertest(app) + .post('/contacts') + .send(createTestFormData) - const response = await supertest(app).get('/contacts') + expect(response.status).toEqual(201) + expect(response.body.contact).not.toEqual(undefined) - expect(response.status).toEqual(200) - expect(response.body.contacts).not.toEqual(undefined) - expect(response.body.contacts.length).toEqual(3) + const contact = response.body.contact + expect(contact.id).toEqual(3) + expect(contact.firstName).toEqual(createTestFormData.firstName) + expect(contact.lastName).toEqual(createTestFormData.lastName) + }) - const [contact1, contact2, contact3] = response.body.contacts - expect(contact3.firstName).toEqual(createTestFormData.firstName) - expect(contact3.lastName).toEqual(createTestFormData.lastName) - }) - }) + it('adds contact to data store', async () => { + await supertest(app).post('/contacts').send(createTestFormData) - describe('PUT /contacts', () => { - let updatedContact - beforeEach(() => { - updatedContact = { - ...updateTestFormData, - id: 1 - } - }) - it('returns updated contact', async () => { - const response = await supertest(app) - .put(`/contacts/1`) - .send(updateTestFormData) + const response = await supertest(app).get('/contacts') - expect(response.status).toEqual(200) - expect(response.body.contact).not.toEqual(undefined) + expect(response.status).toEqual(200) + expect(response.body.contacts).not.toEqual(undefined) + expect(response.body.contacts.length).toEqual(3) - const contact = response.body.contact - expect(contact).toMatchObject(updatedContact) + const [contact1, contact2, contact3] = response.body.contacts + expect(contact3.firstName).toEqual(createTestFormData.firstName) + expect(contact3.lastName).toEqual(createTestFormData.lastName) + }) }) - it('updated contact is in data store', async () => { - await supertest(app) - .put(`/contacts/1`) - .send(updateTestFormData) - - const response = await supertest(app).get('/contacts') - - expect(response.status).toEqual(200) - expect(response.body.contacts).not.toEqual(undefined) - expect(response.body.contacts.length).toEqual(2) - - const [contact1, contact2] = response.body.contacts - expect(contact1.firstName).toEqual(updatedContact.firstName) - expect(contact1.lastName).toEqual(updatedContact.lastName) + describe('PUT /contacts', () => { + let updatedContact + beforeEach(() => { + updatedContact = { + ...updateTestFormData, + id: 1, + } + }) + it('returns updated contact', async () => { + const response = await supertest(app) + .put(`/contacts/1`) + .send(updateTestFormData) + + expect(response.status).toEqual(200) + expect(response.body.contact).not.toEqual(undefined) + + const contact = response.body.contact + expect(contact).toMatchObject(updatedContact) + }) + + it('updated contact is in data store', async () => { + await supertest(app).put(`/contacts/1`).send(updateTestFormData) + + const response = await supertest(app).get('/contacts') + + expect(response.status).toEqual(200) + expect(response.body.contacts).not.toEqual(undefined) + expect(response.body.contacts.length).toEqual(2) + + const [contact1, contact2] = response.body.contacts + expect(contact1.firstName).toEqual(updatedContact.firstName) + expect(contact1.lastName).toEqual(updatedContact.lastName) + }) }) - }) - describe('DELETE /contacts', () => { - it('returns deleted contact', async () => { - const response = await supertest(app) - .delete(`/contacts/1`) + describe('DELETE /contacts', () => { + it('returns deleted contact', async () => { + const response = await supertest(app).delete(`/contacts/1`) - expect(response.status).toEqual(200) - expect(response.body.contact).not.toEqual(undefined) - expect(response.body.contact.id).toEqual(1) - }) + expect(response.status).toEqual(200) + expect(response.body.contact).not.toEqual(undefined) + expect(response.body.contact.id).toEqual(1) + }) - it('removes contact from data store', async () => { - const response = await supertest(app) - .delete(`/contacts/1`) + it('removes contact from data store', async () => { + const response = await supertest(app).delete(`/contacts/1`) - const deletedContact = response.body.contact + const deletedContact = response.body.contact - const response2 = await supertest(app).get('/contacts') + const response2 = await supertest(app).get('/contacts') - expect(response2.status).toEqual(200) - expect(response2.body.contacts).not.toEqual(undefined) - expect(response2.body.contacts.length).toEqual(1) - expect(response2.body.contacts).not.toContain(deletedContact) + expect(response2.status).toEqual(200) + expect(response2.body.contacts).not.toEqual(undefined) + expect(response2.body.contacts.length).toEqual(1) + expect(response2.body.contacts).not.toContain(deletedContact) + }) }) - }) })