Skip to content

Commit

Permalink
Added initial API setup
Browse files Browse the repository at this point in the history
  • Loading branch information
SeedyROM committed Sep 26, 2019
1 parent 65952cb commit 565a408
Show file tree
Hide file tree
Showing 13 changed files with 3,822 additions and 51 deletions.
2 changes: 2 additions & 0 deletions api/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.nyc_output
node_modules/
21 changes: 18 additions & 3 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,26 @@
"name": "api",
"version": "1.0.0",
"description": "",
"main": "index.js",
"main": "./src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"start": "nodemon ./src/index.js --watch ./src",
"test": "nyc mocha ./test/**/*.test.js --require=./test/test-helper --timeout=10000"
},
"keywords": [],
"author": "",
"license": "ISC"
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"express": "^4.17.1",
"express-async-router": "^0.1.15",
"mongoose": "^5.7.1",
"morgan": "^1.9.1"
},
"devDependencies": {
"chai": "^4.2.0",
"chai-http": "^4.3.0",
"mocha": "^6.2.0",
"nodemon": "^1.19.2",
"nyc": "^14.1.1"
}
}
69 changes: 69 additions & 0 deletions api/src/controllers/people.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const { AsyncRouter } = require("express-async-router");
const Person = require("../models/Person");

const router = AsyncRouter();

//
// CRUD routes for the Person resource
//

// List
router.get("/", async (req, res) => {
const people = await Person.find();

res.send(people);
});

// Create
router.post("/", async (req, res) => {
const person = new Person(req.body);

try {
await person.save();
} catch(e) {
return res.sendStatus(500);
}

res.status(201).send(person);
});

// Retrieve
router.get("/:_id", async (req, res) => {
const person = await Person.findOne({_id: req.params._id});

// Short circuit the request response cycle!
if(!person) return res.sendStatus(404);

res.send(person);
});

// Update
router.patch("/:_id", async (req, res) => {
const person = await Person.findOne({_id: req.params._id});

// Short circuit the request response cycle!
if(!person) return res.sendStatus(404);

person.set(req.body);
try {
await person.save();
} catch(e) {
return res.sendStatus(500);
}

res.send(person);
});

// Delete
router.delete("/:_id", async (req, res) => {
const person = await Person.findOne({_id: req.params._id});

// Short circuit the request response cycle!
if(!person) return res.sendStatus(404);

await person.remove();

res.send(person);
});

module.exports = router;
3 changes: 3 additions & 0 deletions api/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const { startServer } = require("./server");

startServer();
32 changes: 32 additions & 0 deletions api/src/models/Person.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const mongoose = require("mongoose");

const { Schema } = mongoose;

const personSchema = Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
username: {
type: String,
required: true,
unique: true,
},
age: Number
}, {
timestamps: true,
toJSON: {
virtuals: true,
},
toObject: {
virtuals: true,
}
});

const Person = mongoose.model("Person", personSchema);

module.exports = Person;
46 changes: 46 additions & 0 deletions api/src/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose");
const morgan = require("morgan");

const PeopleController = require("./controllers/people.controller");

// Express application
const app = express();

// Middleware
app.use(cors());
/* istanbul ignore if */
if(process.env.ENV !== "test") app.use(morgan("tiny"));
app.use(express.json());

// Controllers
app.use("/people", PeopleController);

// Helper functions
const connectDatabase = async (databaseName="lab4-peopledb") => {
const database = await mongoose.connect(
`mongodb://localhost/${databaseName}`,
{
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: true,
useUnifiedTopology: true
}
);

return database;
}
const startServer = (port=8000, host="localhost") => {
app.listen(port, host, async () => {
await connectDatabase();

console.log(`Listening at ${host}:${port}...`);
})
}

module.exports = {
app,
connectDatabase,
startServer,
};
118 changes: 118 additions & 0 deletions api/test/controllers.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
const chai = require("chai");

const Person = require("../src/models/Person");
const { app } = require("../src/server");
const mongoose = require("mongoose");

const { ObjectId } = mongoose.Types;

const { expect } = chai;

const makePerson = async () => {
const person = new Person({
firstName: "Mike",
lastName: "Zentz",
username: "moikzentz",
age: 311
})

await person.save();

return person;
}

describe("People CRUD controller", () => {
afterEach(async () => {
await Person.deleteMany({});
});

it("GET /: Shows all people", async () => {
let response = await chai
.request(app)
.get("/people");

expect(response.body.length).to.eq(0);

await makePerson();
response = await chai
.request(app)
.get("/people");

expect(response.body.length).to.eq(1);
});

it("POST /: Create a person", async () => {
let response = await chai
.request(app)
.post("/people")
.send({
firstName: "Carl",
lastName: "Johnson",
username: "bellatrix",
age: 12
});

expect(response.status).to.eq(201);

response = await chai
.request(app)
.post("/people")
.send({
firstName: "Carl",
lastName: "Johnson",
username: "bellatrix",
age: 12
});

expect(response.status).to.eq(500);
});

it("GET /:_id: Get a specific person", async () => {
let response = await chai
.request(app)
.get(`/people/${new ObjectId()}`);

expect(response.status).to.eq(404);

const person = await makePerson();
response = await chai
.request(app)
.get(`/people/${person._id}`);

expect(response.status).to.eq(200);
});

it("PATCH /:_id: Update a specific person", async () => {
let response = await chai
.request(app)
.patch(`/people/${new ObjectId()}`);

expect(response.status).to.eq(404);

const person = await makePerson();
response = await chai
.request(app)
.patch(`/people/${person._id}`)
.send({
lastName: "Zintz",
});

expect(response.status).to.eq(200);
expect(response.body.lastName).to.eq("Zintz");
});

it("DELETE /:_id: Delete a specific person", async () => {
let response = await chai
.request(app)
.delete(`/people/${new ObjectId()}`);

expect(response.status).to.eq(404);

const person = await makePerson();
response = await chai
.request(app)
.delete(`/people/${person._id}`);

expect(response.status).to.eq(200);
});
});
20 changes: 20 additions & 0 deletions api/test/test-helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
process.env.ENV = "test";

const mocha = require("mocha");
const chai = require("chai");
const chaiHttp = require("chai-http");

const { connectDatabase } = require("../src/server");

chai.use(chaiHttp);

setTimeout(() => {
before(async function() {
this.database = await connectDatabase("lab4-peopledb-test");
});

after(async function() {
await this.database.connection.dropDatabase();
await this.database.connection.close();
});
});
Loading

0 comments on commit 565a408

Please sign in to comment.