From 0321ed29925cc0c334eeb3ded19f3343addff56e Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Thu, 24 Jan 2019 18:55:12 +0000 Subject: [PATCH 1/4] updated lab sheet --- 01 Setup.md | 4 ++-- exercises/10_auth/simple/index.js | 36 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 exercises/10_auth/simple/index.js diff --git a/01 Setup.md b/01 Setup.md index 7986b5c..34ee822 100644 --- a/01 Setup.md +++ b/01 Setup.md @@ -139,12 +139,12 @@ Once the web server is up and running you access the page by pointing the browse As we develop more complex web apps it becomes more and more difficult to fully test our app every time we change the code. By not testing everything at regular intervals there is an increasing chance that our new code could break the existing code in our system. Since regular testing is a chore, programmers have developed ways to automate this process. -In this section you will be given a sneak preview of how an automated test suite works. We will be using a testing framework developed by Facebook, called [Jest](https://jestjs.io) and will be using a second tool called [Supertest](https://github.com/visionmedia/supertest#readme) which allows us to interact with our code using http. +In this section you will be given a sneak preview of how an automated test suite works. We will be using a testing framework developed by Facebook, called [Jest](https://jestjs.io) and will be using a second tool called [Supertest](https://github.com/visionmedia/supertest#readme) which allows us to interact with our code using http. Rather than using the status code numbers in our tests we will use a module called [http-status-codes](https://www.npmjs.com/package/http-status-codes) to display these as human-readable strings. The process requires you to install both these packages and then run the `jest` command: ```shell -$ npm install jest supertest +$ npm install jest supertest http-status-codes $ ./node_modules/.bin/jest PASS .test/index.test.js GET / diff --git a/exercises/10_auth/simple/index.js b/exercises/10_auth/simple/index.js new file mode 100644 index 0000000..47b3381 --- /dev/null +++ b/exercises/10_auth/simple/index.js @@ -0,0 +1,36 @@ + +'use strict' + +const Router = require('koa-router') +const auth = require('koa-simple-auth') +const koaBody = require('koa-body')() +const router = module.exports = new Router() + +const catch_api_error = async ctx => { + try{ + yield next + } catch(err){ + this.body = JSON.stringify({ 'error': err.message }) + } +} + +router.post('/login', + catch_api_error, + koaBody, + auth.login, + function *() { + this.body = JSON.stringify({ authenticated: true }) + } +) + +router.post('/register', catch_api_error, koaBody, auth.register, function *() { + this.body = JSON.stringify({ authenticated: true }) +}) + +router.get('/unregister', catch_api_error, koaBody, auth.unregister, function *() { + this.body = JSON.stringify({ authenticated: false }) +}) + +router.get('/logout', auth.logout, function *() { + this.body = JSON.stringify({ authenticated: false }) +}) From 7e1810e94825770600c96c289d15ef27093d5500 Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Wed, 30 Jan 2019 19:50:35 +0000 Subject: [PATCH 2/4] fixed body parser --- exercises/01_http/01_url/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/exercises/01_http/01_url/index.js b/exercises/01_http/01_url/index.js index 8ed166b..ef915ea 100644 --- a/exercises/01_http/01_url/index.js +++ b/exercises/01_http/01_url/index.js @@ -9,9 +9,9 @@ const js2xmlparser = require('js2xmlparser') /* CONFIGURING THE MIDDLEWARE */ const app = new Koa() +app.use(bodyParser()) const router = new Router() app.use(router.routes()) -app.use(bodyParser()) app.use(staticFiles('./public')) /* GLOBAL VARIABLES */ @@ -45,6 +45,7 @@ router.get('/hello/:name', ctx => { router.post('/form', ctx => { const minLength = 3 + console.log(ctx.request.body) const body = ctx.request.body if(body.lastname.length >= minLength) { names.push( { firstname: body.firstname, lastname: body.lastname } ) @@ -54,6 +55,7 @@ router.post('/form', ctx => { ctx.status = 422 ctx.body = 'invalid lastname' } + //ctx.body = 'form processed' }) router.get('/names', ctx => { From 16211ac43f08ed128532c67dc02bc1edaadb7530 Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Thu, 31 Jan 2019 19:24:27 +0000 Subject: [PATCH 3/4] fixed some issues in lab notes --- 01a The HTTP Protocol.md | 13 ++++++++----- 02 Learning HTML5.md | 14 +++++++------- exercises/02_html/03_hypermedia/index.js | 1 - 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/01a The HTTP Protocol.md b/01a The HTTP Protocol.md index 6c80022..bb8030c 100644 --- a/01a The HTTP Protocol.md +++ b/01a The HTTP Protocol.md @@ -34,9 +34,9 @@ We will be working through some exercises that make use of all of these. Start the server: -1. Open the terminal (on Windows this is called the bash shell). -2. Navigate to the `exercises/01_http/` directory. -3. Install the dependencies using 1. `npm install koa koa-router koa-bodyparser koa-static js2xmlparser`. +1. Open the terminal. +2. Navigate to the `exercises/01_http/01_url/` directory. +3. Install the dependencies using `npm install koa koa-router koa-bodyparser koa-static js2xmlparser`. 4. Start the server using `node index.js` 5. Access the root url, notice that the message **Hello World** is displayed in the browser. 6. Access the `/hello` url. This should result in the same message being displayed. @@ -108,7 +108,7 @@ In this section you will learn about a number of JavaScript functions. In each c 1. Modify the route to add a second parameter called `index2`. 2. Make sure this is triggered by restarting the server and accessing this by passing a second parameter. 3. Modify the script to print out both book titles. -3. Next you need to add some validation to make sure the script does not crash: +3. Next you need to add some validation to make sure the script does not crash (note that if you are using GoormIDE you will not be able to test it): 1. If the index in the URL exceeds to number of books in the array you get an error. Insert an [`if...else` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) that sends a suitable message to the browser if the index number in the URL is too high. 2. The index must be a number. Use the [`isNaN()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN) to check and send a suitable message to the browser if it is not. if it is, use the [`parseInt()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt) to convert it to a number. 3. The number needs to be a whole number (integer). All JavaScript numbers are objects and have a number of useful functions. Use the [`Number.isInteger()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger) to check it is indeed an integer. Send a suitable message to the browser if it is not. @@ -135,7 +135,10 @@ Open the `index.js` file. The route is between lines 37-43. 1. Modify the route so that if the `format` query string is set to `lower` the name is set as [lowercase](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase). 2. Add a second query string called `reverse`: 1. if missing or set to `false` the text is left alone. - 2. If it has a value of `true` the text should be reversed by using the [`split()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split) to convert the string to an array of characters and then the [`join()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join) to convert the array back into a string. + 2. If it has a value of `true` the text should be reversed. You will need to use the following JavaScript functions, read the documentation carefully before trying to complete the task: + 1. You will need to use the [`split()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split) to convert the string to an array of characters. + 2. Then you will need to use the [Array.reverse()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) function to reverse the array indexes. + 3. Finally the [`join()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join) to convert the array back into a string. ### 1.4 Request Headers diff --git a/02 Learning HTML5.md b/02 Learning HTML5.md index 50b6aa4..1f27f58 100644 --- a/02 Learning HTML5.md +++ b/02 Learning HTML5.md @@ -1,7 +1,7 @@ # Learning HTML5 -The worksheet is based on the materials from the HTML lecture and you should refer to the [slide deck](https://goo.gl/DGFkr6) to help your understanding. It will take approximately **15 hours** to work through all the exercises and you should ensure that you have completed them all before attempting subsequent worksheets. +The worksheet is based on the materials from the HTML lecture and you should refer to the [slide deck](https://drive.google.com/open?id=1-kA3w6-H7AkW5iWRG2D1O-soxAnHgnU0YgOH3eYfeAQ) to help your understanding. It will take approximately **15 hours** to work through all the exercises and you should ensure that you have completed them all before attempting subsequent worksheets. Before you start you need to download and new materials. To do this you will be carrying out three tasks: @@ -41,7 +41,7 @@ You should get into the habit of doing this each time you sit down to work on yo ## 1 Syntax -Lets take a look at some basic HTML syntax. Start by locating the `exercises/03_html/01_syntax/` directory. Navigate to this using the SSH Terminal, install the `express` package and start the web server. If you navigate to the base route `/` you will see a screen full of text. +Lets take a look at some basic HTML syntax. Start by locating the `exercises/02_html/01_syntax/` directory. Navigate to this using the SSH Terminal, install the all the necessary `koa` packages and start the web server. If you navigate to the base route `/` you will see a screen full of text. ![the unformatted text](exercises/.images/chrome_07.png) @@ -58,7 +58,7 @@ As you work, save the html file and refresh the browser, you don't need to resta ## 2 Lists -Now you have mastered the basics of html its time to move on to how it can be used to render lists of different types. Start by locating the files in the `exercises/03_html/02_lists/` directory. Now start the Express server and view the root URL `/`. This should display a simple page with the title **1980's Home Computers**. +Now you have mastered the basics of html its time to move on to how it can be used to render lists of different types. Start by locating the files in the `exercises/02_html/02_lists/` directory. Now install the necessary packages, start the `koa` server and view the root URL `/`. This should display a simple page with the title **1980's Home Computers**. Now, add a list on your web page. Insert the following lines of code after the paragraph describing clever uses for home computers: @@ -110,11 +110,11 @@ Now you have mastered the basics of HTML markup we will look at one of the most ### 3.1 Routes -Every resource on the WWW (such as html documents and images) has a unique URL and so when we design our website we need to define these. In a website built using _NodeJS_ and _Express_ these are known as **routes**. Start by locating the `exercises/03_html/02_hypermedia/` directory. Start the web server and opening the `index.js` file. +Every resource on the WWW (such as html documents and images) has a unique URL and so when we design our website we need to define these. In a website built using _NodeJS_ and _Koa_ these are known as **routes**. Start by locating the `exercises/02_html/03_hypermedia/` directory. Start the web server and open the `index.js` file. 1. Some resources need to be directly accessible in the web browser (they are accessed either directly or loaded by the html web page). These need to have their own directly accessible URL. 1. One directory needs to be specified as being publicly available. In this example we have created a directory called `public/` - 2. Express needs to make this directory public. This is achieved on line by importing a static module and using this to specify the public directory. + 2. Koa needs to make this directory public. This is achieved on line by importing a static module and using this to specify the public directory. 3. assuming the server is running you can directly view the image using the URL `http://xxx:8080/paradox.jpeg`, remembering to substitute your server's URL. 2. Some resources are _virtual_ and are generated by a script running on the server before being sent back to the browser client. 1. There are some simple examples in `index.js`. Both the `/` and `/paradoxes` routes trigger scripts that take the contents of html files and send this back to the browser. @@ -128,7 +128,7 @@ Every resource on the WWW (such as html documents and images) has a unique URL a ### 3.2 Hyperlinks -Now you understand the concept of URLs representing resources and how this relates to _routes_, it is time to start linking resources together. With the Express server running access the `/commodore` URL which should display a web page describing the **Commodore 64 home computer** +Now you understand the concept of URLs representing resources and how this relates to _routes_, it is time to start linking resources together. With the server running access the `/commodore` URL which should display a web page describing the **Commodore 64 home computer** Add a link to the appropriate Wikipedia article to this web page, in a suitable location directly inside the `body` element: @@ -136,7 +136,7 @@ Add a link to the appropriate Wikipedia article to this web page, in a suitable

Read the Wikipedia article for Retrocomputing.

``` -To test the functionality in your browser you will need to make sure the Express server is running and navigate to the correct URL. +To test the functionality in your browser you will need to make sure the server is running and navigate to the correct URL. A link, defined by the `a` element contains the URL of the linked web page as its `href` attribute. The link above contains an absolute path to a document on the external server. The absolute path begins will full protocol identifier and domain name. diff --git a/exercises/02_html/03_hypermedia/index.js b/exercises/02_html/03_hypermedia/index.js index f04dec4..a56923c 100644 --- a/exercises/02_html/03_hypermedia/index.js +++ b/exercises/02_html/03_hypermedia/index.js @@ -13,7 +13,6 @@ app.use(views(`${__dirname}/views`, { extension: 'html' }, {map: { handlebars: ' router.get('/', async ctx => await ctx.render('index')) router.get('/commodore', async ctx => ctx.render('commodore64')) router.get('/paradoxes', async ctx => ctx.render('paradoxes')) -router.get('/cathedral', async ctx => ctx.render('cathedral')) router.get('/date', async ctx => { const today = new Date() From 4b6ef2012142ed486b37f8bc713c51d1d5f7af1e Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Sun, 10 Feb 2019 20:57:08 +0000 Subject: [PATCH 4/4] started koa lab --- 04 Intro to Koa.md | 105 ++++++++++++-------- exercises/04_koa/index.js | 18 ++++ exercises/04_koa/package.json | 27 +++++ exercises/04_koa/public/css/hello.css | 4 + exercises/04_koa/public/images/computer.png | Bin 0 -> 11317 bytes exercises/04_koa/views/hello.html | 16 +++ 6 files changed, 126 insertions(+), 44 deletions(-) mode change 100644 => 100755 exercises/04_koa/index.js create mode 100644 exercises/04_koa/package.json create mode 100644 exercises/04_koa/public/css/hello.css create mode 100644 exercises/04_koa/public/images/computer.png create mode 100644 exercises/04_koa/views/hello.html diff --git a/04 Intro to Koa.md b/04 Intro to Koa.md index 23ef88a..6d8f584 100644 --- a/04 Intro to Koa.md +++ b/04 Intro to Koa.md @@ -58,19 +58,53 @@ Use the terminal tool to access the `exercises/06_routing/` directory and ope We will be using the [Koa](https://koajs.com) framework as our web server in this module. Koa was designed by the team who created the [Express Framework](https://expressjs.com) which was one of the first mainstream web servers to use the JavaSscript language. Almost all the online tutorials cover the use of Express so why have we chosen not to use this? -**TODO: why use koa** +The Express framework has grown over the years and contains a lot of functionaity that we won't need. Koa has the opposite philosophy. It’s a minimalist framework where all the functionality is aplit into smaller modules that can be imported when needed. +. +Koa is Express 5.0 in spirit; it’s by the same people that created Express, and the authors changed the name to avoid upsetting people because of the backwards incompatible changes (which also happened in the Express 3 to Express 4 transition). -Study the `index.js` script in the `exercises/02_http/01_url/` directory. +The only issue is that there was a big change from Koa v1 to Koa v2 and the older tutorials are therefore of no use. We will focus on using the latest version of Koa, currently 2.7 at the time of writing. Lets take an in-depth look at a script which should be familiar to you to understand how the web server works. + +### 2.1 The Manifest + +A correctly-configured NodeJS application includes a special _manifest_ file called `package.json`. You will find one in the `exercises/04_koa/` directory. This contains important _metadata_ about the application. If you open this you will notice it contains a [JSON string](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON) which includes a number of [keys](https://nodesource.com/blog/the-basics-of-package-json-in-node-js-and-npm/): + +1. The `name` key contains the name of the application, in this case `koa-intro`. +2. Underneath this you will find the version number and a brief description of the software. +3. The `main` key defined the entry point to the application (the script that should be run). +4. Next are _script aliases_, shortcuts to run different commands. In our example we have a `test` alias that is used to trigger the jest testing tool and a `server` alias to start the server. +5. After the `scripts` key you will notice a `jest` key that contains the configuration options for the [Jest](https://jestjs.io) testing tools. +6. Next we have the author and licence fields. +7. Finally the manifest list the packages needed for the application to run: + 1. The `dependencies` key contains all the packages needed to run the application such as `koa` and its plugins. + 2. The `devDependencies` key lists all the extra packages needed when developing the application but not needed by the app itself such as the testing tools. + +To see how the manifest can help us with running an application: + +1. Navigate to the `exercises/04_koa/` directory using terminal. +2. Use the `npm install --production` command to install all the packages needed to run the application (no development tools). +3. Use the `npm run server` to trigger the `server` alias. +4. Try using `npm run test` to run the test suite, notice that the `jest` command is no currently installed. +5. Run `npm install` to install the developer tools (it won't' install the production modules because these are already installed). +6. Now you can run the test suite. + +### 2.2 The Routing File + +Study the `index.js` script in the `exercises/04_koa/` directory. 1. The first line is the _shebang_, it tells the script what application is needed to run it. If the file is _executable_ you can simply call this without using the node command like this: `./index.js` instead of `node index.js`. -2. If you study lines 4-10 of `index.js` you will see a list of the modules we need to install. -3. Lines 4-10 import the module packages we need for our script to work. Koa is a modular framework, on its own it does very little but depends on plugins (middleware) for its functionality. -4. Lines 11-15 are where we configure the koa _middleware_. -5. We need two global variables in our script, one to store a list of items and the second to store the port number we will be using: - 1. The `let` keyword defines a _mutable variable_ which can change its value. - 2. The `const` keyword defines an _immutable variable_. Once a value is assigned it cannot be changed, these are sometime called _constants_. +2. Lines 3-6 are where we import all the modules we are going to be using. +3. Lines 8-12 are where we create instances of the `koa` and `router` objects and configure the plugins (known as the _middleware_). +4. Next we define any global variables and constants. In this script we store the port number as a constant. 6. The main part of the script defines the _routes_ and we will be covering these in more detail as we progress through the lab. -7. Right at the end (line 123) we start the server on the defined port and _export_ the _koa object_ `app`. By exporting it we can import the script into our automated test suite (briefly covered in the previous lab). +7. Right at the end we start the server on the defined port and _export_ the _koa object_ `app`. By exporting it we can import the script into our automated test suite (briefly covered in the previous lab). + +### 2.2.1 Test Your Understanding + +Lets start with a quick refresher: + +1. Create a new route called `/test` and create a file called `mytest.html` containing a valid HTML5 web page that displays your name in the `views/` directory. Restart the server and make sure the page displays. +2. Create a new CSS3 stylesheet called `test.css` in the `css/` directory in the `public/` directory. Link it to your new page and change the font face and colour of the text. +3. Find a download a photo of the University, add it to the `images/` directory inside the `public/` directory and make sure you can view this in the browser. -------- @@ -88,6 +122,8 @@ A package manifest is an json-formatted file called `package.json` that is creat The real benefit to having dependencies defined like this in package.json, is that it becomes possible to install the correct versions of all the required packages with a single command. This means that we could use an automated build and deploy tool. +You have probably spotted another file called `package-lock.json`. This contains a list of _all_ packages installed indicating their dependencies plus details of all dependencies. + ### 1.1 Understanding the Manifest Let's look at a simple example. You can find this in the `examples/06_express/todo/` directory. Open the `package.json` file: @@ -106,21 +142,6 @@ Let's look at a simple example. You can find this in the `examples/06_express/to 1. Lets install these packages using `npm install --only=dev`. This will install the `eslint` package. 2. List the locally-installed modules again using `npm list --depth=0` to make sure the package was installed. -You have probably spotted another file called `package-lock.json`. This contains a list of _all_ packages installed indicating their dependencies plus details of all dependencies. - -### 1.2 Creating and Editing the Manifest - -Now we understand the contents of the manifest we will create one from scratch. - -1. Open the SSH Terminal and navigate to the `exercises/06_express/todo/` directory. -2. Delete the current manifest using `rm package.json` and the package lock file using `rm package-lock.json`. -3. Delete the `node_modules/` directory using `rm -rf node_modules` -4. Run the manifest wizard using `npm init` and choose the default options by pressing enter for each question. This will create a new `package.json` file. -5. Install the `express` package using `npm install --save express`. The `--save` flag adds the package to the manifest file in the `dependencies` object. -6. Install the `eslint` package using `npm install --save-dev eslint`. The `--save-dev` flag adds the package to the manifest file in the `devDependencies` object. -7. Open the `package.json` and check that these two packages are listed. -8. add a `hello` object to the `scripts` object and set its value to `"echo HelloWorld!"`. - ## 2 Routing 1. Start by locating the `exercises/06_express/todo/` directory and locate the `index.js` file. This is the routing file used by the express web server. @@ -138,45 +159,41 @@ Now we understand the contents of the manifest we will create one from scratch. ### 2.1 Routes -Every _request_ sent from the client is handled by a route. The server compares the requested HTTP method and route against the strings passed as the first parameter until it finds a match. If there are no routes that match the specific URL the express server will repond with a `404 NOT FOUND` response. - -When a match is found, the server runs the _callback_ (anonymous function) that has been supplied as the second parameter. This function takes three parameters: +Every _request_ sent from the client is handled by a route. The server compares the requested HTTP method and route against the strings passed as the first parameter until it finds a match. If there are no routes that match the specific URL the koa server will repond with a `404 NOT FOUND` response. -1. A `request` object that contains all the data passed as part of the HTTP request headers. -2. A `response` object that will contain the data to be returned the the client as part of the response. -3. A `body` object that contains the string passed as the _request body_. +When a match is found, the server runs the _callback_ (anonymous function) that has been supplied as the second parameter. This function takes a single `ctx` parameter which is an object that contains all the data from both the request and response (the _context_). ```javascript -app.get('/test', (req, res, body) { +app.get('/test', ctx => { // code goes here }) ``` -use the todo/ example +---------- ### 2.2 The Request Object -The `request` object that contains all the data passed as part of the HTTP request headers and body. it contains all the information from these headers, in particular, given the request: +The `ctx` parameter contains a `request` object (`ctx.request`) that contains all the data passed as part of the HTTP request headers and body. it contains all the information from these headers, in particular, given the request: ``` http://www.example.com/hello/mark?gender=male ``` -| Object | Contains | Example | -| -------------- | --------------------- | ----------------- | -| `req.query` | The querystring | `gender=male` | -| `req.body` | The request body | - | -| `req.hostname` | The server hostname | `www` | -| `req.baseUrl` | The base URL | `www.example.com` | -| `req.path` | The route | `/hello/mark` | -| `req.ip` | The server IP address | `192.168.0.1` | -| `req.params` | The parameters | `/mark` | +| Object | Contains | Example | +| ---------------------- | --------------------- | ----------------- | +| `ctx.request.query` | The querystring | `gender=male` | +| `ctx.request.body` | The request body | - | +| `ctx.request.hostname` | The server hostname | `www` | +| `ctx.request.baseUrl` | The base URL | `www.example.com` | +| `ctx.request.path` | The route | `/hello/mark` | +| `ctx.request.ip` | The server IP address | `192.168.0.1` | +| `ctx.request.params` | The parameters | `/mark` | -req.accepts(types) Checks if the specified content types are acceptable, based on the request’s Accept HTTP header field. The method returns the best match, or if none of the specified content types is acceptable, returns false (in which case, the application should respond with 406 "Not Acceptable"). req.accepts('html') +`ctx.request.accepts(types)` Checks if the specified content types are acceptable, based on the request’s Accept HTTP header field. The method returns the best match, or if none of the specified content types is acceptable, returns false (in which case, the application should respond with 406 "Not Acceptable"). req.accepts('html') -req.get(field) Returns the specified HTTP request header field (case-insensitive match). The Referrer and Referer fields are interchangeable. req.get('Content-Type') +`ctx.request.get(field)` Returns the specified HTTP request header field (case-insensitive match). The Referrer and Referer fields are interchangeable. req.get('Content-Type') ### 2.3 The Response Object diff --git a/exercises/04_koa/index.js b/exercises/04_koa/index.js old mode 100644 new mode 100755 index e69de29..d1b1692 --- a/exercises/04_koa/index.js +++ b/exercises/04_koa/index.js @@ -0,0 +1,18 @@ +#!/usr/bin/env node + +const Koa = require('koa') +const Router = require('koa-router') +const views = require('koa-views') +const stat = require('koa-static') + +const app = new Koa() +const router = new Router() +app.use(stat('public')) +app.use(views(`${__dirname}/views`, { extension: 'html' }, {map: { handlebars: 'handlebars' }})) +app.use(router.routes()) + +const port = 8080 + +router.get('/', async ctx => await ctx.render('hello')) + +module.exports = app.listen(port, () => console.log(`listening on port ${port}`)) diff --git a/exercises/04_koa/package.json b/exercises/04_koa/package.json new file mode 100644 index 0000000..2f272fd --- /dev/null +++ b/exercises/04_koa/package.json @@ -0,0 +1,27 @@ +{ + "name": "koa-intro", + "version": "1.0.0", + "description": "Simple Koa Web App", + "main": "index.js", + "scripts": { + "server": "node index.js", + "test": "./node_modules/.bin/jest" + }, + "jest": { + "testEnvironment": "node", + "verbose": true + }, + "author": "Mark Tyers", + "license": "ISC", + "dependencies": { + "http-status-codes": "^1.3.0", + "koa": "^2.7.0", + "koa-router": "^7.4.0", + "koa-static": "^5.0.0", + "koa-views": "^6.1.5" + }, + "devDependencies": { + "jest": "^24.1.0", + "supertest": "^3.4.2" + } +} diff --git a/exercises/04_koa/public/css/hello.css b/exercises/04_koa/public/css/hello.css new file mode 100644 index 0000000..fb0e5d2 --- /dev/null +++ b/exercises/04_koa/public/css/hello.css @@ -0,0 +1,4 @@ + +h1 { + color: red; +} \ No newline at end of file diff --git a/exercises/04_koa/public/images/computer.png b/exercises/04_koa/public/images/computer.png new file mode 100644 index 0000000000000000000000000000000000000000..b71ac3893bedc1e1ced90b612c237eadc47d1a7b GIT binary patch literal 11317 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 bw=CR4349w?_#D8fFP55;wqmWkb>#m8CmO9U literal 0 HcmV?d00001 diff --git a/exercises/04_koa/views/hello.html b/exercises/04_koa/views/hello.html new file mode 100644 index 0000000..06cab1b --- /dev/null +++ b/exercises/04_koa/views/hello.html @@ -0,0 +1,16 @@ + + + + + + + Let's see CSS at Work + + + + + +

Hello CSS!

+

Use this file to see how CSS can be used to change the appearance of a web page.

+ + \ No newline at end of file