2
\$\begingroup\$

I recently applied for a job as a Node/React developer. I'm attempting to cross over from a research position to web development. I didn't get the job but all the feedback I got was that my code was too academic and that it would take me too long to get up to their requirements. I'm not really sure what this means so any insight into the code much appreciated. Obviously I'd like to improve. Also, general tips on how to improve code in all aspects (blogs, books etc) very welcome.

The second part of the task was to design a RESTful API with very simple requirements:

Question:

In this repository you will find a JSON file: product.json with some product data. Each product will have the following fields:

{
  "name": "XXXXX",
  "description": "XXXX",
  "category": "XXXX"
}

You will need to perform the following tasks:

  • Create a node backend application and database using the framework of your choice. Create database migration and load scripts to support the data.
  • Create API endpoints that support the following operations:
    • Retrieve all products
    • Retrieve a list of categories
    • Retrieve the products for a category
    • Creation of a new product (and if necessary the category for that product) Deletion of a product

This is intended to be a creative exercise so the structure of the data stored in the database and the organisation of the APIs is left as a design decision for you.

Answer:

Structure:

-config
--database.js
--initialiseData.js
-data
--products.json
-helpers
--initialiseData.js
-models
--products.json
-routes
--index.js
--products.js
-tests
--routes.js
app.js
package.json

database.js

module.exports = {
    remoteUrl : '',
    localUrl: 'mongodb://localhost:27017/mrmnode'
};

initialiseData.js

module.exports = {
    recreateDBOnRestart: true,
};

products.json

[
    {
        "name": "Shot of Goldschläger",
        "description": "chilled liqueur with tiny, floating, gold flakes",
        "category": "Cocktails"
    },
    {
        "name": "Alabama Slammer",
        "description": "sloe gin, Southern Comfort, amaretto, orange juice",
        "category": "Cocktails"
    }
]

helpers/initialiseData.js

//./helper/initialiseData.js

//check the database to see if data has been added and add it if it hasn't
//options to wipe database on re-run
var data = require('../data/products.json'); //import data
var Products = require('../models/products.js'); //get the database
var config = require('../config/initialiseData.js');
var mongoose = require('mongoose')

var addProducts = function(){
    Products.collection.insert({_id:new mongoose.mongo.ObjectId('56cb91bdc3464f14678934ca'), name:data[0].name,description:data[0].description,category:data[0].category})
    Products.collection.insert(data.slice(1));
}

var dropCollection = function(){
    Products.remove({},function(err){
        if(err) return handleError(err);
    });
}
var initialiseData = function(){
    if (config.recreateDBOnRestart==true){
        dropCollection();
        addProducts();
    }
    if(Products.find()==[]){
        addProducts();
    }
}

module.exports = initialiseData;

models/products.json

var mongoose = require('mongoose');

module.exports = mongoose.model('Products', {
    _id  : {
        type : mongoose.Schema.ObjectId, auto: true
    },
    name : {
        type : String,
        required : true,
    },
    description : {
        type : String,
        required : true,
    },
    category : {
        type : String,
    default : undefined,
    },

});

routes/index.js

var express = require('express');
var router = express.Router();

router.use('/products', require('./products.js'));

module.exports = router

routes/products.js

var express = require('express');
var router = express.Router();
var Products = require('../models/products.js');

//get all products
router.get('/', function(req,res){

    Products.find(function(err, products){
        if(err){
            res.send(err);
        }
        res.json(products);
    });
});

//get distinct categories
router.get('/categories', function(req,res){
    Products.distinct('category',function(err, products){
        if(err){
            res.send(err);
        }
        res.json(products);
    });
});

//get all products of a certain category
router.get('/categories/:category', function(req,res){
    category =req.params.category;
    Products.find({category:category},function(err, products){
        if(err){
            res.send(err);
        }
        res.json(products);
    });
});

router.delete('/:id', function (req, res) {
    Products.remove({
        _id: req.params.id
    }, function (err, products) {
        if (err){
            res.send(err);
        }
        res.json({DELETED:products});
    });
});

module.exports = router

test/routes/products.js

process.env.NODE_ENV = 'test';

var chai = require('chai');
var expect = require('chai').expect;
var should = require('chai').should;
var chaiHttp = require('chai-http');
var app = require('../../app.js');
var Products = require('../../models/products.js');
var mongoose = require("mongoose");
var database = require('../../config/database.js');
var data = require('../../data/products.json');
var initialiseData = require('../../helpers/initialiseData')
var mongoose = require("mongoose");
var database = require('../../config/database.js');

//mongoose.connect(database.localUrl);
chai.use(chaiHttp);

describe('product api', function(){
    beforeEach(function(done){
        initialiseData();
        done();
    });

    it('should get all the products in the db', function(done){
        chai.request(app).get('/products').end(function(err,res){
            res.body.forEach(function(product,index){
                expect(product.name).to.equal(data[index].name);
                expect(product.description.replace('/','')).to.equal(data[index].description);
                expect(product.category).to.equal(data[index].category);
            });
            done();
        });
    });

    it('should get all of the distinct categories', function(done){
        chai.request(app).get('/products/categories').end(function(err,res){
                        console.log(res.body)
            expect(res.body).to.deep.have.same.members(["Cocktails","Beers"]);
            done();
        });
    });

    var cocktails = [{"name":"Shot of Goldschläger","description":"chilled liqueur with tiny, floating, gold flakes","category":"Cocktails"},
                     {"name":"Alabama Slammer","description":"sloe gin, Southern Comfort, amaretto, orange juice","category":"Cocktails"},
                     {"name":"Mai Tai","description":"light rum, orange curaçao, sour mix, pineapple juice, dark rum float","category":"Cocktails"},
                     {"name":"Long Island Iced Tea","description":"vodka, gin, rum, triple sec, sour mix, Coke","category":"Cocktails"}]

    it('should get all of the products of a certain category', function(done){
        chai.request(app).get('/products/categories/Cocktails').end(function(err,res){

            res.body.forEach(function(product,index){
                expect(product.name).to.equal(data[index].name);
                expect(product.description.replace('/','')).to.equal(data[index].description);
                expect(product.category).to.equal(data[index].category);
            });

            done();
        });
    });

    it('should delete a product by id', function(done){
        chai.request(app).delete('/products/56cb91bdc3464f14678934ca').end(function(err,res){
            expect(res.body.DELETED.ok).to.equal(1);
            done();
        });
    });
});

app.js

//app.js

//set up =================================
var express  = require('express');
var app      = express();                              
var mongoose = require('mongoose'); //setup the db mongoose for mongodb
var initialiseDB = require('./helpers/initialiseData.js'); //method to load data in to the db
var port = process.env.PORT || 8080; //set the port
var database = require('./config/database.js');
var morgan = require('morgan');             // log requests to the console (express4)
var bodyParser = require('body-parser');    // pull information from HTML POST (express4)
var methodOverride = require('method-override'); // simulate DELETE and PUT (express4)

//configuration ===========================
mongoose.connect(database.localUrl); //load up the database
initialiseDB(); //check for data and load if missing or config (./config/initialiseData.js) set to do so

app.use(morgan('dev')); // log every request to the console
app.use(bodyParser.urlencoded({'extended': 'true'})); // parse application/x-www-form-urlencoded
app.use(bodyParser.json()); // parse application/json
app.use(bodyParser.json({type: 'application/vnd.api+json'})); // parse application/vnd.api+json as json
app.use(methodOverride('X-HTTP-Method-Override')); // override with the X-HTTP-Method-Override header in the request

//routes ===================================
app.use(require('./routes/index.js'));

app.listen(port);//listen (start app with node app.js)
console.log('app listening on port ' + port); //maybe even add the config options here

module.exports = app; //for testing
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.