Spaces:
Sleeping
Sleeping
Delete app
Browse files- app/app.js +0 -44
- app/config.js +0 -56
- app/handlers/error.js +0 -45
- app/handlers/index.js +0 -3
- app/handlers/thing.js +0 -91
- app/handlers/things.js +0 -28
- app/helpers/APIError.js +0 -31
- app/helpers/index.js +0 -2
- app/helpers/parseSkipLimit.js +0 -33
- app/models/Thing.js +0 -108
- app/models/index.js +0 -1
- app/routers/index.js +0 -1
- app/routers/things.js +0 -25
- app/schemas/index.js +0 -2
- app/schemas/thingNew.json +0 -27
- app/schemas/thingUpdate.json +0 -27
- app/server.js +0 -6
app/app.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
| 1 |
-
// npm packages
|
| 2 |
-
const dotenv = require("dotenv");
|
| 3 |
-
const express = require("express");
|
| 4 |
-
|
| 5 |
-
// app imports
|
| 6 |
-
const { connectToDatabase, globalResponseHeaders } = require("./config");
|
| 7 |
-
const { errorHandler } = require("./handlers");
|
| 8 |
-
const { thingsRouter } = require("./routers");
|
| 9 |
-
|
| 10 |
-
// global constants
|
| 11 |
-
dotenv.config();
|
| 12 |
-
const app = express();
|
| 13 |
-
const {
|
| 14 |
-
bodyParserHandler,
|
| 15 |
-
globalErrorHandler,
|
| 16 |
-
fourOhFourHandler,
|
| 17 |
-
fourOhFiveHandler,
|
| 18 |
-
} = errorHandler;
|
| 19 |
-
|
| 20 |
-
// database
|
| 21 |
-
connectToDatabase();
|
| 22 |
-
|
| 23 |
-
// body parser setup
|
| 24 |
-
app.use(express.urlencoded({ extended: true }));
|
| 25 |
-
app.use(express.json({ type: "*/*" }));
|
| 26 |
-
app.use(bodyParserHandler); // error handling specific to body parser only
|
| 27 |
-
|
| 28 |
-
// response headers setup; CORS
|
| 29 |
-
app.use(globalResponseHeaders);
|
| 30 |
-
|
| 31 |
-
app.use("/things", thingsRouter);
|
| 32 |
-
|
| 33 |
-
// catch-all for 404 "Not Found" errors
|
| 34 |
-
app.get("*", fourOhFourHandler);
|
| 35 |
-
// catch-all for 405 "Method Not Allowed" errors
|
| 36 |
-
app.all("*", fourOhFiveHandler);
|
| 37 |
-
|
| 38 |
-
app.use(globalErrorHandler);
|
| 39 |
-
|
| 40 |
-
/**
|
| 41 |
-
* This file does NOT run the app. It merely builds and configures it then exports it.config
|
| 42 |
-
* This is for integration tests with supertest (see __tests__).
|
| 43 |
-
*/
|
| 44 |
-
module.exports = app;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/config.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
| 1 |
-
const mongoose = require("mongoose");
|
| 2 |
-
|
| 3 |
-
const APP_NAME = "Boilerplate API";
|
| 4 |
-
const ENV = process.env.NODE_ENV;
|
| 5 |
-
const PORT = process.env.PORT || 8080;
|
| 6 |
-
|
| 7 |
-
/**
|
| 8 |
-
* Connect to mongoose asynchronously or bail out if it fails
|
| 9 |
-
*/
|
| 10 |
-
async function connectToDatabase() {
|
| 11 |
-
const MONGODB_URI =
|
| 12 |
-
process.env.MONGODB_URI || "mongodb://mongodb/boilerplate";
|
| 13 |
-
|
| 14 |
-
mongoose.Promise = Promise;
|
| 15 |
-
if (ENV === "development" || ENV === "test") {
|
| 16 |
-
mongoose.set("debug", true);
|
| 17 |
-
}
|
| 18 |
-
|
| 19 |
-
try {
|
| 20 |
-
await mongoose.connect(MONGODB_URI, {
|
| 21 |
-
autoIndex: false,
|
| 22 |
-
useNewUrlParser: true,
|
| 23 |
-
useUnifiedTopology: true,
|
| 24 |
-
});
|
| 25 |
-
console.log(`${APP_NAME} successfully connected to database.`);
|
| 26 |
-
} catch (error) {
|
| 27 |
-
console.log(error);
|
| 28 |
-
process.exit(1);
|
| 29 |
-
}
|
| 30 |
-
}
|
| 31 |
-
|
| 32 |
-
/**
|
| 33 |
-
* Configuration middleware to enable cors and set some other allowed headers.
|
| 34 |
-
* You can also just use the 'cors' package.
|
| 35 |
-
*/
|
| 36 |
-
function globalResponseHeaders(request, response, next) {
|
| 37 |
-
response.header("Access-Control-Allow-Origin", "*");
|
| 38 |
-
response.header(
|
| 39 |
-
"Access-Control-Allow-Headers",
|
| 40 |
-
"Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, Authorization"
|
| 41 |
-
);
|
| 42 |
-
response.header(
|
| 43 |
-
"Access-Control-Allow-Methods",
|
| 44 |
-
"POST,GET,PATCH,DELETE,OPTIONS"
|
| 45 |
-
);
|
| 46 |
-
response.header("Content-Type", "application/json");
|
| 47 |
-
return next();
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
-
module.exports = {
|
| 51 |
-
APP_NAME,
|
| 52 |
-
ENV,
|
| 53 |
-
PORT,
|
| 54 |
-
connectToDatabase,
|
| 55 |
-
globalResponseHeaders,
|
| 56 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/handlers/error.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
| 1 |
-
const { APP_NAME } = require("../config");
|
| 2 |
-
const { APIError } = require("../helpers");
|
| 3 |
-
|
| 4 |
-
function bodyParserHandler(error, request, response, next) {
|
| 5 |
-
if (error instanceof SyntaxError || error instanceof TypeError) {
|
| 6 |
-
// console.error(error);
|
| 7 |
-
return next(new APIError(400, "Bad Request", "Malformed JSON."));
|
| 8 |
-
}
|
| 9 |
-
}
|
| 10 |
-
|
| 11 |
-
function fourOhFourHandler(request, response, next) {
|
| 12 |
-
return next(
|
| 13 |
-
new APIError(
|
| 14 |
-
404,
|
| 15 |
-
"Resource Not Found",
|
| 16 |
-
`${request.path} is not valid path to a ${APP_NAME} resource.`
|
| 17 |
-
)
|
| 18 |
-
);
|
| 19 |
-
}
|
| 20 |
-
|
| 21 |
-
function fourOhFiveHandler(request, response, next) {
|
| 22 |
-
return next(
|
| 23 |
-
new APIError(
|
| 24 |
-
405,
|
| 25 |
-
"Method Not Allowed",
|
| 26 |
-
`${request.method} method is not supported at ${request.path}.`
|
| 27 |
-
)
|
| 28 |
-
);
|
| 29 |
-
}
|
| 30 |
-
|
| 31 |
-
function globalErrorHandler(error, request, response, next) {
|
| 32 |
-
let err = error;
|
| 33 |
-
if (!(error instanceof APIError)) {
|
| 34 |
-
err = new APIError(500, error.type, error.message);
|
| 35 |
-
}
|
| 36 |
-
|
| 37 |
-
return response.status(err.status).json(err);
|
| 38 |
-
}
|
| 39 |
-
|
| 40 |
-
module.exports = {
|
| 41 |
-
bodyParserHandler,
|
| 42 |
-
fourOhFourHandler,
|
| 43 |
-
fourOhFiveHandler,
|
| 44 |
-
globalErrorHandler
|
| 45 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/handlers/index.js
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
exports.errorHandler = require("./error");
|
| 2 |
-
exports.thingHandler = require("./thing");
|
| 3 |
-
exports.thingsHandler = require("./things");
|
|
|
|
|
|
|
|
|
|
|
|
app/handlers/thing.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
| 1 |
-
// npm packages
|
| 2 |
-
const { validate } = require("jsonschema");
|
| 3 |
-
|
| 4 |
-
// app imports
|
| 5 |
-
const { Thing } = require("../models");
|
| 6 |
-
const { APIError } = require("../helpers");
|
| 7 |
-
const { thingNewSchema, thingUpdateSchema } = require("../schemas");
|
| 8 |
-
|
| 9 |
-
/**
|
| 10 |
-
* Validate the POST request body and create a new Thing
|
| 11 |
-
*/
|
| 12 |
-
async function createThing(request, response, next) {
|
| 13 |
-
const validation = validate(request.body, thingNewSchema);
|
| 14 |
-
if (!validation.valid) {
|
| 15 |
-
return next(
|
| 16 |
-
new APIError(
|
| 17 |
-
400,
|
| 18 |
-
"Bad Request",
|
| 19 |
-
validation.errors.map(e => e.stack).join(". ")
|
| 20 |
-
)
|
| 21 |
-
);
|
| 22 |
-
}
|
| 23 |
-
|
| 24 |
-
try {
|
| 25 |
-
const newThing = await Thing.createThing(new Thing(request.body));
|
| 26 |
-
return response.status(201).json(newThing);
|
| 27 |
-
} catch (err) {
|
| 28 |
-
return next(err);
|
| 29 |
-
}
|
| 30 |
-
}
|
| 31 |
-
|
| 32 |
-
/**
|
| 33 |
-
* Get a single thing
|
| 34 |
-
* @param {String} name - the name of the Thing to retrieve
|
| 35 |
-
*/
|
| 36 |
-
async function readThing(request, response, next) {
|
| 37 |
-
const { name } = request.params;
|
| 38 |
-
try {
|
| 39 |
-
const thing = await Thing.readThing(name);
|
| 40 |
-
return response.json(thing);
|
| 41 |
-
} catch (err) {
|
| 42 |
-
return next(err);
|
| 43 |
-
}
|
| 44 |
-
}
|
| 45 |
-
|
| 46 |
-
/**
|
| 47 |
-
* Update a single thing
|
| 48 |
-
* @param {String} name - the name of the Thing to update
|
| 49 |
-
*/
|
| 50 |
-
async function updateThing(request, response, next) {
|
| 51 |
-
const { name } = request.params;
|
| 52 |
-
|
| 53 |
-
const validation = validate(request.body, thingUpdateSchema);
|
| 54 |
-
if (!validation.valid) {
|
| 55 |
-
return next(
|
| 56 |
-
new APIError(
|
| 57 |
-
400,
|
| 58 |
-
"Bad Request",
|
| 59 |
-
validation.errors.map(e => e.stack).join(". ")
|
| 60 |
-
)
|
| 61 |
-
);
|
| 62 |
-
}
|
| 63 |
-
|
| 64 |
-
try {
|
| 65 |
-
const thing = await Thing.updateThing(name, request.body);
|
| 66 |
-
return response.json(thing);
|
| 67 |
-
} catch (err) {
|
| 68 |
-
return next(err);
|
| 69 |
-
}
|
| 70 |
-
}
|
| 71 |
-
|
| 72 |
-
/**
|
| 73 |
-
* Remove a single thing
|
| 74 |
-
* @param {String} name - the name of the Thing to remove
|
| 75 |
-
*/
|
| 76 |
-
async function deleteThing(request, response, next) {
|
| 77 |
-
const { name } = request.params;
|
| 78 |
-
try {
|
| 79 |
-
const deleteMsg = await Thing.deleteThing(name);
|
| 80 |
-
return response.json(deleteMsg);
|
| 81 |
-
} catch (err) {
|
| 82 |
-
return next(err);
|
| 83 |
-
}
|
| 84 |
-
}
|
| 85 |
-
|
| 86 |
-
module.exports = {
|
| 87 |
-
createThing,
|
| 88 |
-
readThing,
|
| 89 |
-
updateThing,
|
| 90 |
-
deleteThing
|
| 91 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/handlers/things.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
| 1 |
-
// app imports
|
| 2 |
-
const { Thing } = require("../models");
|
| 3 |
-
const { APIError, parseSkipLimit } = require("../helpers");
|
| 4 |
-
|
| 5 |
-
/**
|
| 6 |
-
* List all the things. Query params ?skip=0&limit=1000 by default
|
| 7 |
-
*/
|
| 8 |
-
async function readThings(request, response, next) {
|
| 9 |
-
/* pagination validation */
|
| 10 |
-
let skip = parseSkipLimit(request.query.skip) || 0;
|
| 11 |
-
let limit = parseSkipLimit(request.query.limit, 1000) || 1000;
|
| 12 |
-
if (skip instanceof APIError) {
|
| 13 |
-
return next(skip);
|
| 14 |
-
} else if (limit instanceof APIError) {
|
| 15 |
-
return next(limit);
|
| 16 |
-
}
|
| 17 |
-
|
| 18 |
-
try {
|
| 19 |
-
const things = await Thing.readThings({}, {}, skip, limit);
|
| 20 |
-
return response.json(things);
|
| 21 |
-
} catch (err) {
|
| 22 |
-
return next(err);
|
| 23 |
-
}
|
| 24 |
-
}
|
| 25 |
-
|
| 26 |
-
module.exports = {
|
| 27 |
-
readThings
|
| 28 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/helpers/APIError.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
| 1 |
-
/** Class representing an API Error Response with a related HTTP Status Code **/
|
| 2 |
-
class APIError extends Error {
|
| 3 |
-
/**
|
| 4 |
-
* Create an Error Object
|
| 5 |
-
* @param {Number} status - The HTTP Status Code (e.g. 404)
|
| 6 |
-
* @param {String} title - The title corresponding to the Status Code (e.g. Bad Request)
|
| 7 |
-
* @param {String} message - Specific information about what caused the error
|
| 8 |
-
*/
|
| 9 |
-
constructor(
|
| 10 |
-
status = 500,
|
| 11 |
-
title = "Internal Server Error",
|
| 12 |
-
message = "An unknown server error occurred."
|
| 13 |
-
) {
|
| 14 |
-
super(message);
|
| 15 |
-
this.status = status;
|
| 16 |
-
this.title = title;
|
| 17 |
-
this.message = message;
|
| 18 |
-
}
|
| 19 |
-
toJSON() {
|
| 20 |
-
const { status, title, message } = this;
|
| 21 |
-
return {
|
| 22 |
-
error: {
|
| 23 |
-
status,
|
| 24 |
-
title,
|
| 25 |
-
message
|
| 26 |
-
}
|
| 27 |
-
};
|
| 28 |
-
}
|
| 29 |
-
}
|
| 30 |
-
|
| 31 |
-
module.exports = APIError;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/helpers/index.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
exports.APIError = require("./APIError");
|
| 2 |
-
exports.parseSkipLimit = require("./parseSkipLimit");
|
|
|
|
|
|
|
|
|
app/helpers/parseSkipLimit.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
| 1 |
-
const APIError = require("./APIError");
|
| 2 |
-
/**
|
| 3 |
-
* Validate the 'limit' and `skip` query params
|
| 4 |
-
* @param {String} val - limit or skip param
|
| 5 |
-
* @param {Number} max - the max value (default 1000)
|
| 6 |
-
* @param {String} type - what we're validating (skip or limit, default limit)
|
| 7 |
-
* @return {Number} numerical form of the val
|
| 8 |
-
*/
|
| 9 |
-
function parseSkipLimit(val, max = 1000, type = "limit") {
|
| 10 |
-
if (!val) {
|
| 11 |
-
return null;
|
| 12 |
-
}
|
| 13 |
-
const min = type === "skip" ? 0 : 1;
|
| 14 |
-
const num = +val;
|
| 15 |
-
|
| 16 |
-
if (!Number.isInteger(num)) {
|
| 17 |
-
return new APIError(
|
| 18 |
-
400,
|
| 19 |
-
"Bad Request",
|
| 20 |
-
`Invalid ${type}: '${val}', ${type} needs to be an integer.`
|
| 21 |
-
);
|
| 22 |
-
} else if (num < min || (max && num > max)) {
|
| 23 |
-
return new APIError(
|
| 24 |
-
400,
|
| 25 |
-
"Bad Request",
|
| 26 |
-
`${num} is out of range for ${type} -- it should be between ${min} and ${max}.`
|
| 27 |
-
);
|
| 28 |
-
}
|
| 29 |
-
|
| 30 |
-
return num;
|
| 31 |
-
}
|
| 32 |
-
|
| 33 |
-
module.exports = parseSkipLimit;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/models/Thing.js
DELETED
|
@@ -1,108 +0,0 @@
|
|
| 1 |
-
// npm packages
|
| 2 |
-
const mongoose = require("mongoose");
|
| 3 |
-
|
| 4 |
-
// app imports
|
| 5 |
-
const { APIError } = require("../helpers");
|
| 6 |
-
|
| 7 |
-
// globals
|
| 8 |
-
const Schema = mongoose.Schema;
|
| 9 |
-
|
| 10 |
-
const thingSchema = new Schema({
|
| 11 |
-
name: String,
|
| 12 |
-
number: Number,
|
| 13 |
-
stuff: [String],
|
| 14 |
-
url: String
|
| 15 |
-
});
|
| 16 |
-
|
| 17 |
-
thingSchema.statics = {
|
| 18 |
-
/**
|
| 19 |
-
* Create a Single New Thing
|
| 20 |
-
* @param {object} newThing - an instance of Thing
|
| 21 |
-
* @returns {Promise<Thing, APIError>}
|
| 22 |
-
*/
|
| 23 |
-
async createThing(newThing) {
|
| 24 |
-
const duplicate = await this.findOne({ name: newThing.name });
|
| 25 |
-
if (duplicate) {
|
| 26 |
-
throw new APIError(
|
| 27 |
-
409,
|
| 28 |
-
"Thing Already Exists",
|
| 29 |
-
`There is already a thing with name '${newThing.name}'.`
|
| 30 |
-
);
|
| 31 |
-
}
|
| 32 |
-
const thing = await newThing.save();
|
| 33 |
-
return thing.toObject();
|
| 34 |
-
},
|
| 35 |
-
/**
|
| 36 |
-
* Delete a single Thing
|
| 37 |
-
* @param {String} name - the Thing's name
|
| 38 |
-
* @returns {Promise<Thing, APIError>}
|
| 39 |
-
*/
|
| 40 |
-
async deleteThing(name) {
|
| 41 |
-
const deleted = await this.findOneAndRemove({ name });
|
| 42 |
-
if (!deleted) {
|
| 43 |
-
throw new APIError(404, "Thing Not Found", `No thing '${name}' found.`);
|
| 44 |
-
}
|
| 45 |
-
return deleted.toObject();
|
| 46 |
-
},
|
| 47 |
-
/**
|
| 48 |
-
* Get a single Thing by name
|
| 49 |
-
* @param {String} name - the Thing's name
|
| 50 |
-
* @returns {Promise<Thing, APIError>}
|
| 51 |
-
*/
|
| 52 |
-
async readThing(name) {
|
| 53 |
-
const thing = await this.findOne({ name });
|
| 54 |
-
|
| 55 |
-
if (!thing) {
|
| 56 |
-
throw new APIError(404, "Thing Not Found", `No thing '${name}' found.`);
|
| 57 |
-
}
|
| 58 |
-
return thing.toObject();
|
| 59 |
-
},
|
| 60 |
-
/**
|
| 61 |
-
* Get a list of Things
|
| 62 |
-
* @param {Object} query - pre-formatted query to retrieve things.
|
| 63 |
-
* @param {Object} fields - a list of fields to select or not in object form
|
| 64 |
-
* @param {String} skip - number of docs to skip (for pagination)
|
| 65 |
-
* @param {String} limit - number of docs to limit by (for pagination)
|
| 66 |
-
* @returns {Promise<Things, APIError>}
|
| 67 |
-
*/
|
| 68 |
-
async readThings(query, fields, skip, limit) {
|
| 69 |
-
const things = await this.find(query, fields)
|
| 70 |
-
.skip(skip)
|
| 71 |
-
.limit(limit)
|
| 72 |
-
.sort({ name: 1 })
|
| 73 |
-
.exec();
|
| 74 |
-
if (!things.length) {
|
| 75 |
-
return [];
|
| 76 |
-
}
|
| 77 |
-
return things.map(thing => thing.toObject());
|
| 78 |
-
},
|
| 79 |
-
/**
|
| 80 |
-
* Patch/Update a single Thing
|
| 81 |
-
* @param {String} name - the Thing's name
|
| 82 |
-
* @param {Object} thingUpdate - the json containing the Thing attributes
|
| 83 |
-
* @returns {Promise<Thing, APIError>}
|
| 84 |
-
*/
|
| 85 |
-
async updateThing(name, thingUpdate) {
|
| 86 |
-
const thing = await this.findOneAndUpdate({ name }, thingUpdate, {
|
| 87 |
-
new: true
|
| 88 |
-
});
|
| 89 |
-
if (!thing) {
|
| 90 |
-
throw new APIError(404, "Thing Not Found", `No thing '${name}' found.`);
|
| 91 |
-
}
|
| 92 |
-
return thing.toObject();
|
| 93 |
-
}
|
| 94 |
-
};
|
| 95 |
-
|
| 96 |
-
/* Transform with .toObject to remove __v and _id from response */
|
| 97 |
-
if (!thingSchema.options.toObject) thingSchema.options.toObject = {};
|
| 98 |
-
thingSchema.options.toObject.transform = (doc, ret) => {
|
| 99 |
-
const transformed = ret;
|
| 100 |
-
delete transformed._id;
|
| 101 |
-
delete transformed.__v;
|
| 102 |
-
return transformed;
|
| 103 |
-
};
|
| 104 |
-
|
| 105 |
-
/** Ensure MongoDB Indices **/
|
| 106 |
-
thingSchema.index({ name: 1, number: 1 }, { unique: true }); // example compound idx
|
| 107 |
-
|
| 108 |
-
module.exports = mongoose.model("Thing", thingSchema);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/models/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
exports.Thing = require("./Thing");
|
|
|
|
|
|
app/routers/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
exports.thingsRouter = require("./things");
|
|
|
|
|
|
app/routers/things.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
| 1 |
-
// npm packages
|
| 2 |
-
const express = require("express");
|
| 3 |
-
|
| 4 |
-
// app imports
|
| 5 |
-
const { thingHandler, thingsHandler } = require("../handlers");
|
| 6 |
-
|
| 7 |
-
// globals
|
| 8 |
-
const router = new express.Router();
|
| 9 |
-
const { readThings } = thingsHandler;
|
| 10 |
-
const { createThing, readThing, updateThing, deleteThing } = thingHandler;
|
| 11 |
-
|
| 12 |
-
/* All the Things Route */
|
| 13 |
-
router
|
| 14 |
-
.route("")
|
| 15 |
-
.get(readThings)
|
| 16 |
-
.post(createThing);
|
| 17 |
-
|
| 18 |
-
/* Single Thing by Name Route */
|
| 19 |
-
router
|
| 20 |
-
.route("/:name")
|
| 21 |
-
.get(readThing)
|
| 22 |
-
.patch(updateThing)
|
| 23 |
-
.delete(deleteThing);
|
| 24 |
-
|
| 25 |
-
module.exports = router;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/schemas/index.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
exports.thingNewSchema = require('./thingNew');
|
| 2 |
-
exports.thingUpdateSchema = require('./thingUpdate');
|
|
|
|
|
|
|
|
|
app/schemas/thingNew.json
DELETED
|
@@ -1,27 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"$schema": "http://json-schema.org/draft-04/schema#",
|
| 3 |
-
"type": "object",
|
| 4 |
-
"additionalProperties": false,
|
| 5 |
-
"properties": {
|
| 6 |
-
"name": {
|
| 7 |
-
"type": "string"
|
| 8 |
-
},
|
| 9 |
-
"number": {
|
| 10 |
-
"type": "integer",
|
| 11 |
-
"minimum": 0
|
| 12 |
-
},
|
| 13 |
-
"stuff": {
|
| 14 |
-
"type": "array",
|
| 15 |
-
"uniqueItems": true,
|
| 16 |
-
"minItems": 1,
|
| 17 |
-
"items": {
|
| 18 |
-
"type": "string"
|
| 19 |
-
}
|
| 20 |
-
},
|
| 21 |
-
"url": {
|
| 22 |
-
"type": "string",
|
| 23 |
-
"format": "uri"
|
| 24 |
-
}
|
| 25 |
-
},
|
| 26 |
-
"required": ["name"]
|
| 27 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/schemas/thingUpdate.json
DELETED
|
@@ -1,27 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"$schema": "http://json-schema.org/draft-04/schema#",
|
| 3 |
-
"type": "object",
|
| 4 |
-
"additionalProperties": false,
|
| 5 |
-
"properties": {
|
| 6 |
-
"name": {
|
| 7 |
-
"type": "string"
|
| 8 |
-
},
|
| 9 |
-
"number": {
|
| 10 |
-
"type": "integer",
|
| 11 |
-
"minimum": 0
|
| 12 |
-
},
|
| 13 |
-
"stuff": {
|
| 14 |
-
"type": "array",
|
| 15 |
-
"uniqueItems": true,
|
| 16 |
-
"minItems": 1,
|
| 17 |
-
"items": {
|
| 18 |
-
"type": "string"
|
| 19 |
-
}
|
| 20 |
-
},
|
| 21 |
-
"url": {
|
| 22 |
-
"type": "string",
|
| 23 |
-
"format": "uri"
|
| 24 |
-
}
|
| 25 |
-
},
|
| 26 |
-
"required": ["name"]
|
| 27 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/server.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
const { APP_NAME, PORT } = require("./config");
|
| 2 |
-
const app = require("./app");
|
| 3 |
-
|
| 4 |
-
app.listen(PORT, () => {
|
| 5 |
-
console.log(`${APP_NAME} is listening on port ${PORT}...`);
|
| 6 |
-
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|