ee-templates
Advanced tools
Comparing version 0.1.0 to 0.2.0
@@ -6,6 +6,17 @@ "use strict"; | ||
var DefaultRenderer = { | ||
render: function initialize(data, callback){ | ||
/** | ||
* todo this will be used in future to determine which renderer to use | ||
*/ | ||
contentTypes: ['application/json'] | ||
, type: null | ||
, init: function(type){ | ||
this.type = type; | ||
} | ||
, render: function initialize(data, callback){ | ||
try { | ||
var rendered = JSON.stringify(data.content); | ||
callback(null, rendered); | ||
callback(null, rendered, this.type); | ||
} catch(e) { | ||
@@ -12,0 +23,0 @@ callback(e, null); |
@@ -63,3 +63,3 @@ "use strict"; | ||
case 'application/json': | ||
return new DefaultRenderer(); | ||
return new DefaultRenderer(current); | ||
case 'text/html': | ||
@@ -69,3 +69,3 @@ return this._createHTMLRenderer(request); | ||
} | ||
return new DefaultRenderer(); | ||
return new DefaultRenderer('application/json'); | ||
} | ||
@@ -72,0 +72,0 @@ |
@@ -17,3 +17,5 @@ "use strict"; | ||
try { | ||
this.env.render(data.template, data.content, callback); | ||
this.env.render(data.template, data.content, function(err, content){ | ||
return callback(err, content, 'text/html'); | ||
}); | ||
} catch(error){ | ||
@@ -20,0 +22,0 @@ callback(error, null); |
@@ -21,14 +21,29 @@ var log = require('ee-log'), | ||
, request: function (request, response, next) { | ||
/** | ||
* todo: ensure that the template is set and create an error response if not! | ||
*/ | ||
var template = request.template; | ||
var renderer = this.createRenderer(request); | ||
// to set the template to and empty string will trigger a rendering error for text/html, which is fine | ||
var template = request.template || '', | ||
renderer = this.createRenderer(request); | ||
response.render = function (data, callback) { | ||
response.render = function (status, headers, data, callback) { | ||
// create a context which should be sufficient for all renderers | ||
var context = {content: data, template: template}; | ||
renderer.render(context, callback); | ||
}; | ||
// apply the rendering | ||
renderer.render(context, function(err, content, type){ | ||
// if the renderer created an error send it back to the client | ||
if(err){ | ||
this.send(500, err.message); | ||
return callback(err); | ||
} | ||
// otherwise set the passed headers and content type | ||
this.setContentType(type+'; charset=utf8'); | ||
this.setHeaders(headers || {}); | ||
// and send it back to the client | ||
this.send(status, content); | ||
callback(); | ||
}.bind(this)); | ||
}.bind(response); | ||
next(); | ||
@@ -35,0 +50,0 @@ } |
{ | ||
"name" : "ee-templates" | ||
, "description" : "Templating integration for the ee-soa-transport-rest based on Nunjucks" | ||
, "version" : "0.1.0" | ||
, "version" : "0.2.0" | ||
, "license" : "MIT" | ||
@@ -6,0 +6,0 @@ , "author" : "Michael Rüfenacht <ruefe@rcky.ch> (http://www.rcky.ch)" |
@@ -5,11 +5,14 @@ #EE-Templates | ||
##Middleware | ||
The middleware can be hooked into the application stack and will append a `render(data, callback)` method to the response | ||
which contains a renderer based on the request's accept content type. | ||
The middleware can be hooked into the application stack and will append a `render(status, headers, data, callback)` method | ||
to the original http response (or any kind of response which adheres to the interface defined for response in `ee-webserver`). | ||
The renderer method contains a renderer resolved based on the accept headers, which renders the passed content into an | ||
appropriate representation for the `http` protocol (properly supperted at the moment: `text/html` or `application/json`). | ||
##Renderers | ||
Currently there are only two supported renderers: HTML and JSON. Both are resolved, set up and cached by a factory. | ||
Currently there are only two supported renderers: HTML and JSON. The environments (`nunjucks`) are application specific | ||
and need to be passed to the middleware. | ||
###HTMLRenderer | ||
The `HTMLRenderer` is a wrapper for nunjucks. It creates a new environment based on the domain of the request and loads | ||
the template which has to be set on the request (in our case resolved by the `rewriting` middleware. | ||
the template which has to be set on the request (in our case resolved by the `rewriting` middleware). | ||
@@ -19,72 +22,19 @@ ###DefaultRenderer | ||
##Extensions | ||
The templating provides the following (asynchronous extensions to nunjucks). | ||
##Templating Extensions | ||
The templating extensions originally provided by this package were moved to their own packages `ee-soa-extension-api` and | ||
`ee-soa-extension-locale`. Since environments now are passed into the middleware, the dependency is removed and extensions | ||
are directly attached by the running application. | ||
###LocaleExtension | ||
The locale extensions allows the integration of a translator service. Use it in your template as follows: | ||
##Todo | ||
{% locale "key", name=value, .. namen=valuen %} | ||
- Add a better loader which allows loading the templates asynchronously | ||
- Improve handling of the mapping between the accept header and the renderer. | ||
The parameters result in a dictionary of key value pairs (see signature parsing of Nunjucks). The extension takes a | ||
locales object, a default language ('en') and a languageKey ('language') on initialization. | ||
##Changelog | ||
Locales is an object which is able to load a resource by `key` and `language` and interpolates the given dictionary | ||
into the resulting string and must implement a `get(key, language, parameters)` method. | ||
### v0.2.0 | ||
var locales = { | ||
get: function(key, language, parameters){ | ||
// load resource which belongs to key in the specified language | ||
// inject the parameters | ||
// return the localized string | ||
} | ||
} | ||
var ext = new LocaleExtension(locales, 'de'); | ||
environment.addExtension('Locale', ext); | ||
In your template: | ||
{% locale "say.hello.to", username=user.name %} | ||
The language to be used is determined by a lookup to the rendering context (accessing the `languageKey`) with a fallback | ||
to the default language. To change the language used by the extension you could. | ||
- set it explicitly in your template `{% set language="en" %}` | ||
- pass it to your rendering context `env.render("template.html", { language: 'en' }` | ||
If the language property is already in use, you can change the lookup by passing another key to the extension on initialization. | ||
var ext = new LocaleExtension(locales, 'de', 'lang'); | ||
###API | ||
The api extension provides a wrapping mechanism for an asynchronous get and set in your templates. | ||
{% api user = getUser() %} | ||
<!-- from now on the user is available /--> | ||
Hello {{ user.username }} | ||
The extension takes an api object which needs to be able to dispatch the invocation, based on the method name and a parameters array. | ||
var api = { | ||
invoke: function(methodName, parameters){ | ||
this[methodName].apply(parameters); | ||
} | ||
getUser: function(args... , callback){ | ||
// do something asynchronous | ||
callback(err, user); | ||
} | ||
} | ||
var apiExt = new ApiExtension(api); | ||
The dispatching is necessary to keep the logic which binds the result to the rendering context away from the API. It also | ||
allows the API to react in generic ways. | ||
#Todo | ||
- Implement the api | ||
- Append the locale service | ||
- Add a better mechanism to resolve paths | ||
- Add a better loader which allows loading the templates asynchronously | ||
- The api needs to be loaded on a per domain base | ||
- the `render` method of the response now directly writes the data back to the original response | ||
- the renderers now directly write their assigned content type to the response | ||
- the renderers directly create server errors if the rendering created an error | ||
- therefore the API has slightly changed from `render(data, callback)` to `render(status, headers, data, callback)` |
@@ -6,3 +6,4 @@ var assert = require('assert'), | ||
var MockRequest = require('./utils/MockRequest'); | ||
var MockRequest = require('./utils/MockRequest'), | ||
MockResponse = require('./utils/MockResponse'); | ||
@@ -30,3 +31,4 @@ var loader = new nunjucks.FileSystemLoader('./test/contents/test.ch/templates'), | ||
var response = {}; | ||
var response = new MockResponse(); | ||
middleware.request(request, response, function(){ | ||
@@ -37,7 +39,12 @@ it('should append a rendering method to the response', function(){ | ||
response.render({ciao: 'Hallo'}, function(err, result){ | ||
response.render(200, {}, {ciao: 'Hallo'}, function(err){ | ||
it('which resolves the template and renders it', function(){ | ||
assert(err==null); | ||
assert.equal('Hallo: Test succeeded.', result); | ||
assert.equal(err, null); | ||
assert.equal('Hallo: Test succeeded.', response.data); | ||
}); | ||
it('should set the content type and the status correctly', function(){ | ||
assert.equal('text/html; charset=utf8', response.contentType); | ||
assert.equal(200, response.status); | ||
}); | ||
}); | ||
@@ -55,10 +62,14 @@ }); | ||
var response1 = {}; | ||
var response1 = new MockResponse(); | ||
middleware.request(request1, response1, function(){ | ||
response1.render({test: 'succeeded'}, function(err, result){ | ||
response1.render(200, {}, {test: 'succeeded'}, function(err){ | ||
it('if the request has an accept value of application/json it should render it as json, and ignore the template', function(){ | ||
assert(err==null); | ||
assert.equal('{"test":"succeeded"}', result); | ||
assert.equal(err, null); | ||
assert.equal('{"test":"succeeded"}', response1.data); | ||
}); | ||
it('should set the content type and the status correctly', function(){ | ||
assert.equal('application/json; charset=utf8', response1.contentType); | ||
assert.equal(200, response1.status); | ||
}); | ||
}); | ||
@@ -75,14 +86,40 @@ }); | ||
var response1 = {}; | ||
var response1 = new MockResponse(); | ||
middleware.request(request1, response1, function(){ | ||
response1.render({test: 'succeeded'}, function(err, result){ | ||
response1.render(200, {}, {test: 'succeeded'}, function(err){ | ||
it('if the request has another accept type it should fallback to json', function(){ | ||
assert(err==null); | ||
assert.equal('{"test":"succeeded"}', result); | ||
assert.equal('{"test":"succeeded"}', response1.data); | ||
}); | ||
it('should set the content type and the status correctly', function(){ | ||
assert.equal('application/json; charset=utf8', response1.contentType); | ||
assert.equal(200, response1.status); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('on errors', function(){ | ||
var request1 = new MockRequest('test.ch', 'test.nunjuck.inexistent.html', | ||
{'accept': [ | ||
{key:'text', value: 'html'} | ||
]} | ||
); | ||
var response1 = new MockResponse(); | ||
middleware.request(request1, response1, function(){ | ||
response1.render(200, {}, {test: 'succeeded'}, function(err){ | ||
it('if there happens an error during the rendering it is passed to the callback', function(){ | ||
assert(!!err); | ||
}); | ||
it('on error the response is equivalent to a server error', function(){ | ||
assert.equal(response1.status, 500); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
module.exports = function MockRequest(host, template, headers) { | ||
this.hostname = host; | ||
@@ -3,0 +4,0 @@ this.template = template; |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
25553
23
566
38
1