A forum engine using Nodejs and Vuejs (part 2)
In case you missed the part 1 of the series, you can do well to check it here. The part 2 would be more fun as we walk through the structure of the project.
Grab a seat with a cup of coffee. clone the project here to make it easier to access for better understanding as we progress.
Overtime, I have structured theproject as much as I think it would be pretty simple for someone to understand at a glance. I’m a fan of Model-View-Controller (separation of concerns). This design pattern ensures the project is well maintained. Now we have got a router (ensures easy access to handle client request).
In part 1, we created a basic router. The browser(http://localhost:3000) served as the client which sends a request to the application, the request was then handled by the router by returning the appropriate result.
app.get('/', (req, res) => {
res.json({ status: 'Introduction to Nodejs' })
})
Here we go,
Project breakdown
- Webpack : Well, we are in the 24th century, Webpack is not only used for the client side anymore. We would be using es6 and above and guess what ? The project is most likely to break depending on where its being hosted. The best use-case for us is to convert it back to es5. Webpack does that in a flash. One of the most interesting thing about Webpack is the state its maintains when a file is changed. In Nodejs, the moment you edit any file in the project, the application has to be restarted for the change(s) to take place. The webpack.testing.js file handles the test part of the project.
webpack.HotModuleReplacementPlugin()
The above snippet performs hot reload once it smells a change in the project. To understand more on how we would be using Webpack in this project, please check here.
- test: The test folder contains two files (api.test.js and helper). The api.test would handle test(s) that ensure the routes work as expected while the helper contains modules we would be using in api.test.
- middleware: Nothing is safe but we can make it very hard to crack. The middleware is the wall to the apis. Once a request is made, it hits the middleware before the resource is being fetched.
- config: The config handles how the application responds to different environment (production, development or local).
- modules: This contains independent units.
auth : This contains logic of how to verify a client, sign in a client etc.
errorHandler: we would always run into errors but its very important to handle them well. errorHandler ensures handled errors are well interpreted.
query: A generic CRUD (Create, Read, Update and Delete) that serves the controller based on request.
query.test.js: Yeah, we need to test the sub-module (query) to ensure its working as expected.
- router: handles all the routes we have in the resource. we can call him a base router.
- resources: Since we are trying to create a forum api. We would only need two resources which are user and post.
For each resource, the separation of concern plays a major role here. A resource contains a model, controller and a router. Personally, I believe this structure makes it easier to spot an error, test and easy to read or understand.
Once we can familiarize ourselves with the way the project is structured and what each file is meant for. I believe we are ready to take a full dive and get our hands dirty.
Lest I forget, the package.json file has been updated to handle all the dependencies we would be using for the application.
{
"name": "forum-engine-api",
"version": "1.0.0",
"description": "Using nodejs to write Forum engine api.",
"author": "Meshileya Seun <meshileyaseun@gmail.com/>",
"license": "MIT",
"scripts": {
"start": "webpack --progress --color",
"test:unit": "NODE_ENV=testing rm -rf ./tmp/mocha-webpack && mocha-webpack --webpack-config webpack.testing.js \"src/**/*.test.js\" --timeout 10000 --require source-map-support/register",
"test": "yarn run test:unit"
},
"dependencies": {
"bcrypt": "^1.0.3",
"express": "^4.16.3",
"express-jwt": "^5.3.0",
"jsonwebtoken": "^8.1.0",
"lodash.merge": "^4.6.0",
"mongoose": "^4.12.1"
},
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-plugin-transform-regenerator": "^6.26.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.6.0",
"babel-preset-stage-0": "^6.24.1",
"chai": "^4.1.2",
"chai-http": "^3.0.0",
"mocha": "^4.0.1",
"mocha-webpack": "next",
"raw-loader": "^0.5.1",
"source-map-support": "^0.5.0",
"start-server-webpack-plugin": "^2.2.0",
"webpack": "^4.5.0",
"webpack-cli": "^2.0.14",
"webpack-node-externals": "^1.6.0"
}
}
The modules should look familiar.. if not, as we proceed, there usefulness would be revealed.
"scripts": {
"start": "webpack --colors --progress",
}
we have two custom scripts .. (start and test) . yarn start runs the custom script (start) with webpack using two arguments (colors and progress). The colors argument makes the output colorful while the progress arguments shows the percentage of file bundling.
Lets install the dependencies and run the project.
yarn install && start
Did you notice the folder dist created based on what we configured in webpack ? The dist folder contains all the bundled scripts.
Lastly, lets run the test script even though we are yet to write any test.
"scripts": {
"test:unit": NODE_ENV=testing rm -rf ./tmp/mocha-webpack && mocha- webpack --webpack-config webpack.testing.js \"src/**/*.test.js\" --timeout 10000 --require source-map-support/register","test": "yarn run test:unit
}
The above run the test when time ≤10000sec, look for any file that ends with *.test.js using webpack.
Obviously, no test has been written. So number of test pass would definitely be zero.