If you have any questions or suggestions, just send me an e-mail. If you find any bugs, please create an issue in this repository. Pull requests are also welcome.
This project is aimed at implementing a simple http server using koa.js. In The Node Beginner Book, a similar server was implemented without any frameworks.
In the following sections, the development of this project is illustrated step by step.
Initialization
Dependencies
First, all basic dependencies need to be installed, e.g., node, npm (or yarn). As I am using MacOS, I have installed all the prerequisites via homebrew:
# Install node and yarn# If you want to use npm, you can install node only, which includes npm
brew install node yarn
I personally prefer yarn to npm as the package manager. If you want to use npm, that is definitely OK.
If you want to switch between different node versions, you can install nvm via brew, and then install different node versions via nvm.
# Install nvm
brew install nvm
# Install different node versions
nvm install 10
nvm install 8
# Select a version to use
nvm use 10
Now you have both node 8 and node 10 installed, while node 10 is being used in the current environment.
Repository initialization
Next, it is time to init a repository. There are numerous scaffolds available, but we are going to build this project from scratch, so no scaffolds will be used.
Note that we do not need to specify index.js in the script, for it has been defined in "main". If you did not specify the entrypoint file during yarn init, then you should specify it in the script.
We are going to follow BDD (Behavior-Driven-Development) in this project. We will use Mocha+Chai as the test framework. These packages should be installed as dev-dependencies. Also, we will use Istanbul to count code coverage.
# Install test-related packages as dev dependencies
yarn add mocha chai chai-http nyc --dev# Create a subfolder for testsmkdir test# Create our first test filetouch test/index.spec.js
We always want our code to be clean and neat. For this purpose, ESLint is the best choice.
# Install ESLint as a dev dependency
yarn add eslint --dev# Interactively configure your rules
node_modules/eslint/bin/eslint.js --init
After that, we can add one more script:
"scripts":{"lint":"eslint *.js test/*.js --fix"}
--fix is used so that style errors will be automatically fixed when we run yarn lint.
To enable ESLint in mocha environment, we need to modify the generated ESLint configuration file (.eslintrc.yml in my case) manually.
env:es6:truenode:truemocha:true
Now we have finished most configurations. In my project, I have also configured codebeat, renovate, codecov, mergify, travis and heroku, so as to empower a full-featured CI/CD flow. These details will not be discussed in this note, but you can refer to the code, or search and read the documentation of each tool mentioned above.
Start a server
As we are going to use the koa framework, we should install the package first.
# Install koa
yarn add koa
We will write the test first.
// test/index.spec.jsconstchai=require("chai");constchaiHttp=require("chai-http");const{server}=require("../index");constexpect=chai.expect;chai.use(chaiHttp);describe("Basic routes",()=>{after(()=>{server.close();});it("should get HOME",done=>{chai.request(server).get("/").end((err,res)=>{expect(res).to.have.status(200);expect(res.text).equal("Hello World");done();});});});
We can then run yarn test , and it will fail doubtlessly for we have not implemented the corresponding functions. We are going to do it now.
Now the route '/' is defined in router.js, and the test should still pass.
Add new routes
The 'POST /upload/text' route is discussed here as an example.
Test goes first.
// test/index.spec.js// ...it("should upload a text",done=>{chai.request(server).post("/upload/text").set("content-type","application/json").send({textLayout:"hello"}).end((err,res)=>{expect(res).to.have.status(200);expect(res.text).equal("You've sent the text: hello");done();});});// ...
Then the implementation:
// router.jsconstroute=router.get("home","/",home).post("upload-text","/upload/text",uploadText);// ...asyncfunctionuploadText(ctx){consttext=ctx.request.body.textLayout;ctx.body=`You've sent the text: ${text}`;}// ...
However, test will fail!
The reason is that a body-parser is needed so that chai-http can work fluently. Here, we will use koa-body, because it supports multipart.