diff --git a/api/cars/cars-middleware.js b/api/cars/cars-middleware.js
index 7e738d6062..3184723343 100644
--- a/api/cars/cars-middleware.js
+++ b/api/cars/cars-middleware.js
@@ -1,15 +1,72 @@
-const checkCarId = (req, res, next) => {
- // DO YOUR MAGIC
+const Cars = require('./cars-model')
+const db = require('../../data/db-config')
+const vinValidator = require('vin-validator')
+const yup = require('yup')
+
+const checkCarId = async (req, res, next) => {
+ try {
+ const carIdCheck = await Cars.getById(req.params.id)
+ if (carIdCheck) {
+ req.car = carIdCheck
+ next()
+ } else {
+ res.status(404).json({
+ message: `car with id ${req.params.id} is not found`
+ })
+ }
+ } catch (err) {
+ next(err)
+ }
}
-const checkCarPayload = (req, res, next) => {
- // DO YOUR MAGIC
+const chechCarPayloadSchema = yup.object().shape({
+ vin: yup.string().required('vin is missing'),
+ make: yup.string().required('make is missing'),
+ model: yup.string().required('model is missing'),
+ mileage: yup.number().required('mileage is missing'),
+ title: yup.string(),
+ transmission: yup.string()
+})
+
+const checkCarPayload = async (req, res, next) => {
+ try {
+ const payloadValidation = await chechCarPayloadSchema.validate(
+ req.body,
+ { strict: false, stripUnknown: true }
+ )
+ req.body = payloadValidation
+ next()
+ } catch (err) {
+ res.status(400).json({
+ message: err.message
+ })
+ }
}
const checkVinNumberValid = (req, res, next) => {
- // DO YOUR MAGIC
+ next()
+}
+
+const checkVinNumberUnique = async (req, res, next) => {
+ try {
+ const exisiting = await db('cars')
+ .where('vin', req.body.vin)
+ .first()
+ if (!exisiting) {
+ next()
+ } else {
+ res.status(400).json({
+ message: `vin ${req.body.vin} already exists`
+ })
+ }
+ } catch (err) {
+ next(err)
+ }
}
-const checkVinNumberUnique = (req, res, next) => {
- // DO YOUR MAGIC
+module.exports = {
+ checkCarId,
+ checkCarPayload,
+ checkVinNumberValid,
+ checkVinNumberUnique,
}
diff --git a/api/cars/cars-model.js b/api/cars/cars-model.js
index 39b2c50a8d..e2561f05c5 100644
--- a/api/cars/cars-model.js
+++ b/api/cars/cars-model.js
@@ -1,11 +1,25 @@
+
+const db = require('../../data/db-config')
+
const getAll = () => {
- // DO YOUR MAGIC
+ return db('cars')
}
-const getById = () => {
- // DO YOUR MAGIC
+const getById = (id) => {
+ return db('cars')
+ .where('id', id)
+ .first()
}
-const create = () => {
- // DO YOUR MAGIC
+const create = (car) => {
+ return db('cars').insert(car)
+ .then(([id]) => {
+ return getById(id)
+ })
}
+
+module.exports = {
+ getAll,
+ getById,
+ create,
+}
\ No newline at end of file
diff --git a/api/cars/cars-router.js b/api/cars/cars-router.js
index 3fca0e7d7d..ebf6682d4d 100644
--- a/api/cars/cars-router.js
+++ b/api/cars/cars-router.js
@@ -1 +1,35 @@
-// DO YOUR MAGIC
+const router = require('express').Router()
+const Cars = require('./cars-model')
+const { checkCarId,
+ checkCarPayload,
+ checkVinNumberValid,
+ checkVinNumberUnique,
+} = require('./cars-middleware')
+
+router.get('/', async (req, res, next) => {
+ try {
+ const cars = await Cars.getAll()
+ res.json(cars)
+ } catch (err) {
+ next(err)
+ }
+})
+
+router.get('/:id', checkCarId, async (req, res) => {
+ res.status(200).json(req.car)
+})
+
+router.post('/',
+checkCarPayload,
+checkVinNumberValid,
+checkVinNumberUnique,
+async (req, res, next) => {
+ try {
+ const newCar = await Cars.create(req.body)
+ res.json(newCar)
+ } catch (err) {
+ next(err)
+ }
+})
+
+module.exports = router
\ No newline at end of file
diff --git a/api/server.js b/api/server.js
index c5a0be1b41..64fe434f5f 100644
--- a/api/server.js
+++ b/api/server.js
@@ -1,7 +1,14 @@
const express = require("express")
-
+const CarRouter = require('./cars/cars-router');
const server = express()
-// DO YOUR MAGIC
+server.use(express.json());
+server.use('/api/cars', CarRouter);
+
+server.get('/', (req, res) => {
+ res.send(`
CARS
`)
+});
+
+
-module.exports = server
+module.exports = server
\ No newline at end of file
diff --git a/data/dealer.db3 b/data/dealer.db3
new file mode 100644
index 0000000000..c4ca72f96d
Binary files /dev/null and b/data/dealer.db3 differ
diff --git a/data/migrations/01-make_cars_table.js b/data/migrations/01-make_cars_table.js
index 9723c175be..3adfbc20f3 100644
--- a/data/migrations/01-make_cars_table.js
+++ b/data/migrations/01-make_cars_table.js
@@ -1,7 +1,17 @@
exports.up = function (knex) {
// DO YOUR MAGIC
+ return knex.schema.createTable('cars', tbl => {
+ tbl.increments();
+ tbl.string('vin').unique().notNullable();
+ tbl.string('make').notNullable();
+ tbl.string('model').notNullable();
+ tbl.integer('mileage').notNullable();
+ tbl.string('title');
+ tbl.string('transmission');
+ })
};
exports.down = function (knex) {
// DO YOUR MAGIC
+ return knex.schema.dropTableIfExists('cars');
};
diff --git a/package-lock.json b/package-lock.json
index 4db3b8fc7b..8c42c45b87 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,12 +5,13 @@
"requires": true,
"packages": {
"": {
- "name": "node-db2-project",
"version": "1.0.0",
"dependencies": {
"express": "^4.17.1",
"knex": "^0.95.11",
- "sqlite3": "^5.0.2"
+ "sqlite3": "^5.0.2",
+ "vin-validator": "^1.0.0",
+ "yup": "^0.32.11"
},
"devDependencies": {
"@types/jest": "^27.0.1",
@@ -566,6 +567,17 @@
"@babel/core": "^7.0.0-0"
}
},
+ "node_modules/@babel/runtime": {
+ "version": "7.15.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz",
+ "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==",
+ "dependencies": {
+ "regenerator-runtime": "^0.13.4"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/template": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz",
@@ -1101,6 +1113,11 @@
"pretty-format": "^27.0.0"
}
},
+ "node_modules/@types/lodash": {
+ "version": "4.14.175",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.175.tgz",
+ "integrity": "sha512-XmdEOrKQ8a1Y/yxQFOMbC47G/V2VDO1GvMRnl4O75M4GW/abC5tnfzadQYkqEveqRM1dEJGFFegfPNA2vvx2iw=="
+ },
"node_modules/@types/node": {
"version": "16.7.13",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.13.tgz",
@@ -5577,6 +5594,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
+ "node_modules/lodash-es": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
+ },
"node_modules/lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
@@ -5825,6 +5847,11 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
+ "node_modules/nanoclone": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz",
+ "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA=="
+ },
"node_modules/nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -6806,6 +6833,11 @@
"node": ">= 6"
}
},
+ "node_modules/property-expr": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.4.tgz",
+ "integrity": "sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg=="
+ },
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -7006,6 +7038,11 @@
"node": ">= 0.10"
}
},
+ "node_modules/regenerator-runtime": {
+ "version": "0.13.9",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
+ "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
+ },
"node_modules/regex-not": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
@@ -8727,6 +8764,11 @@
"node": ">=0.6"
}
},
+ "node_modules/toposort": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
+ "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA="
+ },
"node_modules/touch": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
@@ -9144,6 +9186,11 @@
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"optional": true
},
+ "node_modules/vin-validator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/vin-validator/-/vin-validator-1.0.0.tgz",
+ "integrity": "sha1-F2Via4VYskAvd7bCXHYX9zzsrmc="
+ },
"node_modules/w3c-hr-time": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
@@ -9468,6 +9515,23 @@
"engines": {
"node": ">=8"
}
+ },
+ "node_modules/yup": {
+ "version": "0.32.11",
+ "resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz",
+ "integrity": "sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==",
+ "dependencies": {
+ "@babel/runtime": "^7.15.4",
+ "@types/lodash": "^4.14.175",
+ "lodash": "^4.17.21",
+ "lodash-es": "^4.17.21",
+ "nanoclone": "^0.2.1",
+ "property-expr": "^2.0.4",
+ "toposort": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
}
},
"dependencies": {
@@ -9885,6 +9949,14 @@
"@babel/helper-plugin-utils": "^7.14.5"
}
},
+ "@babel/runtime": {
+ "version": "7.15.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz",
+ "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==",
+ "requires": {
+ "regenerator-runtime": "^0.13.4"
+ }
+ },
"@babel/template": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz",
@@ -10343,6 +10415,11 @@
"pretty-format": "^27.0.0"
}
},
+ "@types/lodash": {
+ "version": "4.14.175",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.175.tgz",
+ "integrity": "sha512-XmdEOrKQ8a1Y/yxQFOMbC47G/V2VDO1GvMRnl4O75M4GW/abC5tnfzadQYkqEveqRM1dEJGFFegfPNA2vvx2iw=="
+ },
"@types/node": {
"version": "16.7.13",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.13.tgz",
@@ -13861,6 +13938,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
+ "lodash-es": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
+ },
"lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
@@ -14056,6 +14138,11 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
+ "nanoclone": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz",
+ "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA=="
+ },
"nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -14810,6 +14897,11 @@
"sisteransi": "^1.0.5"
}
},
+ "property-expr": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.4.tgz",
+ "integrity": "sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg=="
+ },
"proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -14971,6 +15063,11 @@
"resolve": "^1.9.0"
}
},
+ "regenerator-runtime": {
+ "version": "0.13.9",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
+ "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
+ },
"regex-not": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
@@ -16337,6 +16434,11 @@
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
},
+ "toposort": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
+ "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA="
+ },
"touch": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
@@ -16676,6 +16778,11 @@
}
}
},
+ "vin-validator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/vin-validator/-/vin-validator-1.0.0.tgz",
+ "integrity": "sha1-F2Via4VYskAvd7bCXHYX9zzsrmc="
+ },
"w3c-hr-time": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
@@ -16941,6 +17048,20 @@
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
+ },
+ "yup": {
+ "version": "0.32.11",
+ "resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz",
+ "integrity": "sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==",
+ "requires": {
+ "@babel/runtime": "^7.15.4",
+ "@types/lodash": "^4.14.175",
+ "lodash": "^4.17.21",
+ "lodash-es": "^4.17.21",
+ "nanoclone": "^0.2.1",
+ "property-expr": "^2.0.4",
+ "toposort": "^2.0.2"
+ }
}
}
}
diff --git a/package.json b/package.json
index 09c4d0ea1e..58dc4383e1 100644
--- a/package.json
+++ b/package.json
@@ -17,7 +17,9 @@
"dependencies": {
"express": "^4.17.1",
"knex": "^0.95.11",
- "sqlite3": "^5.0.2"
+ "sqlite3": "^5.0.2",
+ "vin-validator": "^1.0.0",
+ "yup": "^0.32.11"
},
"repository": {
"type": "git",