diff --git a/.gitignore b/.gitignore index 40b878d..600d3b6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -node_modules/ \ No newline at end of file +node_modules/ + +config.js diff --git a/fetches.js b/fetches.js index 7fc1f6b..39aaaa9 100644 --- a/fetches.js +++ b/fetches.js @@ -3,7 +3,7 @@ const fetchPromise = fetch('https://kiwipanel-gravitycrater-3000.codio-box.uk/ap headers: { 'Content-type': 'application/json' }, - body: JSON.stringify({title: "test", fullText: 'Textual content'}) + body: JSON.stringify({title: "test", allText: 'Textual content'}) }); fetchPromise.then(res => res.json()).then(res => console.log(res)) diff --git a/helpers/database.js b/helpers/database.js new file mode 100644 index 0000000..0e4e530 --- /dev/null +++ b/helpers/database.js @@ -0,0 +1,19 @@ +const mysql = require('promise-mysql'); +const info = require('../config'); + +// define an async utility function to get a connection +// run an SQL query then end the connection +exports.run_query = async function run_query(query, values) { + try { + const connection = await mysql.createConnection(info.config); + let data = await connection.query(query, values); + await connection.end(); + return data; + } catch (error) { + // Don't let the actual error propagate up to the response object + // as it may contain sensitive server information. + // Instead log it somehow and throw a generic error. + console.error(error, query, values); + throw 'Database query error' + } +} diff --git a/index.js b/index.js index 93c47d7..18ec9af 100644 --- a/index.js +++ b/index.js @@ -1,30 +1,13 @@ -// My blog API -// Set up the application and its router +const Koa = require('koa'); -const Koa = require('koa'); -const Router = require('koa-router'); -const app = new Koa(); -const router = new Router(); - -/* -* Define route handler(s): -* -* This means we connect HTTP methods: GET, POST, ... -* and URI paths: /some/uri/path -* to JavaScript functions that handle the request. -* -* Once defined we then add them to the app object. -*/ - -router.get('/api/v1', welcomeAPI); -app.use(router.routes()); // Define the actual handler functions - -function welcomeAPI(ctx, next) { - ctx.body = { message: "Welcome to the blog API!" } -} +const app = new Koa(); +const special = require('./routes/special.js') const articles = require('./routes/articles.js'); + +app.use(special.routes()); app.use(articles.routes()); -// Finally, run the app as a process on a given port -app.listen(3000); \ No newline at end of file +let port = process.env.PORT || 3000; + +app.listen(port); diff --git a/models/articleViews.js b/models/articleViews.js new file mode 100644 index 0000000..48c3eba --- /dev/null +++ b/models/articleViews.js @@ -0,0 +1,32 @@ +const db = require('../helpers/database'); + +// update views of an article by its id +exports.updateViews = async function updateViews (id) { + // check if article id exists + let query = "SELECT * FROM articles WHERE ID = ?;"; + let articleExists = await db.run_query(query, id); + console.log(articleExists) + if (articleExists.length == 0) return 404; // article not found + + // check if article was viewed, get number of views + query = "SELECT * FROM articleViews WHERE articleID = ?;"; + let data = await db.run_query(query, id); + + console.log(data) + if (data.length > 0) { // record exists + let query = "UPDATE articleViews SET views = ? WHERE articleID = ?"; + let views = data[0].views + let values = [ views + 1, id ] + let data2 = await db.run_query(query, values); + } + else { + let query = "INSERT INTO articleViews SET ?"; + let values = { "articleID": id, "views": 1 } + let data2 = await db.run_query(query, values); + } + + //let query = ""; + //let values = [id]; + //let data = await db.run_query(query, values); + return data; +} \ No newline at end of file diff --git a/models/articles.js b/models/articles.js new file mode 100644 index 0000000..d0f76c1 --- /dev/null +++ b/models/articles.js @@ -0,0 +1,45 @@ +const db = require('../helpers/database'); +const articleViews = require('./articleViews'); + +//get a single article by its id +exports.getById = async function getById (id) { + let query = "SELECT * FROM articles WHERE ID = ?"; + let values = [id]; + let data = await db.run_query(query, values); + + // update views + await articleViews.updateViews(id); + + return data; +} + +//list all the articles in the database +exports.getAll = async function getAll (page, limit, order) { + // TODO: use page, limit, order to give pagination + let query = "SELECT * FROM articles;"; + let data = await db.run_query(query); + return data; +} + +//create a new article in the database +exports.add = async function add (article) { + let query = "INSERT INTO articles SET ?"; + let data = await db.run_query(query, article); + return data; +} + +//update an article in the database +exports.update = async function update (id, article) { + let query = "UPDATE articles SET ? WHERE ID = ?"; + + let data = await db.run_query(query, [article, id]); + return article; +} + +//delete an article from the database +exports.deleteArticle = async function deleteArticle (id) { + let query = "DELETE FROM articles WHERE id = ?;"; + + let data = await db.run_query(query, id); + return data; +} \ No newline at end of file diff --git a/models/users.js b/models/users.js new file mode 100644 index 0000000..2efdceb --- /dev/null +++ b/models/users.js @@ -0,0 +1 @@ +const db = require('../helpers/database'); diff --git a/package-lock.json b/package-lock.json index aa50118..6dd0d5b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,28 @@ "dependencies": { "koa": "^2.14.1", "koa-bodyparser": "^4.3.0", - "koa-router": "^12.0.0" + "koa-router": "^12.0.0", + "promise-mysql": "^5.2.0" } }, + "node_modules/@types/bluebird": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.38.tgz", + "integrity": "sha512-yR/Kxc0dd4FfwtEoLZMoqJbM/VE/W7hXn/MIjb+axcwag0iFmSPK7OBUZq1YWLynJUoWQkfUrI7T0HDqGApNSg==" + }, + "node_modules/@types/mysql": { + "version": "2.15.21", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.21.tgz", + "integrity": "sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "18.11.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", + "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -26,6 +45,19 @@ "node": ">= 0.6" } }, + "node_modules/bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "engines": { + "node": "*" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -114,6 +146,11 @@ "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", "integrity": "sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==" }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -310,6 +347,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, "node_modules/keygrip": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", @@ -460,6 +502,25 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "dependencies": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mysql/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -505,6 +566,22 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise-mysql": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/promise-mysql/-/promise-mysql-5.2.0.tgz", + "integrity": "sha512-IKkBe7OukgCpy5U5EZPlgH6BRvnngmP+HwD6PoMNzvGXBYVZkiJ5nx6SY7bo+sgwXsMOVE7zQf6CfS9qaFs2pw==", + "dependencies": { + "@types/bluebird": "^3.5.26", + "@types/mysql": "^2.15.2", + "bluebird": "^3.5.1", + "mysql": "^2.18.1" + } + }, "node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", @@ -556,6 +633,25 @@ "node": ">= 0.8" } }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -598,6 +694,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -606,6 +710,19 @@ "node": ">= 0.6" } }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -642,6 +759,11 @@ "node": ">= 0.8" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -660,6 +782,24 @@ } }, "dependencies": { + "@types/bluebird": { + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.38.tgz", + "integrity": "sha512-yR/Kxc0dd4FfwtEoLZMoqJbM/VE/W7hXn/MIjb+axcwag0iFmSPK7OBUZq1YWLynJUoWQkfUrI7T0HDqGApNSg==" + }, + "@types/mysql": { + "version": "2.15.21", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.21.tgz", + "integrity": "sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg==", + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "18.11.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", + "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" + }, "accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -669,6 +809,16 @@ "negotiator": "0.6.3" } }, + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -735,6 +885,11 @@ "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", "integrity": "sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==" }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -873,6 +1028,11 @@ "has-tostringtag": "^1.0.0" } }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, "keygrip": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", @@ -992,6 +1152,24 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "requires": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -1025,6 +1203,22 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "promise-mysql": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/promise-mysql/-/promise-mysql-5.2.0.tgz", + "integrity": "sha512-IKkBe7OukgCpy5U5EZPlgH6BRvnngmP+HwD6PoMNzvGXBYVZkiJ5nx6SY7bo+sgwXsMOVE7zQf6CfS9qaFs2pw==", + "requires": { + "@types/bluebird": "^3.5.26", + "@types/mysql": "^2.15.2", + "bluebird": "^3.5.1", + "mysql": "^2.18.1" + } + }, "qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", @@ -1063,6 +1257,27 @@ } } }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1088,11 +1303,31 @@ "object-inspect": "^1.9.0" } }, + "sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==" + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, "toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -1117,6 +1352,11 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index d5dff37..615cc6c 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "dependencies": { "koa": "^2.14.1", "koa-bodyparser": "^4.3.0", - "koa-router": "^12.0.0" + "koa-router": "^12.0.0", + "promise-mysql": "^5.2.0" } } diff --git a/routes/articles.js b/routes/articles.js index 0dc24e4..3057ad1 100644 --- a/routes/articles.js +++ b/routes/articles.js @@ -1,98 +1,55 @@ -// This file will define the API route handlers for Articles -const Router = require('koa-router'); +const Router = require('koa-router'); +const bodyParser = require('koa-bodyparser'); +const model = require('../models/articles'); -// We are going to parse request bodies so import koa-bodyparser -const bodyParser = require('koa-bodyparser'); - -// Since we are handling articles use a URI that begins with an appropriate path const router = Router({prefix: '/api/v1/articles'}); - -// Temporarily define some random articles in an array. -// Later this will come from the DB. - -let articles = [ - {title:'hello article', fullText:'some text here to fill the body'}, - {title:'another article', fullText:'again here is some text here to fill'}, - {title:'coventry university ', fullText:'some news about coventry university'} -]; - - -// Routes are needed to connect path endpoints to handler functions. -// When an Article id needs to be matched we use a pattern to match -// a named route parameter. Here the name of the parameter will be 'id' -// and we will define the pattern to match at least 1 numeral. - -router.get('/', getAll); -router.post('/', bodyParser(), createArticle); - +router.get('/', getAll); +router.post('/', bodyParser(), createArticle); router.get('/:id([0-9]{1,})', getById); -router.put('/:id([0-9]{1,})', bodyParser(), updateArticle); -router.del('/:id([0-9]{1,})', deleteArticle); - - -// Now we define the handler functions used above. - -function getAll(cnx, next){ - // Use the response body to send the articles as JSON. - cnx.body = articles; -} - -function getById(cnx, next){ - // Get the ID from the route parameters. - let id = cnx.params.id; +router.put('/:id([0-9]{1,})', bodyParser(), updateArticle); +router.del('/:id([0-9]{1,})', deleteArticle); - // If it exists then return the article as JSON. - // Otherwise return a 404 Not Found status code - if ((id < articles.length+1) && (id > 0)) { - cnx.body = articles[id-1]; - } else { - cnx.status = 404; +async function getAll(ctx) { + let articles = await model.getAll(); + if (articles.length) { + ctx.body = articles; } } -function createArticle(cnx, next) { - // The body parser gives us access to the request body on cnx.request.body. - // Use this to extract the title and fullText we were sent. - let {title, fullText} = cnx.request.body; - // In turn, define a new article for addition to the array. - let newArticle = {title:title, fullText:fullText}; - articles.push(newArticle); - // Finally send back appropriate JSON and status code. - // Once we move to a DB store, the newArticle sent back will now have its ID. - cnx.status = 201; - cnx.body = newArticle; -} - -function updateArticle(cnx, next){ - //TODO: edit an article - - // Get the ID from the route parameters. - let id = cnx.params.id; - // get body - let {title, fullText} = cnx.request.body; +async function getById(ctx) { + let id = ctx.params.id; + let article = await model.getById(id); + if (article.length) { + ctx.body = article[0]; + } +} - articles[id - 1].title = title; - articles[id - 1].fullText = fullText; +async function createArticle(ctx) { + const body = ctx.request.body; + let result = await model.add(body); + if (result) { + ctx.status = 201; + ctx.body = {ID: result.insertId} + } +} +async function updateArticle(ctx) { + // TODO edit an existing article + let id = ctx.params.id; + const body = ctx.request.body; - cnx.body = articles; -} + let article = await model.update(id, body) + ctx.body = article; +} -function deleteArticle(cnx, next){ - //TODO: delete an article +async function deleteArticle(ctx) { + // TODO delete an existing article + let id = ctx.params.id; - // Get the ID from the route parameters. - let id = cnx.params.id; - // If it exists then return the article as JSON. - // Otherwise return a 404 Not Found status code - if ((id < articles.length+1) && (id > 0)) { - articles.splice(id - 1, 1) - cnx.body = articles; - } else { - cnx.status = 404; - } -} + let data = await model.deleteArticle(id) + ctx.body = data; +} -// Finally, define the exported object when 'require'd from other scripts. module.exports = router; + diff --git a/routes/special.js b/routes/special.js new file mode 100644 index 0000000..b28d3ea --- /dev/null +++ b/routes/special.js @@ -0,0 +1,14 @@ +const Router = require('koa-router'); +const bodyParser = require('koa-bodyparser'); + +const router = Router({prefix: '/api/v1'}); + +router.get('/', welcomeAPI); + +function welcomeAPI(ctx) { + ctx.body = { + message: 'Welcome to the blog API' + } +} + +module.exports = router; diff --git a/routes/users.js b/routes/users.js new file mode 100644 index 0000000..579514f --- /dev/null +++ b/routes/users.js @@ -0,0 +1,5 @@ +const Router = require('koa-router'); +const bodyParser = require('koa-bodyparser'); +const model = require('../models/users'); + +const router = Router({prefix: '/api/v1/users'});