UNPKG

7.75 kBMarkdownView Raw
1# Hypermedia Pipeline
2
3This project provides helper functions and default implementations for creating Hypermedia Processing Pipelines.
4
5It uses reducers and continuations to create a simple processing pipeline that can pre-and post-process HTML, JSON, and other hypermedia.
6
7# Status
8
9[![codecov](https://img.shields.io/codecov/c/github/adobe/hypermedia-pipeline.svg)](https://codecov.io/gh/adobe/hypermedia-pipeline)
10[![CircleCI](https://img.shields.io/circleci/project/github/adobe/hypermedia-pipeline.svg)](https://circleci.com/gh/adobe/parcel-plugin-htl)
11[![GitHub license](https://img.shields.io/github/license/adobe/hypermedia-pipeline.svg)](https://github.com/adobe/hypermedia-pipeline/blob/master/LICENSE.txt)
12[![GitHub issues](https://img.shields.io/github/issues/adobe/hypermedia-pipeline.svg)](https://github.com/adobe/hypermedia-pipeline/issues)
13[![npm](https://img.shields.io/npm/dw/@adobe/hypermedia-pipeline.svg)](https://www.npmjs.com/package/@adobe/hypermedia-pipeline) [![Greenkeeper badge](https://badges.greenkeeper.io/adobe/hypermedia-pipeline.svg)](https://greenkeeper.io/)
14
15## Anatomy of a Pipeline
16
17A pipeline consists of following main parts:
18
19- pre-processing functions
20- the main response generating function
21- an optional wrapper function
22- post-processing functions
23
24Each step of the pipeline is processing a single payload object, that will slowly accumulate the `return` values of the functions above through `Object.assign`.
25
26See below for the anatomy of a payload.
27
28Typically, there is one pipeline for each content type supported and pipeline are identified by file name, e.g.
29
30- `html.pipe.js` – creates HTML documents with the `text/html` content-type
31- `json.pipe.js` – creates JSON documents with the `application/json` content-type
32
33### Building a Pipeline
34
35A pipeline builder can be created by creating a CommonJS module that exports a function `pipe` which accepts following arguments and returns a Pipeline function.
36
37- `cont`: the main function that will be executed as a continuation of the pipeline
38- `params`: a map of parameters that are interpreted at runtime
39- `secrets`: a map of protected configuration parameters like API keys that should be handled with care. By convention, all keys in `secret` are in ALL_CAPS_SNAKE_CASE.
40- `logger`: a [Winston](https://www.github.com/winstonjs/winston) logger
41
42This project's main entry provides a helper function for pipeline construction and a few helper functions, so that a basic pipeline can be constructed like this:
43
44```javascript
45// the pipeline itself
46const pipeline = require("@adobe/hypermedia-pipeline");
47// helper functions and log
48const { adaptOWRequest, adaptOWResponse, log } = require('@adobe/hypermedia-pipeline/src/defaults/default.js');
49
50module.exports.pipe = function(cont, params, secrets, logger = log) {
51 logger.log("debug", "Constructing Custom Pipeline");
52
53 return pipeline()
54 .pre(adaptOWRequest) // optional: turns OpenWhisk-style arguments into a proper payload
55 .once(cont) // required: execute the continuation function
56 .post(adaptOWResponse) // optional: turns the Payload into an OpenWhisk-style response
57}
58```
59
60In a typical pipeline, you will add additional processing steps as `.pre(require('some-module'))` or as `.post(require('some-module'))`.
61
62### The Main Function
63
64The main function is typically a pure function that converts the `request`, `context`, and `content` properties of the payload into a `response` object.
65
66In most scenarios, the main function is compiled from a template in a templating language like HTL, JST, or JSX.
67
68Typically, there is one template (and thus one main function) for each content variation of the file type. Content variations are identified by a selector (the piece of the file name before the file extension, e.g. in `example.navigation.html` the selector would be `navigation`). If no selector is provided, the template is the default template for the pipeline.
69
70Examples of possible template names include:
71
72- `html.jsx` (compiled to `html.js`) – default for the HTML pipeline
73- `html.navigation.jst` (compiled to `html.navigation.js`) – renders the navigation
74- `dropdown.json.js` (not compiled) – creates pure JSON output
75- `dropdown.html.htl` (compiled to `dropdown.html.js`) – renders the dropdown component
76
77
78### (Optional) The Wrapper Function
79
80Sometimes it is neccessary to pre-process the payload in a template-specific fashion. This wrapper function (often called "Pre-JS" for brevity sake) allows the full transformation of the pipeline's payload.
81
82Compared to the pipeline-specific pre-processing functions which handle the request, content, and response, the focus of the wrapper function is implementing business logic needed for the main template function. This allows for a clean separation between:
83
841. presentation (in the main function, often expressed in declarative templates)
852. business logic (in the wrapper function, often expressed in imperative code)
863. content-type specific implementation (in the pipeline, expressed in functional code)
87
88A simple implementation of a wrapper function would look like this:
89
90```javascript
91// All wrapper functions must export `pre`
92// The functions takes following arguments:
93// - `cont` (the continuation function, i.e. the main template function)
94// - `payload` (the payload of the pipeline)
95module.exports.pre = (cont, payload) => {
96 const {request, content, context, response} = payload;
97
98 // modifying the payload content before invoking the main function
99 content.hello = 'World';
100 const modifiedpayload = {request, content, context, response};
101
102 // invoking the main function with the new payload. Capturing the response
103 // payload for further modification
104
105 const responsepayload = cont(modifiedpayload);
106
107 // Adding a value to the payload response
108 const modifiedresponse = modifiedpayload.response;
109 modifiedresponse.hello = 'World';
110
111 return Object.assign(modifiedpayload, modifiedresponse);
112}
113```
114
115### Pre-Processing Functions
116
117Pre-Processing functions are meant to:
118
119- parse and process request parameters
120- fetch and parse the requested content
121- transform the requested content
122
123### Post-Processing Functions
124
125Post-Processing functions are meant to:
126
127- process and transform the response
128
129## Anatomy of the Payload
130
131Following main properties exist:
132
133- `request`
134- `content`
135- `response`
136- `context`
137- `error`
138
139### The `request` object
140
141- `params`: a map of request parameters
142- `headers`: a map of HTTP headers
143
144### The `content` object
145
146- `body`: the unparsed content body as a `string`
147- `mdast`: the parsed [Markdown AST](https://github.com/syntax-tree/mdast)
148- `meta`: a map metadata properties, including
149 - `title`: title of the document
150 - `intro`: a plain-text introduction or description
151 - `type`: the content type of the document
152- `htast`: the HTML AST
153- `html`: a string of the content rendered as HTML
154- `children`: an array of top-level elements of the HTML-rendered content
155
156### The `response` object
157
158- `body`: the unparsed response body as a `string`
159- `headers`: a map of HTTP response headers
160- `status`: the HTTP status code
161
162### The `context` object
163
164TBD: used for stuff that is neither content, request, or response
165
166### The `error` object
167
168This object is only set when there has been an error during pipeline processing. Any step in the pipeline may set the `error` object. Subsequent steps should simply skip any processing if they encounter an `error` object.
169
170Alternatively, steps can attempt to handle the `error` object, for instance by generating a formatted error message and leaving it in `response.body`.
171
172The only known property in `error` is
173
174- `message`: the error message