Skip to content

Commit

Permalink
Merge branch 'GPII-2615'
Browse files Browse the repository at this point in the history
* GPII-2615:
  GPII-2615: Revised caveats regarding reuse of the `gpii.schema.handler` grade.
  GPII-2165: Fixed typo.
  GPII-2615: Removed outdated TODONEs...
  GPII-2628: Use released version of gpii-express "global failure handler".
  GPII-2628: Refactored to use gpii-express "global failure handler".
  NOJIRA: Reenabled parser failure tests to assist in troubleshooting issues further.
  GPII-2615:  Refactored "schema link" support.
  GPII-2623: Removed `yarn.lock` file.
  NOJIRA: Added temp chromedriver to path to hopefully fix Travis builds.
  NOJIRA: Updated Travis config (again) to hopefully fix builds that fail because of missing `chromedriver` package.
  NOJIRA: Updated Travis config to hopefully fix builds that fail because of missing `chromedriver` package.
  • Loading branch information
amb26 committed Oct 9, 2017
2 parents 273d18e + 1a5b136 commit bb23e09
Show file tree
Hide file tree
Showing 28 changed files with 628 additions and 3,503 deletions.
17 changes: 11 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
language: node_js
node_js: "6.9.1"
node_js: "6"
addons:
apt:
packages:
- xvfb
- g++-4.8
- gcc-4.8
- xvfb
before_install:
- wget https://chromedriver.storage.googleapis.com/2.32/chromedriver_linux64.zip -O /tmp/chromedriver
- chmod 777 /tmp/chromedriver
- export CHROME_DRIVER_PATH=/tmp/chromedriver
- export PATH=$PATH:/tmp
install:
- sudo apt-get install -y chromedriver
- export DISPLAY=':99.0'
- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
- npm install -g yarn
- yarn install
- npm install
script:
- BROWSERS=chrome yarn test
- BROWSERS=chrome npm test
77 changes: 0 additions & 77 deletions docs/schemaLinkMiddleware.md

This file was deleted.

154 changes: 154 additions & 0 deletions docs/schemaLinks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# JSON Schemas and HTTP headers

When writing REST interfaces, we also commonly return JSON data in response to a request. JSON Schemas can also be
used to provide hints about the output format we are using.

The working group that writes the JSON Schema standard [has outlined two approaches for labeling outgoing responses](http://json-schema.org/latest/json-schema-core.html#anchor33).
Both of these involve setting HTTP headers in the outgoing response, as in:

Content-Type: application/my-media-type+json; profile="http://example.com/my-hyper-schema#"
Link: <http://example.com/my-hyper-schema#>; rel="describedBy"

This package provides two approaches to adding these headers:

1. The "Schema Link Handler" grade describe on this page adds headers for both "success" and "error" messages it fields, and has the option to use a different schema URL for each.
2. The "Schema Link Middleware" grades described on this page add headers for a single schema to all requests they are allowed to process.

# Schema Link Handler

This approach is better suited a wider range of scenarios, for example, when there is a chance that "success" and
"failure" for a given endpoint might be represented by different schemas. A common example would be an endpoint that
returns a set of records when search terms are entered, but which returns an error message when the search terms are
invalid or a server error occurs.

## `gpii.schema.handlerWithSchemaHeaders`

An extension of [`gpii.express.handler`](https://github.com/GPII/gpii-express/blob/master/docs/handler.md) that adds
the HTTP headers when the `sendResponse` or `sendError` invoker is called. This grade only adds headers, it does not
decide what success or failure looks like. It is designed to be overlayed with any existing `gpii.express.handler`
grade that relies on the standard `sendResponse` and `sendError` functions.

If you are already customising these in your handler, you should be careful if you are:

1. Setting the `Content-Type` or `Link` headers yourself.
2. Sending a response yourself using the `response` object's `send` method, in which case this grade's invoker will not have a chance to send the headers.

### Component Options

In addition to the standard available for an instance of
[`gpii.express.handler`](https://github.com/GPII/gpii-express/blob/master/docs/handler.md), this grade supports
the following unique

| Option | Type | Description |
| -------------------- | ---------- | ----------- |
| `schemaUrls` | `{String}` | The URLs to be included in both the `Link` and `Content-Type` headers (see below). |
| `schemaUrls.error` | `{String}` | The JSON Schema to which an error response conforms. |
| `schemaUrls.success` | `{String}` | The JSON Schema to which a successful response conforms. |

### Component Invokers

#### `{that}.sendError(statusCode, body)`
* `statusCode`: The [HTTP status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) associated with the error.
* `body`: The body (JSON, text, or otherwise) to be passed along as an error message.
* Returns: Nothing.

Sets the HTTP headers using the URL contained in `schemaUrls.error`, then handles the error as outlined in the
`gpii.express.handler` docs.

#### `{that}.sendResponse(statusCode, body)`
* `statusCode`: The [HTTP status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) to be sent to the user.
* `body`: The body (JSON, text, or otherwise) to be sent via `that.response.send`.
* Returns: Nothing.

Sets the HTTP headers using the URL contained in `schemaUrls.success`, then sends the response as outlined in the
`gpii.express.handler` docs.


# Schema Link Middleware

The schema link middleware provided in this package adds the required HTTP headers to all requests it is allowed to
work with. There are two grades, one for normal (non-error) requests, and one for error requests. To use either of
these, they must be allowed to work with the request before whatever router or middleware sends the final response to
the user. The ordering of middleware components is controlled using
[priorities and namespaces](http://docs.fluidproject.org/infusion/development/Priorities.html).

These grades do not send a response to the user. You are expected to wire a `gpii.express.router` instance into the
middleware chain that will respond to the user. Otherwise, the error will be passed along to the default Express
error handler. Another key limitation of this approach is that the headers are always set for every request. It is
only really appropriate when only a single type of payload will ever be sent, for example:

1. When delivering a static payload such as a JSON document saved to a file.
2. When delivering a single JSON error message format as the last "link" in the error-handling middleware chain.

## `gpii.schema.schemaLink.middleware`

The middleware grade for non-error requests, which extends [`gpii.express.middleware.headerSetter`](https://github.com/GPII/gpii-express/blob/master/docs/headerMiddleware.md#gpiiexpressmiddlewareheadersetter).
Adds the two headers outlined above to all "non-error" messages and then allows processing to continue along the chain
of (non-error-handling) middleware.

### Component Options

In addition to the supported by the underlyng `gpii.express.headerSetter` grade, this grade supports the
following unique

| Option | Type | Description |
| -------------------------------- | ---------- | ----------- |
| `schemaBaseUrl` | `{String}` | The base URL, relative to which all schemas can be found. |
| `schemaPaths.success` (required) | `{String}` | The path to the "success" schema, relative to `schemaBaseUrl`. |

You may also choose to manage the schema URL directly and to set separate base URLs for the "error" and "success" schema.
See the documentation below for `gpii.schema.schemaLink.schemaUrlHolder` for details.


## `gpii.schema.schemaLink.middleware.error`

The middleware grade for error requests, which extends [`gpii.express.headerSetter.error`](github.com/GPII/gpii-express/blob/master/docs/headerMiddleware.md).
Adds the two headers outlined above to all "error" messages and then allows processing to continue along the chain of (error-handling) middleware.

### Component Options

In addition to the supported by the underlying `gpii.express.headerSetter.error` grade, this component supports:

| Option | Type | Description |
| ------------------------------ | ---------- | ----------- |
| `schemaBaseUrl` | `{String}` | The base URL, relative to which all schemas can be found. |
| `schemaPaths.error` (required) | `{String}` | The path to the "error" schema, relative to `schemaBaseUrl`. |

You may also choose to manage the schema URL directly and to set separate base URLs for the "error" and "success" schema.
See the documentation below for `gpii.schema.schemaLink.schemaUrlHolder` for details.

# The Schema Link "Holder"

Rather than require implementers to manage individual schema URLs, a convenience grade is provided that will assemble
schema URLs from base URLs and schema paths. These are configured such that most people will only need to set
`schemaBaseUrl` and one or both of `schemaPaths.error` and `schemaPaths.success`.

## `gpii.schema.schemaLink.schemaUrlHolder`

### Component Options

| Option | Type | Description |
| ------------------------ | ---------- | ----------- |
| `schemaBaseUrl` | `{String}` | The base URL, relative to which all schemas can be found. |
| `schemaBaseUrls.error` | `{String}` | The base URL, relative to which the "error" schema can be found. Set to `schemaBaseUrl` by default. |
| `schemaBaseUrls.success` | `{String}` | The base URL, relative to which the "success" schema can be found. Set to `schemaBaseUrl` by default. |
| `schemaPaths.error` | `{String}` | The path to the "error" schema, relative to `schemaBaseUrls.error`. |
| `schemaPaths.success` | `{String}` | The path to the "success" schema, relative to `schemaBaseUrls.error`. |

By default, the final URLs will be constructed from `schemaBaseUrl` and one of the schema paths. If your "error"
and "success" schemas can be found at different hostnames (ports, etc.), you can set `schemaBaseUrls.error` and
`schemaBaseUrls.success` individually.

The "Schema Link Handler" and "Schema Link Middleware" described above both extend this grade, so you can use it as a
convenient target for setting a common base URL, as in the following example:

```javascript
fluid.defaults("my.express.grade", {
gradeNames: ["gpii.express"],
distributeOptions: {
source: "{that}.options.schemaBaseUrl",
target: "{that gpii.schema.schemaLink.schemaUrlHolder}.options.schemaBaseUrl"
}
// Your components and other unique options.
});
```
26 changes: 13 additions & 13 deletions docs/schemaValidationMiddleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ The default options validate the request body, as expected with a `POST` or `PUT
below for examples of how different rules can handle different types of request data.

The transformed request data is validated against the schema. Any validation errors are then transformed using
`options.rules.validationErrorsToResponse` before they are sent to the user. The default format looks roughly like:
`options.rules.validationErrorsToResponse`. The default format looks roughly like:

{
ok: false,
Expand All @@ -73,23 +73,23 @@ The transformed request data is validated against the schema. Any validation err
}
}

The rejection output of this middleware is delivered using a [`schemaHandler`](./handler.md). It should match the JSON
Schema specified in `options.responseSchemaKey` and `options.responseSchemaUrl`.
If there are validation errors, the validation output of this middleware is passed on to the next piece of middleware
in the error-handling chain. If there are no validation errors, the next piece of middleware in non-error-handling
chain is called. In both cases, this middleware does not send any kind of response itself. You are expected to ensure
that middleware further along in the chain sends the response and/or [sets HTTP headers](schemaLinks.md).

### Component Options

The following component configuration options are supported:

| Option | Type | Description |
| ------------------- | -------- | ----------- |
| `handlerGrades` | `Array` | An array of grade names that will be used in constructing our request handler. |
| `method` | `String` | The method(s) the inner router will respond to. These should be lowercase strings corresponding to the methods exposed by Express routers. The default is to use the `POST` method, there are convenience grades for each method. |
| `responseSchemaKey` | `String` | The schema key that [our handler](./handler.md) will use in constructing response headers. |
| `responseSchemaUrl` | `String` | The base URL where `responseSchemaKey` can be found. |
| `rules.requestContentToValidate` | `Object` | The [rules to use in transforming](http://docs.fluidproject.org/infusion/development/ModelTransformationAPI.html#fluid-model-transformwithrules-source-rules-options-) the incoming data before validation (see below for more details). |
| `rules.validationErrorsToResponse` | `Object` | The [rules to use in transforming](http://docs.fluidproject.org/infusion/development/ModelTransformationAPI.html#fluid-model-transformwithrules-source-rules-options-) validation errors before they are sent to the user (see above). |
| `schemaKey` | `String` | The key (also the filename) of the schema to be used for validation. |
| `schemaDirs` | `String` | The path to the schema directories that contain a file matching `options.schemaKey`. This is expected to be an array of package-relative paths such as `%gpii-handlebars/tests/schemas`. |
| Option | Type | Description |
| ---------------------------------- | --------- | ----------- |
| `handlerGrades` | `Array` | An array of grade names that will be used in constructing our request handler. |
| `method` | `String` | The method(s) the inner router will respond to. These should be lowercase strings corresponding to the methods exposed by Express routers. The default is to use the `POST` method, there are convenience grades for each method. |
| `rules.requestContentToValidate` | `Object` | The [rules to use in transforming](http://docs.fluidproject.org/infusion/development/ModelTransformationAPI.html#fluid-model-transformwithrules-source-rules-options-) the incoming data before validation (see below for more details). |
| `rules.validationErrorsToResponse` | `Object` | The [rules to use in transforming](http://docs.fluidproject.org/infusion/development/ModelTransformationAPI.html#fluid-model-transformwithrules-source-rules-options-) validation errors before they are sent to the user (see above). |
| `schemaKey` | `String` | The key (also the filename) of the schema to be used for validation. |
| `schemaDirs` | `String` | The path to the schema directories that contain a file matching `options.schemaKey`. This is expected to be an array of package-relative paths such as `%gpii-handlebars/tests/schemas`. |

The default `rules.requestContentToValidate` in this grade are intended for use with `PUT` or `POST` body data. This
can be represented as follows:
Expand Down
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require("./src/js/common/validator");
require("./src/js/server/validator");
require("./src/js/server/parser");
require("./src/js/server/schemaInlineMiddleware");
require("./src/js/server/schemaLinkHandler");
require("./src/js/server/schemaLinkMiddleware");
require("./src/js/server/schemaValidationMiddleware");

Loading

0 comments on commit bb23e09

Please sign in to comment.