Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Second review of gpii.express module... #2

Merged
merged 40 commits into from
Apr 7, 2015
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
66accec
GPII-1099: Simplified router and express lifecycle somewhat based on…
the-t-in-rtf Feb 20, 2015
787726e
Merge branch 'master' of https://github.com/the-t-in-rtf/gpii-express
the-t-in-rtf Feb 20, 2015
1eb5a28
GPII-1099: Working to test middleware isolation. Removed req.session…
the-t-in-rtf Feb 20, 2015
af256b2
GPII-1099: Refactored to enable clean nesting of routers while preser…
the-t-in-rtf Feb 23, 2015
2c313ef
GPII-1099: Attempted to rewrite tests using a fluid testCaseHolder an…
the-t-in-rtf Feb 23, 2015
2ad3810
Improved handling when gpii.express is itself nested, and added tests…
the-t-in-rtf Feb 23, 2015
7ede267
Added model relay to the gradeNames.
the-t-in-rtf Feb 24, 2015
32bd6d5
Added support for method-specific routers (you can only support req.p…
the-t-in-rtf Feb 24, 2015
eccf996
Added tests for parameter handling and options to control the method.…
the-t-in-rtf Feb 24, 2015
75217b2
Added index.js files per feedback from Antranig.
the-t-in-rtf Feb 26, 2015
c233d60
Added standard grunt configuration per feedback from Antranig.
the-t-in-rtf Feb 26, 2015
7ce82ca
Cleaned up all errors reported by JSHint. Also completed conversion …
the-t-in-rtf Feb 26, 2015
6916da0
Completed test refactor for gpii.express module per feedback from Ant…
the-t-in-rtf Feb 26, 2015
ec72860
Updated grunt-gpii dependency to fix bug with dedupe-infusion.
the-t-in-rtf Feb 27, 2015
c2b4919
Added safety check for poorly-wired nested modules.
the-t-in-rtf Mar 3, 2015
60aa344
Moved kettle to dev dependencies.
the-t-in-rtf Mar 3, 2015
e441828
Removed old "shutdown" cruft from the tests.
the-t-in-rtf Mar 17, 2015
51c98b0
Vastly expanded documentation per feedback from the pull request.
the-t-in-rtf Mar 17, 2015
3162ebe
Standardized all "router" and "middleware" invokers to use `getMiddle…
the-t-in-rtf Mar 18, 2015
3aeeabf
Cleaned up unused arguments in cookie parser middleware per pull requ…
the-t-in-rtf Mar 18, 2015
1b21fb9
Converted from using `throw()` to using `fluid.fail()` per feedback f…
the-t-in-rtf Mar 18, 2015
4048333
Replaced calls to `console.log()` with calls to `fluid.log()` per fee…
the-t-in-rtf Mar 18, 2015
12878ab
Renamed `stopped` and `started` events to `onStopped` and `onStarted`…
the-t-in-rtf Mar 18, 2015
e568bc0
Added `that` as a second argument when starting the server, per pull…
the-t-in-rtf Mar 18, 2015
898bb4f
Removed unneeded "model relay" grade per feedback from pull request.
the-t-in-rtf Mar 18, 2015
f813485
Explicitly enabled `whitespace` check in `.jshintrc` and fixed the er…
the-t-in-rtf Mar 18, 2015
1dd5e89
Collapsed `components.options.members.variable` calls down to `compon…
the-t-in-rtf Mar 18, 2015
d0e9812
Removed previous `model` cruft and simplified the `gradeNames` as well.
the-t-in-rtf Mar 18, 2015
b519858
Renamed variables in `connectDirectDescendants` per feedback from pul…
the-t-in-rtf Mar 18, 2015
8c47e6d
Namespaced `onDestroy` handler and removed unneeded arrays from liste…
the-t-in-rtf Mar 18, 2015
436b2cc
Added local `port` variable to improve readability of express initial…
the-t-in-rtf Mar 18, 2015
e4fe4c9
Consolidated all "content checking" functions into a single function …
the-t-in-rtf Mar 18, 2015
419393c
Committed work in progress on refactor to get feedback from Antranig.
the-t-in-rtf Mar 18, 2015
eb1c7ab
Moved `isSaneResponse` to its own helper module that can be reused el…
duhrer Mar 31, 2015
f5cc8f7
Updated dependencies (while troubleshooting unrelated problems) and f…
duhrer Mar 31, 2015
6743708
Migrated from using `fluid.log` to `fluid.fail` when errors are encou…
duhrer Mar 31, 2015
0afec7d
Fixed whitespacing.
duhrer Mar 31, 2015
c579105
Moved `isSaneResponse` to its own helper module that can be reused el…
duhrer Mar 31, 2015
dbb1f38
Moved `fluid.modelRelayComponent` grade to just the test middleware t…
duhrer Mar 31, 2015
d2b57d7
Updated testCaseHolder to wire in common "setup" steps to all test se…
duhrer Apr 7, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"unused": true,
"strict": true,
"trailing": true,
"white": true,

"maxerr": 1000,

Expand Down
23 changes: 23 additions & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use strict";

module.exports = function (grunt) {

grunt.initConfig({
jshint: {
src: ["src/**/*.js", "tests/**/*.js"],
buildScripts: ["Gruntfile.js"],
options: {
jshintrc: true
}
},
jsonlint: {
src: ["src/**/*.json", "tests/**/*.json"]
}
});

grunt.loadNpmTasks("grunt-contrib-jshint");
grunt.loadNpmTasks("grunt-jsonlint");
grunt.loadNpmTasks("grunt-shell");
grunt.loadNpmTasks("grunt-gpii");

};
111 changes: 109 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,109 @@
# gpii-express
A fluid module to load express.js
# What is this?

This package provides a series of a [Fluid components](https://github.com/fluid-project/infusion-docs/blob/master/src/documents/UnderstandingInfusionComponents.md) that encapsulates the main features of [Express](http://expressjs.com/). Express is a node-based server framework written in Javascript.

In addition to Express itself, this package provides components that act as:

1. Routers (things that respond to requests for a given path).
2. Middleware (things that manipulate the request or response, such as parsing cookie headers)

## About routers

Routers are designed to work with an Express `request` object, and eventually return a `response` object to the client. Only one router will ever respond to a single request. To determine which router to use, each router registers itself for a particular `path`.

Routers can be nested, and you can even nest an instance of a module within itself. The `path` variable for a given router module is combined with the paths of its parents, and that ultimately determines which URLs a given router will be asked to handle. For complex examples, see the tests included with this package.

One of the key strengths of Express 4.x and higher is that routers are self-contained bubbles that can use different middleware than any other router, or Express itself. This is incredibly important when working with even the most common third-party modules for Express. There are often modules that must have a particular piece of middleware, and other modules that do not work at all if that middleware is available. Routers can either inherit middleware from their parent, or can have their own middleware as needed.


## About middleware

Middleware is given access to the same `request` and `response` objects by Express. Middleware can both read and update the request object.

Middleware is called before any router is allowed to respond. Many middleware modules may be in use at the same time, and they are called in the order in which they are added to their parent object (Express itself or a router). The order in which they are called can be significant. As an example, the session middleware provided by Express will only work if the cookie parsing middleware provided by Express has already been loaded.

Middleware is visible to its container (`gpii.express` or a `gpii.express.router` module) and any of its container's child `gpii.express.router` modules.


# Why would I need it?

This module allows you to wire together fluid components to serve up APIs and static content. Simple server-side use cases can be implemented purely by configuring the components provided here.

# How is this different from Kettle?

[Kettle](https://github.com/GPII/kettle) is a server side framework written entirely as a series of Fluid components, and used extensively within the GPII. Kettle serves a wider range of use cases, and provides deeper options for replacing the internals of the server.

This module, by comparison, works very much in the way that Express works. It uses the native request and response objects provided by that framework. In other words, this module is completely dependent on Express and is only ever likely to work like Express does.

# How do I use it?

To use this module, you will need to instantiate an instance of `gpii.express` itself (or something that extends it), and wire in at least one `gpii.express.router` module. The most basic example (serving static content) should look something like:

```
var path = require("path");
var contentDir = path.resolve(__dirname, "./content");
gpii.express(
{ // instance of component under test
createOnEvent: "constructServer",
type: "gpii.express",
options: {
events: {
started: "{testEnvironment}.events.started"
},
config: {
express: {
port: 80808,
baseUrl: "http://localhost:80808"
}
},
components: {
staticRouter: {
type: "gpii.express.router.static",
options: {
path: "/",
content: contentDir
}
}
}
}
}
)
```

As you can see, you are expected to have a `config.express` option that includes at least a `port` and `baseUrl` setting.

In this case, we also configure a "static" router that is designed to serve up filesystem content (see ["Static Router Module"](#static-router-module) for more details).

## Common Middleware

This package provides predefined wrappers for common Express middleware, including:

1. `gpii.express.middleware.cookieparser`: Parses client cookie headers and makes them available as part of the `request` object, via the `request.cookies` object.
2. `gpii.express.middleware.session`: Parses client session cookies makes server-side session data associated with the cookie available as part of the `request` object, via the `request.sesssion` object.
3. `gpii.express.middleware.urlencoded`: Parses URL encoded data passed by the client and makes it available as part of the `request` object, via the `request.query` object.
4. `gpii.express.middleware.json`: Parses JSON data passed by the client and makes it available as part of the `request` object, via the `request.body` object.

For more information on any of these, look at their corresponding modules documentation in the [Express API Documentation](http://expressjs.com/4x/api.html#request). For examples of their usage, check out the tests included with this package.

## Writing your own middleware component

This package provides the abstract `gpii.express.middleware` gradeName that all middleware should extend. At a minimum, a valid implementation must replace the default `getMiddleware` invoker.

For examples, check out the middleware modules included in the tests for this package.

## Static Router Module

This package provides the `gpii.express.router.static` module, a wrapper for the [static router built into Express](http://expressjs.com/guide/using-middleware.html#middleware.built-in).

All router modules are expected to provide a `path` option that will be used to configure which URLs they will listen to. This path follows the same conventions as the [`app.use`](http://expressjs.com/4x/api.html#app.use) method provided by the Express framework. Notably:

1. Paths are relative to their container.
2. Paths can contain wildcards, as in

As demonstrated in the example above, this module expects to work with a full filesystem path containing content. You can use an expander, injection, string templates, or any other means to provide this information as long as a full path is eventually available.

## Writing your own router component

This package provides the abstract `gpii.express.router` gradeName that all routers should extend. At a minimum, a valid implementation must override the default `getRouter` invoker.

For examples, check out the router modules included in the tests for this package.
25 changes: 25 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// A convenience file to allow you to `require` all of the components defined in this module.

// `gpii.express`, a component for express itself
require("./src/js/express");

// `gpii.express.middleware`, the base grade for all middleware components
require("./src/js/middleware");

// A middleware component to add support for cookies
require("./src/js/cookieparser");

// A middleware component to add support for sessions (requires cookie support)
require("./src/js/session");

// A middleware component to add support for handling JSON data in POST requests, etc.
require("./src/js/json");

// A middleware component to add support for URL encoding of variables
require("./src/js/urlencoded");

// `gpii.express.router`, the base grade for all router components
require("./src/js/router");

// A router module to handle static content. Wraps the built-in `express.static()` module.
require("./src/js/static");
12 changes: 9 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@
"express": "4.10.6",
"infusion": "git://github.com/fluid-project/infusion.git#605b0bcfaedf6193c31456236d3aa4e42cf36a96"
},
"devDependencies": {
"jqUnit": "git://github.com/fluid-project/node-jqUnit.git#e9bf72445bd343a4f3aabe3ba96a1087d3498612",
"request": "2.51.0"
"devDependencies": {
"grunt": "~0.4.4",
"grunt-shell": "0.6.4",
"grunt-contrib-jshint": "~0.9.0",
"grunt-jsonlint": "1.0.4",
"grunt-gpii": "git://github.com/GPII/grunt-gpii.git#58ae055833f437a9e91baedb9f39a22c5fdd727f",
"jqUnit": "git://github.com/fluid-project/node-jqUnit.git#e9bf72445bd343a4f3aabe3ba96a1087d3498612",
"kettle": "git://github.com/fluid-project/kettle.git#e79bb81196df68c97eaa9f96c485a4321b69af75",
"request": "2.51.0"
}
}
20 changes: 6 additions & 14 deletions src/js/cookieparser.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,20 @@
// Module to add body parsing to express.
"use strict";
var fluid = fluid || require('infusion');
var fluid = fluid || require("infusion");
var gpii = fluid.registerNamespace("gpii");
fluid.registerNamespace("gpii.express.middleware.cookieparser");

var cp = require('cookie-parser');
var cp = require("cookie-parser");

gpii.express.middleware.cookieparser.cookieparser = function(that, req, res, next) {
if (!that.privateCookieParser) {
that.privateCookieParser = cp();
}

that.privateCookieParser(req, res, next);
gpii.express.middleware.cookieparser.getMiddleware = function () {
return cp();
};

fluid.defaults("gpii.express.middleware.cookieparser", {
gradeNames: ["fluid.standardRelayComponent", "gpii.express.middleware", "autoInit"],
model: {
middleware: ["cookieparser"]
},
invokers: {
"cookieparser": {
funcName: "gpii.express.middleware.cookieparser.cookieparser",
"args": [ "{that}", "{arguments}.0", "{arguments}.1", "{arguments}.2"]
"getMiddleware": {
funcName: "gpii.express.middleware.cookieparser.getMiddleware"
}
}
});
Loading