Queries are working
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
WEB_PORT=3100
|
||||||
|
|
||||||
|
DB_HOSTNAME=127.0.0.1
|
||||||
|
DB_DATABASE=news
|
||||||
|
DB_USERNAME=news
|
||||||
|
DB_PASSWORD=charizard
|
||||||
|
DB_TIMEZONE=Australia/Sydney
|
||||||
|
|
||||||
|
QUERY_LIMIT=10
|
||||||
@@ -1,2 +1,81 @@
|
|||||||
# news-server
|
# news-server
|
||||||
An API centric news server.
|
|
||||||
|
An API centric news server. Uses Sequelize and mariaDB by default.
|
||||||
|
|
||||||
|
# API
|
||||||
|
|
||||||
|
```
|
||||||
|
//NOTE: you can add a "limit" parameter to change the default limit
|
||||||
|
|
||||||
|
//GET get latest news, up to a default limit, or specify the index "id"
|
||||||
|
/news/:id
|
||||||
|
|
||||||
|
//GET get the news starting from the beginning, up to a default limit, or specify the index "id"
|
||||||
|
/news/archive/:id
|
||||||
|
|
||||||
|
//result:
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"index": index, //absolute index of the result
|
||||||
|
"title": title, //title of the article
|
||||||
|
"author": author, //author of the aricle
|
||||||
|
"body": body, //body of the article
|
||||||
|
"edits": edits //number of times this article has been edited
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
|
||||||
|
//GET get the latest titles, up to a default limit, or specify the index "id"
|
||||||
|
/news/titles/:id
|
||||||
|
|
||||||
|
//GET get the titles starting from the beginning, up to a default limit, or specify the index "id"
|
||||||
|
/news/archive/titles/:id
|
||||||
|
|
||||||
|
//result:
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"index": index, //absolute index of the result
|
||||||
|
"title": title, //title of the article
|
||||||
|
"author": author //author of the article
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
|
||||||
|
//POST send a formatted JSON object, returns new index on success, or error on failure
|
||||||
|
/publish
|
||||||
|
|
||||||
|
//arguments:
|
||||||
|
{
|
||||||
|
"key": key //the whitelist key, allows access to the POST routes
|
||||||
|
"title": title //title of the article
|
||||||
|
"author": author //author of the article
|
||||||
|
"body": body //body of the article
|
||||||
|
}
|
||||||
|
|
||||||
|
//result
|
||||||
|
{
|
||||||
|
"ok": ok //true on success, otherwise false
|
||||||
|
"index": index //new index of the article, or undefined
|
||||||
|
"error": error //error encountered, or undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
//POST similar to /publish, but allows overwriting an existing post
|
||||||
|
/edit
|
||||||
|
|
||||||
|
//arguments:
|
||||||
|
{
|
||||||
|
"key": key //the whitelist key, allows access to the POST routes
|
||||||
|
"title": title //title of the article
|
||||||
|
"author": author //author of the article
|
||||||
|
"body": body //body of the article
|
||||||
|
"overwrite": index //the index to save as -
|
||||||
|
}
|
||||||
|
|
||||||
|
//result
|
||||||
|
{
|
||||||
|
"ok": ok //true on success, otherwise false
|
||||||
|
"error": error //error encountered, or undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|||||||
Generated
+3535
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "news-server",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "An API centric news server. Uses Sequelize and mariaDB by default.",
|
||||||
|
"main": "server/server.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node server/server.js",
|
||||||
|
"dev": "npm run watch:server",
|
||||||
|
"watch:server": "nodemon . --ext js,jsx,json --ignore 'node_modules/*'"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/krgamestudios/news-server.git"
|
||||||
|
},
|
||||||
|
"author": "Kayne Ruse",
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/krgamestudios/news-server/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/krgamestudios/news-server#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"mariadb": "^2.5.2",
|
||||||
|
"sequelize": "^6.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"nodemon": "^2.0.7"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
const Sequelize = require('sequelize');
|
||||||
|
|
||||||
|
const sequelize = new Sequelize(process.env.DB_DATABASE, process.env.DB_USERNAME, process.env.DB_PASSWORD, {
|
||||||
|
host: process.env.DB_HOSTADDR,
|
||||||
|
dialect: 'mariadb',
|
||||||
|
timezone: process.env.DB_TIMEZONE,
|
||||||
|
logging: false
|
||||||
|
});
|
||||||
|
|
||||||
|
sequelize.sync();
|
||||||
|
|
||||||
|
module.exports = sequelize;
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
const Sequelize = require('sequelize');
|
||||||
|
const sequelize = require('..');
|
||||||
|
|
||||||
|
module.exports = sequelize.define('articles', {
|
||||||
|
index: {
|
||||||
|
type: Sequelize.INTEGER(11),
|
||||||
|
allowNull: false,
|
||||||
|
autoIncrement: true,
|
||||||
|
primaryKey: true,
|
||||||
|
unique: true
|
||||||
|
},
|
||||||
|
|
||||||
|
title: {
|
||||||
|
type: Sequelize.TEXT,
|
||||||
|
defaultValue: ''
|
||||||
|
},
|
||||||
|
|
||||||
|
author: {
|
||||||
|
type: Sequelize.TEXT,
|
||||||
|
defaultValue: ''
|
||||||
|
},
|
||||||
|
|
||||||
|
body: {
|
||||||
|
type: Sequelize.TEXT,
|
||||||
|
defaultValue: ''
|
||||||
|
},
|
||||||
|
|
||||||
|
edits: {
|
||||||
|
type: Sequelize.INTEGER(11),
|
||||||
|
defaultValue: 0
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
module.exports = {
|
||||||
|
articles: require('./articles'),
|
||||||
|
revisions: require('./revisions')
|
||||||
|
};
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
const Sequelize = require('sequelize');
|
||||||
|
const sequelize = require('..');
|
||||||
|
|
||||||
|
const articles = require('./articles');
|
||||||
|
|
||||||
|
const revisions = sequelize.define('revisions', {
|
||||||
|
title: {
|
||||||
|
type: Sequelize.TEXT,
|
||||||
|
defaultValue: ''
|
||||||
|
},
|
||||||
|
|
||||||
|
author: {
|
||||||
|
type: Sequelize.TEXT,
|
||||||
|
defaultValue: ''
|
||||||
|
},
|
||||||
|
|
||||||
|
body: {
|
||||||
|
type: Sequelize.TEXT,
|
||||||
|
defaultValue: ''
|
||||||
|
},
|
||||||
|
|
||||||
|
revision: {
|
||||||
|
type: Sequelize.INTEGER(11),
|
||||||
|
defaultValue: 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//relationships
|
||||||
|
revisions.hasOne(articles, { as: 'article' });
|
||||||
|
|
||||||
|
sequelize.sync();
|
||||||
|
|
||||||
|
module.exports = revisions;
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
//the routes
|
||||||
|
const query = require('./query');
|
||||||
|
|
||||||
|
//basic route management
|
||||||
|
router.get('/', query(false, false));
|
||||||
|
router.get('/:id(\\d+)', query(false, false));
|
||||||
|
router.get('/archive', query(true, false));
|
||||||
|
router.get('/archive/:id(\\d+)', query(true, false));
|
||||||
|
router.get('/titles', query(false, true));
|
||||||
|
router.get('/titles/:id(\\d+)', query(false, true));
|
||||||
|
router.get('/archive/titles', query(true, true));
|
||||||
|
router.get('/archive/titles/:id(\\d+)', query(true, true));
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
const { articles } = require('../database/models');
|
||||||
|
|
||||||
|
//the query function that can be reused
|
||||||
|
const query = (ascending, titlesOnly) => async (req, res) => {
|
||||||
|
console.log(ascending, titlesOnly);
|
||||||
|
console.log(req.params);
|
||||||
|
|
||||||
|
//specific search
|
||||||
|
if (req.params.id && typeof(parseInt(req.params.id)) === 'number') {
|
||||||
|
const result = await articles.findOne({
|
||||||
|
attributes: [
|
||||||
|
'index', 'title', 'author', ...(!titlesOnly ? ['body', 'edits'] : [])
|
||||||
|
],
|
||||||
|
order: [
|
||||||
|
['index', ascending ? 'ASC' : 'DESC']
|
||||||
|
],
|
||||||
|
offset: parseInt(req.params.id),
|
||||||
|
limit: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(200).json(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
//default search
|
||||||
|
else {
|
||||||
|
const result = await articles.findAndCountAll({
|
||||||
|
attributes: [
|
||||||
|
'index', 'title', 'author', ...(!titlesOnly ? ['body', 'edits'] : [])
|
||||||
|
],
|
||||||
|
order: [
|
||||||
|
['index', ascending ? 'ASC' : 'DESC']
|
||||||
|
],
|
||||||
|
count: req.params.limit || process.env.QUERY_LIMIT || 999
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(200).json(result.rows || result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = query;
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
//environment variables
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
//create the server
|
||||||
|
const express = require('express');
|
||||||
|
const app = express();
|
||||||
|
const server = require('http').Server(app);
|
||||||
|
|
||||||
|
//database connection
|
||||||
|
const database = require('./database');
|
||||||
|
|
||||||
|
//access the news
|
||||||
|
app.use('/news', require('./news'));
|
||||||
|
|
||||||
|
//error on access
|
||||||
|
app.get('*', (req, res) => {
|
||||||
|
res.redirect('https://github.com/krgamestudios/news-server');
|
||||||
|
});
|
||||||
|
|
||||||
|
//startup
|
||||||
|
server.listen(process.env.WEB_PORT || 3100, (err) => {
|
||||||
|
console.log(`listening to localhost:${process.env.WEB_PORT || 3100}`);
|
||||||
|
});
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#This file only needs to be run once, during initial setup
|
||||||
|
|
||||||
|
#Create the actual database
|
||||||
|
CREATE DATABASE IF NOT EXISTS news;
|
||||||
|
USE news;
|
||||||
|
|
||||||
|
#Create the database user
|
||||||
|
CREATE USER IF NOT EXISTS 'news'@'%' IDENTIFIED BY 'charizard';
|
||||||
|
GRANT ALL PRIVILEGES ON news.* TO 'news'@'%';
|
||||||
Reference in New Issue
Block a user